FEAT: Use a separate union MaybeUninitCopy for ArrayString

This is the "real" union solution, and ArrayString can use it since its
backing array is Copy. Unfortunately, we'll have to use the Copy bound
on the type, making it "viral" and visible in the user API.
This commit is contained in:
bluss
2018-11-25 12:18:59 +01:00
parent 784ccc97ca
commit c4cd63209f
3 changed files with 128 additions and 39 deletions
+83 -39
View File
@@ -2,7 +2,6 @@ use std::borrow::Borrow;
use std::cmp; use std::cmp;
use std::fmt; use std::fmt;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::mem;
use std::ptr; use std::ptr;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::str; use std::str;
@@ -17,6 +16,8 @@ use char::encode_utf8;
#[cfg(feature="serde-1")] #[cfg(feature="serde-1")]
use serde::{Serialize, Deserialize, Serializer, Deserializer}; use serde::{Serialize, Deserialize, Serializer, Deserializer};
use super::MaybeUninitCopy;
/// A string with a fixed capacity. /// A string with a fixed capacity.
/// ///
/// The `ArrayString` is a string backed by a fixed size array. It keeps track /// The `ArrayString` is a string backed by a fixed size array. It keeps track
@@ -25,20 +26,25 @@ use serde::{Serialize, Deserialize, Serializer, Deserializer};
/// The string is a contiguous value that you can store directly on the stack /// The string is a contiguous value that you can store directly on the stack
/// if needed. /// if needed.
#[derive(Copy)] #[derive(Copy)]
pub struct ArrayString<A: Array<Item=u8>> { pub struct ArrayString<A>
// FIXME: Use Copyable union for xs when we can where A: Array<Item=u8> + Copy
xs: A, {
xs: MaybeUninitCopy<A>,
len: A::Index, len: A::Index,
} }
impl<A: Array<Item=u8>> Default for ArrayString<A> { impl<A> Default for ArrayString<A>
where A: Array<Item=u8> + Copy
{
/// Return an empty `ArrayString` /// Return an empty `ArrayString`
fn default() -> ArrayString<A> { fn default() -> ArrayString<A> {
ArrayString::new() ArrayString::new()
} }
} }
impl<A: Array<Item=u8>> ArrayString<A> { impl<A> ArrayString<A>
where A: Array<Item=u8> + Copy
{
/// Create a new empty `ArrayString`. /// Create a new empty `ArrayString`.
/// ///
/// Capacity is inferred from the type parameter. /// Capacity is inferred from the type parameter.
@@ -54,8 +60,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
pub fn new() -> ArrayString<A> { pub fn new() -> ArrayString<A> {
unsafe { unsafe {
ArrayString { ArrayString {
// FIXME: Use Copyable union for xs when we can xs: MaybeUninitCopy::uninitialized(),
xs: mem::zeroed(),
len: Index::from(0), len: Index::from(0),
} }
} }
@@ -91,11 +96,12 @@ impl<A: Array<Item=u8>> ArrayString<A> {
/// let string = ArrayString::from_byte_string(b"hello world").unwrap(); /// let string = ArrayString::from_byte_string(b"hello world").unwrap();
/// ``` /// ```
pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> { pub fn from_byte_string(b: &A) -> Result<Self, Utf8Error> {
let mut arraystr = Self::new(); let len = str::from_utf8(b.as_slice())?.len();
let s = try!(str::from_utf8(b.as_slice())); debug_assert_eq!(len, A::capacity());
let _result = arraystr.try_push_str(s); Ok(ArrayString {
debug_assert!(_result.is_ok()); xs: MaybeUninitCopy::from(*b),
Ok(arraystr) len: Index::from(A::capacity()),
})
} }
/// Return the capacity of the `ArrayString`. /// Return the capacity of the `ArrayString`.
@@ -213,7 +219,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
return Err(CapacityError::new(s)); return Err(CapacityError::new(s));
} }
unsafe { unsafe {
let dst = self.xs.as_mut_ptr().offset(self.len() as isize); let dst = self.xs.ptr_mut().offset(self.len() as isize);
let src = s.as_ptr(); let src = s.as_ptr();
ptr::copy_nonoverlapping(src, dst, s.len()); ptr::copy_nonoverlapping(src, dst, s.len());
let newl = self.len() + s.len(); let newl = self.len() + s.len();
@@ -307,8 +313,8 @@ impl<A: Array<Item=u8>> ArrayString<A> {
let next = idx + ch.len_utf8(); let next = idx + ch.len_utf8();
let len = self.len(); let len = self.len();
unsafe { unsafe {
ptr::copy(self.xs.as_ptr().offset(next as isize), ptr::copy(self.xs.ptr().offset(next as isize),
self.xs.as_mut_ptr().offset(idx as isize), self.xs.ptr_mut().offset(idx as isize),
len - next); len - next);
self.set_len(len - (next - idx)); self.set_len(len - (next - idx));
} }
@@ -342,75 +348,99 @@ impl<A: Array<Item=u8>> ArrayString<A> {
/// Return a mutable slice of the whole strings buffer /// Return a mutable slice of the whole strings buffer
unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] { unsafe fn raw_mut_bytes(&mut self) -> &mut [u8] {
slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.capacity()) slice::from_raw_parts_mut(self.xs.ptr_mut(), self.capacity())
} }
} }
impl<A: Array<Item=u8>> Deref for ArrayString<A> { impl<A> Deref for ArrayString<A>
where A: Array<Item=u8> + Copy
{
type Target = str; type Target = str;
#[inline] #[inline]
fn deref(&self) -> &str { fn deref(&self) -> &str {
unsafe { unsafe {
let sl = slice::from_raw_parts(self.xs.as_ptr(), self.len.to_usize()); let sl = slice::from_raw_parts(self.xs.ptr(), self.len.to_usize());
str::from_utf8_unchecked(sl) str::from_utf8_unchecked(sl)
} }
} }
} }
impl<A: Array<Item=u8>> DerefMut for ArrayString<A> { impl<A> DerefMut for ArrayString<A>
where A: Array<Item=u8> + Copy
{
#[inline] #[inline]
fn deref_mut(&mut self) -> &mut str { fn deref_mut(&mut self) -> &mut str {
unsafe { unsafe {
let sl = slice::from_raw_parts_mut(self.xs.as_mut_ptr(), self.len.to_usize()); let sl = slice::from_raw_parts_mut(self.xs.ptr_mut(), self.len.to_usize());
str::from_utf8_unchecked_mut(sl) str::from_utf8_unchecked_mut(sl)
} }
} }
} }
impl<A: Array<Item=u8>> PartialEq for ArrayString<A> { impl<A> PartialEq for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn eq(&self, rhs: &Self) -> bool { fn eq(&self, rhs: &Self) -> bool {
**self == **rhs **self == **rhs
} }
} }
impl<A: Array<Item=u8>> PartialEq<str> for ArrayString<A> { impl<A> PartialEq<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn eq(&self, rhs: &str) -> bool { fn eq(&self, rhs: &str) -> bool {
&**self == rhs &**self == rhs
} }
} }
impl<A: Array<Item=u8>> PartialEq<ArrayString<A>> for str { impl<A> PartialEq<ArrayString<A>> for str
where A: Array<Item=u8> + Copy
{
fn eq(&self, rhs: &ArrayString<A>) -> bool { fn eq(&self, rhs: &ArrayString<A>) -> bool {
self == &**rhs self == &**rhs
} }
} }
impl<A: Array<Item=u8>> Eq for ArrayString<A> { } impl<A> Eq for ArrayString<A>
where A: Array<Item=u8> + Copy
{ }
impl<A: Array<Item=u8>> Hash for ArrayString<A> { impl<A> Hash for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn hash<H: Hasher>(&self, h: &mut H) { fn hash<H: Hasher>(&self, h: &mut H) {
(**self).hash(h) (**self).hash(h)
} }
} }
impl<A: Array<Item=u8>> Borrow<str> for ArrayString<A> { impl<A> Borrow<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn borrow(&self) -> &str { self } fn borrow(&self) -> &str { self }
} }
impl<A: Array<Item=u8>> AsRef<str> for ArrayString<A> { impl<A> AsRef<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn as_ref(&self) -> &str { self } fn as_ref(&self) -> &str { self }
} }
impl<A: Array<Item=u8>> fmt::Debug for ArrayString<A> { impl<A> fmt::Debug for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
} }
impl<A: Array<Item=u8>> fmt::Display for ArrayString<A> { impl<A> fmt::Display for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) }
} }
/// `Write` appends written data to the end of the string. /// `Write` appends written data to the end of the string.
impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> { impl<A> fmt::Write for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn write_char(&mut self, c: char) -> fmt::Result { fn write_char(&mut self, c: char) -> fmt::Result {
self.try_push(c).map_err(|_| fmt::Error) self.try_push(c).map_err(|_| fmt::Error)
} }
@@ -420,7 +450,9 @@ impl<A: Array<Item=u8>> fmt::Write for ArrayString<A> {
} }
} }
impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> { impl<A> Clone for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn clone(&self) -> ArrayString<A> { fn clone(&self) -> ArrayString<A> {
*self *self
} }
@@ -431,7 +463,9 @@ impl<A: Array<Item=u8> + Copy> Clone for ArrayString<A> {
} }
} }
impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> { impl<A> PartialOrd for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> { fn partial_cmp(&self, rhs: &Self) -> Option<cmp::Ordering> {
(**self).partial_cmp(&**rhs) (**self).partial_cmp(&**rhs)
} }
@@ -441,7 +475,9 @@ impl<A: Array<Item=u8>> PartialOrd for ArrayString<A> {
fn ge(&self, rhs: &Self) -> bool { **self >= **rhs } fn ge(&self, rhs: &Self) -> bool { **self >= **rhs }
} }
impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> { impl<A> PartialOrd<str> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> { fn partial_cmp(&self, rhs: &str) -> Option<cmp::Ordering> {
(**self).partial_cmp(rhs) (**self).partial_cmp(rhs)
} }
@@ -451,7 +487,9 @@ impl<A: Array<Item=u8>> PartialOrd<str> for ArrayString<A> {
fn ge(&self, rhs: &str) -> bool { &**self >= rhs } fn ge(&self, rhs: &str) -> bool { &**self >= rhs }
} }
impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str { impl<A> PartialOrd<ArrayString<A>> for str
where A: Array<Item=u8> + Copy
{
fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> { fn partial_cmp(&self, rhs: &ArrayString<A>) -> Option<cmp::Ordering> {
self.partial_cmp(&**rhs) self.partial_cmp(&**rhs)
} }
@@ -461,7 +499,9 @@ impl<A: Array<Item=u8>> PartialOrd<ArrayString<A>> for str {
fn ge(&self, rhs: &ArrayString<A>) -> bool { self >= &**rhs } fn ge(&self, rhs: &ArrayString<A>) -> bool { self >= &**rhs }
} }
impl<A: Array<Item=u8>> Ord for ArrayString<A> { impl<A> Ord for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn cmp(&self, rhs: &Self) -> cmp::Ordering { fn cmp(&self, rhs: &Self) -> cmp::Ordering {
(**self).cmp(&**rhs) (**self).cmp(&**rhs)
} }
@@ -469,7 +509,9 @@ impl<A: Array<Item=u8>> Ord for ArrayString<A> {
#[cfg(feature="serde-1")] #[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"` /// Requires crate feature `"serde-1"`
impl<A: Array<Item=u8>> Serialize for ArrayString<A> { impl<A> Serialize for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer where S: Serializer
{ {
@@ -479,7 +521,9 @@ impl<A: Array<Item=u8>> Serialize for ArrayString<A> {
#[cfg(feature="serde-1")] #[cfg(feature="serde-1")]
/// Requires crate feature `"serde-1"` /// Requires crate feature `"serde-1"`
impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> { impl<'de, A> Deserialize<'de> for ArrayString<A>
where A: Array<Item=u8> + Copy
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'de> where D: Deserializer<'de>
{ {
@@ -488,7 +532,7 @@ impl<'de, A: Array<Item=u8>> Deserialize<'de> for ArrayString<A> {
struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>); struct ArrayStringVisitor<A: Array<Item=u8>>(PhantomData<A>);
impl<'de, A: Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> { impl<'de, A: Copy + Array<Item=u8>> Visitor<'de> for ArrayStringVisitor<A> {
type Value = ArrayString<A>; type Value = ArrayString<A>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+3
View File
@@ -56,7 +56,10 @@ mod maybe_uninit;
#[path="maybe_uninit_nodrop.rs"] #[path="maybe_uninit_nodrop.rs"]
mod maybe_uninit; mod maybe_uninit;
mod maybe_uninit_copy;
use maybe_uninit::MaybeUninit; use maybe_uninit::MaybeUninit;
use maybe_uninit_copy::MaybeUninitCopy;
#[cfg(feature="serde-1")] #[cfg(feature="serde-1")]
use serde::{Serialize, Deserialize, Serializer, Deserializer}; use serde::{Serialize, Deserialize, Serializer, Deserializer};
+42
View File
@@ -0,0 +1,42 @@
use array::Array;
#[derive(Copy, Clone)]
pub union MaybeUninitCopy<T>
where T: Copy
{
empty: (),
value: T,
}
impl<T> MaybeUninitCopy<T>
where T: Copy
{
/// Create a new MaybeUninit with uninitialized interior
pub unsafe fn uninitialized() -> Self {
Self { empty: () }
}
/// Create a new MaybeUninit from the value `v`.
pub fn from(value: T) -> Self {
Self { value }
}
// Raw pointer casts written so that we don't reference or access the
// uninitialized interior value
/// Return a raw pointer to the start of the interior array
pub fn ptr(&self) -> *const T::Item
where T: Array
{
self as *const _ as *const T::Item
}
/// Return a mut raw pointer to the start of the interior array
pub fn ptr_mut(&mut self) -> *mut T::Item
where T: Array
{
self as *mut _ as *mut T::Item
}
}