From 10aa8245d8ab61444c71fa3d60dd587b6037f259 Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 12 Sep 2015 14:34:11 +0200 Subject: [PATCH] ArrayString: Make Copy, don't use ArrayVec --- src/array_string.rs | 61 ++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/array_string.rs b/src/array_string.rs index 43f3914..c88f072 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -3,10 +3,10 @@ use std::fmt; use std::mem; use std::ops::Deref; use std::str; +use std::slice; -use ArrayVec; use array::Array; - +use array::Index; /// A string with a fixed capacity. /// @@ -18,8 +18,18 @@ use array::Array; /// /// Due to technical restrictions, this struct does not implement `Copy` even /// though it would be safe to do so. +#[derive(Copy)] pub struct ArrayString> { - vec: ArrayVec, + xs: A, + len: A::Index, +} + +unsafe fn new_array>() -> A { + // Note: Returning an uninitialized value here only works + // if we can be sure the data is never used. The nullable pointer + // inside enum optimization conflicts with this this for example, + // so we need to be extra careful. See `NoDrop` enum. + mem::uninitialized() } impl> ArrayString { @@ -36,8 +46,11 @@ impl> ArrayString { /// assert_eq!(string.capacity(), 16); /// ``` pub fn new() -> ArrayString { - ArrayString { - vec: ArrayVec::new() + unsafe { + ArrayString { + xs: new_array(), + len: Index::from(0), + } } } @@ -50,12 +63,12 @@ impl> ArrayString { /// assert_eq!(string.capacity(), 3); /// ``` #[inline] - pub fn capacity(&self) -> usize { self.vec.capacity() } + pub fn capacity(&self) -> usize { A::capacity() } - /// Adds the given character to the end of the string. + /// Adds the given char to the end of the string. /// /// Returns `None` if the push succeeds, or and returns `Some(c)` if the - /// backing array is not large enough to fit the additional character. + /// backing array is not large enough to fit the additional char. /// /// ``` /// use arrayvec::ArrayString; @@ -98,20 +111,25 @@ impl> ArrayString { /// assert_eq!(overflow2, Some("ef")); /// ``` pub fn push_str<'a>(&mut self, s: &'a str) -> Option<&'a str> { + use std::io::Write; + if self.len() + s.len() > self.capacity() { return Some(s); } - let mut bytes = s.bytes(); - self.vec.extend(&mut bytes); - assert!(bytes.next().is_none()); + unsafe { + let sl = slice::from_raw_parts_mut(self.xs.as_mut_ptr(), A::capacity()); + (&mut sl[self.len()..]).write(s.as_bytes()).unwrap(); + let newl = self.len() + s.len(); + self.set_len(newl); + } None } - - /// Make the string empty. pub fn clear(&mut self) { - mem::replace(self, ArrayString::new()); + unsafe { + self.set_len(0); + } } /// Set the strings's length. @@ -119,10 +137,11 @@ impl> ArrayString { /// May panic if `length` is greater than the capacity. /// /// This function is `unsafe` because it changes the notion of the - /// number of “valid” characters in the string. Use with care. + /// number of “valid” bytes in the string. Use with care. #[inline] pub unsafe fn set_len(&mut self, length: usize) { - self.vec.set_len(length) + debug_assert!(length <= self.capacity()); + self.len = Index::from(length); } } @@ -130,7 +149,10 @@ impl> Deref for ArrayString { type Target = str; #[inline] fn deref(&self) -> &str { - unsafe { str::from_utf8_unchecked(&self.vec) } + unsafe { + let sl = slice::from_raw_parts(self.xs.as_ptr(), self.len.to_usize()); + str::from_utf8_unchecked(sl) + } } } @@ -156,10 +178,9 @@ impl> fmt::Write for ArrayString { } } -//#[derive(Clone, /*Copy,*/ Eq, Hash, Ord, PartialEq, PartialOrd)] -impl> Clone for ArrayString { +impl + Copy> Clone for ArrayString { fn clone(&self) -> ArrayString { - ArrayString { vec: self.vec.clone() } + *self } }