diff --git a/Cargo.toml b/Cargo.toml index f6a55b3..6c32e90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,11 +18,10 @@ readme = "README.md" [features] ffi = [] std = ["serde/std"] -union = ["smallvec/union"] [dependencies] serde = { version = "1.0", default-features = false, features = ["alloc"], optional = true } -smallvec = { version = "1.1" } +smallvec = { version = "2.0.0-alpha.1" } [dev-dependencies] bincode = "1.0" diff --git a/src/lib.rs b/src/lib.rs index 3118567..f06faa8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,11 +25,6 @@ //! //! By default, the `serde` dependency is compiled with `no_std`. //! If the `std` feature is enabled, `std` is added as a dependency in `serde`, as well. -//! -//! ## `union` feature -//! -//! This feature will enable the `union` feature in `smallvec`, which reduces the size of -//! a `SmallString` instance. This feature requires a nightly compiler. #![cfg_attr(not(any(feature = "ffi", feature = "std")), no_std)] #![deny(missing_docs)] diff --git a/src/string.rs b/src/string.rs index 3c13c69..a54b9fe 100644 --- a/src/string.rs +++ b/src/string.rs @@ -21,20 +21,20 @@ use serde::{ ser::{Serialize, Serializer}, }; -use smallvec::{Array, SmallVec}; +use smallvec::SmallVec; /// A `String`-like container that can store a small number of bytes inline. /// -/// `SmallString` uses a `SmallVec<[u8; N]>` as its internal storage. +/// `SmallString` uses a `SmallVec` as its internal storage. #[derive(Clone, Default)] -pub struct SmallString> { - data: SmallVec, +pub struct SmallString { + data: SmallVec, } -impl> SmallString { +impl SmallString { /// Construct an empty string. #[inline] - pub fn new() -> SmallString { + pub const fn new() -> SmallString { SmallString { data: SmallVec::new(), } @@ -45,7 +45,7 @@ impl> SmallString { /// /// Will create a heap allocation only if `n` is larger than the inline capacity. #[inline] - pub fn with_capacity(n: usize) -> SmallString { + pub fn with_capacity(n: usize) -> SmallString { SmallString { data: SmallVec::with_capacity(n), } @@ -53,7 +53,7 @@ impl> SmallString { /// Construct a `SmallString` by copying data from a `&str`. #[inline] - pub fn from_str(s: &str) -> SmallString { + pub fn from_str(s: &str) -> SmallString { SmallString { data: SmallVec::from_slice(s.as_bytes()), } @@ -61,7 +61,7 @@ impl> SmallString { /// Construct a `SmallString` by using an existing allocation. #[inline] - pub fn from_string(s: String) -> SmallString { + pub fn from_string(s: String) -> SmallString { SmallString { data: SmallVec::from_vec(s.into_bytes()), } @@ -71,7 +71,7 @@ impl> SmallString { /// /// If the provided byte array is not valid UTF-8, an error is returned. #[inline] - pub fn from_buf(buf: A) -> Result, FromUtf8Error> { + pub fn from_buf(buf: [u8; N]) -> Result, FromUtf8Error> { let data = SmallVec::from_buf(buf); match str::from_utf8(&data) { @@ -94,7 +94,7 @@ impl> SmallString { /// memory unsafety issues, as the Rust standard library functions assume /// that `&str`s are valid UTF-8. #[inline] - pub unsafe fn from_buf_unchecked(buf: A) -> SmallString { + pub const unsafe fn from_buf_unchecked(buf: [u8; N]) -> SmallString { SmallString { data: SmallVec::from_buf(buf), } @@ -102,13 +102,13 @@ impl> SmallString { /// The maximum number of bytes this string can hold inline. #[inline] - pub fn inline_size(&self) -> usize { - A::size() + pub const fn inline_size(&self) -> usize { + N } /// Returns the length of this string, in bytes. #[inline] - pub fn len(&self) -> usize { + pub const fn len(&self) -> usize { self.data.len() } @@ -120,13 +120,13 @@ impl> SmallString { /// Returns the number of bytes this string can hold without reallocating. #[inline] - pub fn capacity(&self) -> usize { + pub const fn capacity(&self) -> usize { self.data.capacity() } /// Returns `true` if the data has spilled into a separate heap-allocated buffer. #[inline] - pub fn spilled(&self) -> bool { + pub const fn spilled(&self) -> bool { self.data.spilled() } @@ -153,7 +153,7 @@ impl> SmallString { /// ``` /// use smallstr::SmallString; /// - /// let mut s: SmallString<[u8; 8]> = SmallString::from("foo"); + /// let mut s: SmallString<8> = SmallString::from("foo"); /// /// s.push('x'); /// @@ -174,7 +174,7 @@ impl> SmallString { /// ``` /// use smallstr::SmallString; /// - /// let mut s: SmallString<[u8; 8]> = SmallString::from("foo"); + /// let mut s: SmallString<8> = SmallString::from("foo"); /// /// s.push_str("bar"); /// @@ -345,7 +345,7 @@ impl> SmallString { /// memory unsafety issues, as the Rust standard library functions assume /// that `&str`s are valid UTF-8. #[inline] - pub unsafe fn as_mut_vec(&mut self) -> &mut SmallVec { + pub unsafe fn as_mut_vec(&mut self) -> &mut SmallVec { &mut self.data } @@ -365,13 +365,13 @@ impl> SmallString { self.into_string().into_boxed_str() } - /// Convert the `SmallString` into `A`, if possible. Otherwise, return `Err(self)`. + /// Convert the `SmallString` into `[u8; N]`, if possible. Otherwise, return `Err(self)`. /// /// This method returns `Err(self)` if the `SmallString` is too short - /// (and the `A` contains uninitialized elements) or if the `SmallString` is too long + /// (and the `[u8; N]` contains uninitialized elements) or if the `SmallString` is too long /// (and the elements have been spilled to the heap). #[inline] - pub fn into_inner(self) -> Result { + pub fn into_inner(self) -> Result<[u8; N], Self> { self.data.into_inner().map_err(|data| SmallString { data }) } @@ -386,7 +386,7 @@ impl> SmallString { /// ``` /// use smallstr::SmallString; /// - /// let mut s: SmallString<[u8; 16]> = SmallString::from("f_o_ob_ar"); + /// let mut s: SmallString<16> = SmallString::from("f_o_ob_ar"); /// /// s.retain(|c| c != '_'); /// @@ -394,13 +394,13 @@ impl> SmallString { /// ``` #[inline] pub fn retain bool>(&mut self, mut f: F) { - struct SetLenOnDrop<'a, A: Array> { - s: &'a mut SmallString, + struct SetLenOnDrop<'a, const N: usize> { + s: &'a mut SmallString, idx: usize, del_bytes: usize, } - impl<'a, A: Array> Drop for SetLenOnDrop<'a, A> { + impl<'a, const N: usize> Drop for SetLenOnDrop<'a, N> { fn drop(&mut self) { let new_len = self.idx - self.del_bytes; debug_assert!(new_len <= self.s.len()); @@ -450,7 +450,7 @@ impl> SmallString { } } -impl> ops::Deref for SmallString { +impl ops::Deref for SmallString { type Target = str; #[inline] @@ -460,7 +460,7 @@ impl> ops::Deref for SmallString { } } -impl> ops::DerefMut for SmallString { +impl ops::DerefMut for SmallString { #[inline] fn deref_mut(&mut self) -> &mut str { let bytes: &mut [u8] = &mut self.data; @@ -468,49 +468,49 @@ impl> ops::DerefMut for SmallString { } } -impl> AsRef for SmallString { +impl AsRef for SmallString { #[inline] fn as_ref(&self) -> &str { self } } -impl> AsMut for SmallString { +impl AsMut for SmallString { #[inline] fn as_mut(&mut self) -> &mut str { self } } -impl> Borrow for SmallString { +impl Borrow for SmallString { #[inline] fn borrow(&self) -> &str { self } } -impl> BorrowMut for SmallString { +impl BorrowMut for SmallString { #[inline] fn borrow_mut(&mut self) -> &mut str { self } } -impl> AsRef<[u8]> for SmallString { +impl AsRef<[u8]> for SmallString { #[inline] fn as_ref(&self) -> &[u8] { self.data.as_ref() } } -impl> Borrow<[u8]> for SmallString { +impl Borrow<[u8]> for SmallString { #[inline] fn borrow(&self) -> &[u8] { self.data.borrow() } } -impl> fmt::Write for SmallString { +impl fmt::Write for SmallString { #[inline] fn write_str(&mut self, s: &str) -> fmt::Result { self.push_str(s); @@ -525,14 +525,14 @@ impl> fmt::Write for SmallString { } #[cfg(feature = "serde")] -impl> Serialize for SmallString { +impl Serialize for SmallString { fn serialize(&self, serializer: S) -> Result { serializer.serialize_str(self) } } #[cfg(feature = "serde")] -impl<'de, A: Array> Deserialize<'de> for SmallString { +impl<'de, const N: usize> Deserialize<'de> for SmallString { fn deserialize>(deserializer: D) -> Result { deserializer.deserialize_str(SmallStringVisitor { phantom: PhantomData, @@ -541,13 +541,13 @@ impl<'de, A: Array> Deserialize<'de> for SmallString { } #[cfg(feature = "serde")] -struct SmallStringVisitor { - phantom: PhantomData, +struct SmallStringVisitor { + phantom: PhantomData<[u8; N]>, } #[cfg(feature = "serde")] -impl<'de, A: Array> Visitor<'de> for SmallStringVisitor { - type Value = SmallString; +impl<'de, const N: usize> Visitor<'de> for SmallStringVisitor { + type Value = SmallString; fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("a string") @@ -562,37 +562,37 @@ impl<'de, A: Array> Visitor<'de> for SmallStringVisitor { } } -impl> From for SmallString { +impl From for SmallString { #[inline] - fn from(ch: char) -> SmallString { + fn from(ch: char) -> SmallString { SmallString::from_str(ch.encode_utf8(&mut [0; 4])) } } -impl<'a, A: Array> From<&'a str> for SmallString { +impl<'a, const N: usize> From<&'a str> for SmallString { #[inline] - fn from(s: &str) -> SmallString { + fn from(s: &str) -> SmallString { SmallString::from_str(s) } } -impl> From> for SmallString { +impl From> for SmallString { #[inline] - fn from(s: Box) -> SmallString { + fn from(s: Box) -> SmallString { SmallString::from_string(s.into()) } } -impl> From for SmallString { +impl From for SmallString { #[inline] - fn from(s: String) -> SmallString { + fn from(s: String) -> SmallString { SmallString::from_string(s) } } macro_rules! impl_index_str { ($index_type: ty) => { - impl> ops::Index<$index_type> for SmallString { + impl ops::Index<$index_type> for SmallString { type Output = str; #[inline] @@ -601,7 +601,7 @@ macro_rules! impl_index_str { } } - impl> ops::IndexMut<$index_type> for SmallString { + impl ops::IndexMut<$index_type> for SmallString { #[inline] fn index_mut(&mut self, index: $index_type) -> &mut str { &mut self.as_mut_str()[index] @@ -615,47 +615,47 @@ impl_index_str!(ops::RangeFrom); impl_index_str!(ops::RangeTo); impl_index_str!(ops::RangeFull); -impl> FromIterator for SmallString { - fn from_iter>(iter: I) -> SmallString { +impl FromIterator for SmallString { + fn from_iter>(iter: I) -> SmallString { let mut s = SmallString::new(); s.extend(iter); s } } -impl<'a, A: Array> FromIterator<&'a char> for SmallString { - fn from_iter>(iter: I) -> SmallString { +impl<'a, const N: usize> FromIterator<&'a char> for SmallString { + fn from_iter>(iter: I) -> SmallString { let mut s = SmallString::new(); s.extend(iter.into_iter().cloned()); s } } -impl<'a, A: Array> FromIterator> for SmallString { - fn from_iter>>(iter: I) -> SmallString { +impl<'a, const N: usize> FromIterator> for SmallString { + fn from_iter>>(iter: I) -> SmallString { let mut s = SmallString::new(); s.extend(iter); s } } -impl<'a, A: Array> FromIterator<&'a str> for SmallString { - fn from_iter>(iter: I) -> SmallString { +impl<'a, const N: usize> FromIterator<&'a str> for SmallString { + fn from_iter>(iter: I) -> SmallString { let mut s = SmallString::new(); s.extend(iter); s } } -impl> FromIterator for SmallString { - fn from_iter>(iter: I) -> SmallString { +impl FromIterator for SmallString { + fn from_iter>(iter: I) -> SmallString { let mut s = SmallString::new(); s.extend(iter); s } } -impl> Extend for SmallString { +impl Extend for SmallString { fn extend>(&mut self, iter: I) { let iter = iter.into_iter(); let (lo, _) = iter.size_hint(); @@ -668,13 +668,13 @@ impl> Extend for SmallString { } } -impl<'a, A: Array> Extend<&'a char> for SmallString { +impl<'a, const N: usize> Extend<&'a char> for SmallString { fn extend>(&mut self, iter: I) { self.extend(iter.into_iter().cloned()); } } -impl<'a, A: Array> Extend> for SmallString { +impl<'a, const N: usize> Extend> for SmallString { fn extend>>(&mut self, iter: I) { for s in iter { self.push_str(&s); @@ -682,7 +682,7 @@ impl<'a, A: Array> Extend> for SmallString { } } -impl<'a, A: Array> Extend<&'a str> for SmallString { +impl<'a, const N: usize> Extend<&'a str> for SmallString { fn extend>(&mut self, iter: I) { for s in iter { self.push_str(s); @@ -690,7 +690,7 @@ impl<'a, A: Array> Extend<&'a str> for SmallString { } } -impl> Extend for SmallString { +impl Extend for SmallString { fn extend>(&mut self, iter: I) { for s in iter { self.push_str(&s); @@ -698,14 +698,14 @@ impl> Extend for SmallString { } } -impl> fmt::Debug for SmallString { +impl fmt::Debug for SmallString { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } -impl> fmt::Display for SmallString { +impl fmt::Display for SmallString { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) @@ -714,7 +714,7 @@ impl> fmt::Display for SmallString { macro_rules! eq_str { ( $rhs:ty ) => { - impl<'a, A: Array> PartialEq<$rhs> for SmallString { + impl<'a, const N: usize> PartialEq<$rhs> for SmallString { #[inline] fn eq(&self, rhs: &$rhs) -> bool { &self[..] == &rhs[..] @@ -734,7 +734,7 @@ eq_str!(String); eq_str!(Cow<'a, str>); #[cfg(feature = "ffi")] -impl> PartialEq for SmallString { +impl PartialEq for SmallString { #[inline] fn eq(&self, rhs: &OsStr) -> bool { &self[..] == rhs @@ -747,7 +747,7 @@ impl> PartialEq for SmallString { } #[cfg(feature = "ffi")] -impl<'a, A: Array> PartialEq<&'a OsStr> for SmallString { +impl<'a, const N: usize> PartialEq<&'a OsStr> for SmallString { #[inline] fn eq(&self, rhs: &&OsStr) -> bool { &self[..] == *rhs @@ -760,7 +760,7 @@ impl<'a, A: Array> PartialEq<&'a OsStr> for SmallString { } #[cfg(feature = "ffi")] -impl> PartialEq for SmallString { +impl PartialEq for SmallString { #[inline] fn eq(&self, rhs: &OsString) -> bool { &self[..] == rhs @@ -773,7 +773,7 @@ impl> PartialEq for SmallString { } #[cfg(feature = "ffi")] -impl<'a, A: Array> PartialEq> for SmallString { +impl<'a, const N: usize> PartialEq> for SmallString { #[inline] fn eq(&self, rhs: &Cow) -> bool { self[..] == **rhs @@ -785,39 +785,35 @@ impl<'a, A: Array> PartialEq> for SmallString { } } -impl PartialEq> for SmallString -where - A: Array, - B: Array, -{ +impl PartialEq> for SmallString { #[inline] - fn eq(&self, rhs: &SmallString) -> bool { + fn eq(&self, rhs: &SmallString) -> bool { &self[..] == &rhs[..] } #[inline] - fn ne(&self, rhs: &SmallString) -> bool { + fn ne(&self, rhs: &SmallString) -> bool { &self[..] != &rhs[..] } } -impl> Eq for SmallString {} +impl Eq for SmallString {} -impl> PartialOrd for SmallString { +impl PartialOrd for SmallString { #[inline] - fn partial_cmp(&self, rhs: &SmallString) -> Option { + fn partial_cmp(&self, rhs: &SmallString) -> Option { self[..].partial_cmp(&rhs[..]) } } -impl> Ord for SmallString { +impl Ord for SmallString { #[inline] - fn cmp(&self, rhs: &SmallString) -> Ordering { + fn cmp(&self, rhs: &SmallString) -> Ordering { self[..].cmp(&rhs[..]) } } -impl> Hash for SmallString { +impl Hash for SmallString { #[inline] fn hash(&self, state: &mut H) { self[..].hash(state) @@ -862,22 +858,22 @@ impl<'a> DoubleEndedIterator for Drain<'a> { /// [`from_buf`]: struct.SmallString.html#method.from_buf /// [`SmallString`]: struct.SmallString.html #[derive(Debug)] -pub struct FromUtf8Error> { - buf: A, +pub struct FromUtf8Error { + buf: [u8; N], error: Utf8Error, } -impl> FromUtf8Error { +impl FromUtf8Error { /// Returns the slice of `[u8]` bytes that were attempted to convert to a `SmallString`. #[inline] pub fn as_bytes(&self) -> &[u8] { let ptr = &self.buf as *const _ as *const u8; - unsafe { slice::from_raw_parts(ptr, A::size()) } + unsafe { slice::from_raw_parts(ptr, N) } } /// Returns the byte array that was attempted to convert into a `SmallString`. #[inline] - pub fn into_buf(self) -> A { + pub fn into_buf(self) -> [u8; N] { self.buf } @@ -888,7 +884,7 @@ impl> FromUtf8Error { } } -impl> fmt::Display for FromUtf8Error { +impl fmt::Display for FromUtf8Error { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.error, f) @@ -906,7 +902,7 @@ mod test { #[test] fn test_drain() { - let mut s: SmallString<[u8; 2]> = SmallString::new(); + let mut s: SmallString<2> = SmallString::new(); s.push('a'); assert_eq!(s.drain().collect::(), "a"); @@ -923,7 +919,7 @@ mod test { #[test] fn test_drain_rev() { - let mut s: SmallString<[u8; 2]> = SmallString::new(); + let mut s: SmallString<2> = SmallString::new(); s.push('a'); assert_eq!(s.drain().rev().collect::(), "a"); @@ -940,7 +936,7 @@ mod test { #[test] fn test_eq() { - let s: SmallString<[u8; 4]> = SmallString::from("foo"); + let s: SmallString<4> = SmallString::from("foo"); assert_eq!(s, *"foo"); assert_eq!(s, "foo"); @@ -953,7 +949,7 @@ mod test { fn test_eq_os_str() { use std::ffi::OsStr; - let s: SmallString<[u8; 4]> = SmallString::from("foo"); + let s: SmallString<4> = SmallString::from("foo"); let os_s: &OsStr = "foo".as_ref(); assert_eq!(s, os_s); @@ -964,15 +960,15 @@ mod test { #[test] fn test_from_buf() { - let s: SmallString<[u8; 2]> = SmallString::from_buf([206, 177]).unwrap(); + let s: SmallString<2> = SmallString::from_buf([206, 177]).unwrap(); assert_eq!(s, "α"); - assert!(SmallString::<[u8; 2]>::from_buf([206, 0]).is_err()); + assert!(SmallString::<2>::from_buf([206, 0]).is_err()); } #[test] fn test_insert() { - let mut s: SmallString<[u8; 8]> = SmallString::from("abc"); + let mut s: SmallString<8> = SmallString::from("abc"); s.insert(1, 'x'); assert_eq!(s, "axbc"); @@ -987,32 +983,32 @@ mod test { #[test] #[should_panic] fn test_insert_panic() { - let mut s: SmallString<[u8; 8]> = SmallString::from("αβγ"); + let mut s: SmallString<8> = SmallString::from("αβγ"); s.insert(1, 'x'); } #[test] fn test_into_string() { - let s: SmallString<[u8; 2]> = SmallString::from("foo"); + let s: SmallString<2> = SmallString::from("foo"); assert_eq!(s.into_string(), "foo"); - let s: SmallString<[u8; 8]> = SmallString::from("foo"); + let s: SmallString<8> = SmallString::from("foo"); assert_eq!(s.into_string(), "foo"); } #[test] fn test_to_string() { - let s: SmallString<[u8; 2]> = SmallString::from("foo"); + let s: SmallString<2> = SmallString::from("foo"); assert_eq!(s.to_string(), "foo"); - let s: SmallString<[u8; 8]> = SmallString::from("foo"); + let s: SmallString<8> = SmallString::from("foo"); assert_eq!(s.to_string(), "foo"); } #[test] fn test_pop() { - let mut s: SmallString<[u8; 8]> = SmallString::from("αβγ"); + let mut s: SmallString<8> = SmallString::from("αβγ"); assert_eq!(s.pop(), Some('γ')); assert_eq!(s.pop(), Some('β')); @@ -1022,7 +1018,7 @@ mod test { #[test] fn test_remove() { - let mut s: SmallString<[u8; 8]> = SmallString::from("αβγ"); + let mut s: SmallString<8> = SmallString::from("αβγ"); assert_eq!(s.remove(2), 'β'); assert_eq!(s, "αγ"); @@ -1037,7 +1033,7 @@ mod test { #[test] #[should_panic] fn test_remove_panic_0() { - let mut s: SmallString<[u8; 8]> = SmallString::from("foo"); + let mut s: SmallString<8> = SmallString::from("foo"); // Attempt to remove at the end s.remove(3); @@ -1046,7 +1042,7 @@ mod test { #[test] #[should_panic] fn test_remove_panic_1() { - let mut s: SmallString<[u8; 8]> = SmallString::from("αβγ"); + let mut s: SmallString<8> = SmallString::from("αβγ"); // Attempt to remove mid-character s.remove(1); @@ -1054,7 +1050,7 @@ mod test { #[test] fn test_retain() { - let mut s: SmallString<[u8; 8]> = SmallString::from("α_β_γ"); + let mut s: SmallString<8> = SmallString::from("α_β_γ"); s.retain(|_| true); assert_eq!(s, "α_β_γ"); @@ -1074,7 +1070,7 @@ mod test { #[test] fn test_truncate() { - let mut s: SmallString<[u8; 2]> = SmallString::from("foobar"); + let mut s: SmallString<2> = SmallString::from("foobar"); s.truncate(6); assert_eq!(s, "foobar"); @@ -1086,7 +1082,7 @@ mod test { #[test] #[should_panic] fn test_truncate_panic() { - let mut s: SmallString<[u8; 2]> = SmallString::from("α"); + let mut s: SmallString<2> = SmallString::from("α"); s.truncate(1); } @@ -1095,7 +1091,7 @@ mod test { fn test_write() { use core::fmt::Write; - let mut s: SmallString<[u8; 8]> = SmallString::from("foo"); + let mut s: SmallString<8> = SmallString::from("foo"); write!(s, "bar").unwrap(); @@ -1107,10 +1103,10 @@ mod test { fn test_serde() { use bincode::{deserialize, serialize}; - let mut small_str: SmallString<[u8; 4]> = SmallString::from("foo"); + let mut small_str: SmallString<4> = SmallString::from("foo"); let encoded = serialize(&small_str).unwrap(); - let decoded: SmallString<[u8; 4]> = deserialize(&encoded).unwrap(); + let decoded: SmallString<4> = deserialize(&encoded).unwrap(); assert_eq!(small_str, decoded); @@ -1119,7 +1115,7 @@ mod test { // Check again after spilling. let encoded = serialize(&small_str).unwrap(); - let decoded: SmallString<[u8; 4]> = deserialize(&encoded).unwrap(); + let decoded: SmallString<4> = deserialize(&encoded).unwrap(); assert_eq!(small_str, decoded); }