diff --git a/src/array_string.rs b/src/array_string.rs index 05b3384..a52fb58 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -2,7 +2,6 @@ use std::borrow::Borrow; use std::cmp; use std::fmt; use std::hash::{Hash, Hasher}; -use std::mem; use std::ptr; use std::ops::{Deref, DerefMut}; use std::str; @@ -17,6 +16,8 @@ use char::encode_utf8; #[cfg(feature="serde-1")] use serde::{Serialize, Deserialize, Serializer, Deserializer}; +use super::MaybeUninitCopy; + /// A string with a fixed capacity. /// /// 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 /// if needed. #[derive(Copy)] -pub struct ArrayString> { - // FIXME: Use Copyable union for xs when we can - xs: A, +pub struct ArrayString + where A: Array + Copy +{ + xs: MaybeUninitCopy, len: A::Index, } -impl> Default for ArrayString { +impl Default for ArrayString + where A: Array + Copy +{ /// Return an empty `ArrayString` fn default() -> ArrayString { ArrayString::new() } } -impl> ArrayString { +impl ArrayString + where A: Array + Copy +{ /// Create a new empty `ArrayString`. /// /// Capacity is inferred from the type parameter. @@ -54,8 +60,7 @@ impl> ArrayString { pub fn new() -> ArrayString { unsafe { ArrayString { - // FIXME: Use Copyable union for xs when we can - xs: mem::zeroed(), + xs: MaybeUninitCopy::uninitialized(), len: Index::from(0), } } @@ -91,11 +96,12 @@ impl> ArrayString { /// let string = ArrayString::from_byte_string(b"hello world").unwrap(); /// ``` pub fn from_byte_string(b: &A) -> Result { - let mut arraystr = Self::new(); - let s = try!(str::from_utf8(b.as_slice())); - let _result = arraystr.try_push_str(s); - debug_assert!(_result.is_ok()); - Ok(arraystr) + let len = str::from_utf8(b.as_slice())?.len(); + debug_assert_eq!(len, A::capacity()); + Ok(ArrayString { + xs: MaybeUninitCopy::from(*b), + len: Index::from(A::capacity()), + }) } /// Return the capacity of the `ArrayString`. @@ -213,7 +219,7 @@ impl> ArrayString { return Err(CapacityError::new(s)); } 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(); ptr::copy_nonoverlapping(src, dst, s.len()); let newl = self.len() + s.len(); @@ -307,8 +313,8 @@ impl> ArrayString { let next = idx + ch.len_utf8(); let len = self.len(); unsafe { - ptr::copy(self.xs.as_ptr().offset(next as isize), - self.xs.as_mut_ptr().offset(idx as isize), + ptr::copy(self.xs.ptr().offset(next as isize), + self.xs.ptr_mut().offset(idx as isize), len - next); self.set_len(len - (next - idx)); } @@ -342,75 +348,99 @@ impl> ArrayString { /// Return a mutable slice of the whole string’s buffer 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> Deref for ArrayString { +impl Deref for ArrayString + where A: Array + Copy +{ type Target = str; #[inline] fn deref(&self) -> &str { 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) } } } -impl> DerefMut for ArrayString { +impl DerefMut for ArrayString + where A: Array + Copy +{ #[inline] fn deref_mut(&mut self) -> &mut str { 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) } } } -impl> PartialEq for ArrayString { +impl PartialEq for ArrayString + where A: Array + Copy +{ fn eq(&self, rhs: &Self) -> bool { **self == **rhs } } -impl> PartialEq for ArrayString { +impl PartialEq for ArrayString + where A: Array + Copy +{ fn eq(&self, rhs: &str) -> bool { &**self == rhs } } -impl> PartialEq> for str { +impl PartialEq> for str + where A: Array + Copy +{ fn eq(&self, rhs: &ArrayString) -> bool { self == &**rhs } } -impl> Eq for ArrayString { } +impl Eq for ArrayString + where A: Array + Copy +{ } -impl> Hash for ArrayString { +impl Hash for ArrayString + where A: Array + Copy +{ fn hash(&self, h: &mut H) { (**self).hash(h) } } -impl> Borrow for ArrayString { +impl Borrow for ArrayString + where A: Array + Copy +{ fn borrow(&self) -> &str { self } } -impl> AsRef for ArrayString { +impl AsRef for ArrayString + where A: Array + Copy +{ fn as_ref(&self) -> &str { self } } -impl> fmt::Debug for ArrayString { +impl fmt::Debug for ArrayString + where A: Array + Copy +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } } -impl> fmt::Display for ArrayString { +impl fmt::Display for ArrayString + where A: Array + Copy +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { (**self).fmt(f) } } /// `Write` appends written data to the end of the string. -impl> fmt::Write for ArrayString { +impl fmt::Write for ArrayString + where A: Array + Copy +{ fn write_char(&mut self, c: char) -> fmt::Result { self.try_push(c).map_err(|_| fmt::Error) } @@ -420,7 +450,9 @@ impl> fmt::Write for ArrayString { } } -impl + Copy> Clone for ArrayString { +impl Clone for ArrayString + where A: Array + Copy +{ fn clone(&self) -> ArrayString { *self } @@ -431,7 +463,9 @@ impl + Copy> Clone for ArrayString { } } -impl> PartialOrd for ArrayString { +impl PartialOrd for ArrayString + where A: Array + Copy +{ fn partial_cmp(&self, rhs: &Self) -> Option { (**self).partial_cmp(&**rhs) } @@ -441,7 +475,9 @@ impl> PartialOrd for ArrayString { fn ge(&self, rhs: &Self) -> bool { **self >= **rhs } } -impl> PartialOrd for ArrayString { +impl PartialOrd for ArrayString + where A: Array + Copy +{ fn partial_cmp(&self, rhs: &str) -> Option { (**self).partial_cmp(rhs) } @@ -451,7 +487,9 @@ impl> PartialOrd for ArrayString { fn ge(&self, rhs: &str) -> bool { &**self >= rhs } } -impl> PartialOrd> for str { +impl PartialOrd> for str + where A: Array + Copy +{ fn partial_cmp(&self, rhs: &ArrayString) -> Option { self.partial_cmp(&**rhs) } @@ -461,7 +499,9 @@ impl> PartialOrd> for str { fn ge(&self, rhs: &ArrayString) -> bool { self >= &**rhs } } -impl> Ord for ArrayString { +impl Ord for ArrayString + where A: Array + Copy +{ fn cmp(&self, rhs: &Self) -> cmp::Ordering { (**self).cmp(&**rhs) } @@ -469,7 +509,9 @@ impl> Ord for ArrayString { #[cfg(feature="serde-1")] /// Requires crate feature `"serde-1"` -impl> Serialize for ArrayString { +impl Serialize for ArrayString + where A: Array + Copy +{ fn serialize(&self, serializer: S) -> Result where S: Serializer { @@ -479,7 +521,9 @@ impl> Serialize for ArrayString { #[cfg(feature="serde-1")] /// Requires crate feature `"serde-1"` -impl<'de, A: Array> Deserialize<'de> for ArrayString { +impl<'de, A> Deserialize<'de> for ArrayString + where A: Array + Copy +{ fn deserialize(deserializer: D) -> Result where D: Deserializer<'de> { @@ -488,7 +532,7 @@ impl<'de, A: Array> Deserialize<'de> for ArrayString { struct ArrayStringVisitor>(PhantomData); - impl<'de, A: Array> Visitor<'de> for ArrayStringVisitor { + impl<'de, A: Copy + Array> Visitor<'de> for ArrayStringVisitor { type Value = ArrayString; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/lib.rs b/src/lib.rs index b7ed449..a2a5547 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,10 @@ mod maybe_uninit; #[path="maybe_uninit_nodrop.rs"] mod maybe_uninit; +mod maybe_uninit_copy; + use maybe_uninit::MaybeUninit; +use maybe_uninit_copy::MaybeUninitCopy; #[cfg(feature="serde-1")] use serde::{Serialize, Deserialize, Serializer, Deserializer}; diff --git a/src/maybe_uninit_copy.rs b/src/maybe_uninit_copy.rs new file mode 100644 index 0000000..dd08e57 --- /dev/null +++ b/src/maybe_uninit_copy.rs @@ -0,0 +1,42 @@ + +use array::Array; + +#[derive(Copy, Clone)] +pub union MaybeUninitCopy + where T: Copy +{ + empty: (), + value: T, +} + +impl MaybeUninitCopy + 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 + } +} +