From 1fa5b2ffbc0f1dd3cfc45adff0329e1bdd46c131 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 8 Aug 2018 20:25:35 +0300 Subject: smol strings --- src/smol_str.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/smol_str.rs (limited to 'src/smol_str.rs') diff --git a/src/smol_str.rs b/src/smol_str.rs new file mode 100644 index 000000000..2a330c343 --- /dev/null +++ b/src/smol_str.rs @@ -0,0 +1,60 @@ +use std::{sync::Arc}; + +const INLINE_CAP: usize = 22; + +#[derive(Clone, Debug)] +pub(crate) enum SmolStr { + Heap(Arc), + Inline { + len: u8, + buf: [u8; INLINE_CAP], + }, +} + +impl SmolStr { + pub fn new(text: &str) -> SmolStr { + let len = text.len(); + if len <= INLINE_CAP { + let mut buf = [0; INLINE_CAP]; + buf[..len].copy_from_slice(text.as_bytes()); + SmolStr::Inline { len: len as u8, buf } + } else { + SmolStr::Heap( + text.to_string().into_boxed_str().into() + ) + } + } + + pub fn as_str(&self) -> &str { + match self { + SmolStr::Heap(data) => &*data, + SmolStr::Inline { len, buf } => { + let len = *len as usize; + let buf = &buf[..len]; + unsafe { ::std::str::from_utf8_unchecked(buf) } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + #[cfg(target_pointer_width = "64")] + fn smol_str_is_smol() { + assert_eq!(::std::mem::size_of::(), 8 + 8 + 8) + } + + #[test] + fn test_round_trip() { + let mut text = String::new(); + for n in 0..256 { + let smol = SmolStr::new(&text); + assert_eq!(smol.as_str(), text.as_str()); + text.push_str(&n.to_string()); + } + } +} + -- cgit v1.2.3