Unnamed repository; edit this file 'description' to name the repository.
Merge pull request rust-analyzer/smol_str#58 from msdrigg/master
| -rw-r--r-- | lib/smol_str/src/lib.rs | 77 | ||||
| -rw-r--r-- | lib/smol_str/tests/test.rs | 8 |
2 files changed, 57 insertions, 28 deletions
diff --git a/lib/smol_str/src/lib.rs b/lib/smol_str/src/lib.rs index 91dc6252cc..5f0431d419 100644 --- a/lib/smol_str/src/lib.rs +++ b/lib/smol_str/src/lib.rs @@ -334,6 +334,14 @@ impl From<Box<str>> for SmolStr { } } +impl From<Arc<str>> for SmolStr { + #[inline] + fn from(s: Arc<str>) -> SmolStr { + let repr = Repr::new_on_stack(s.as_ref()).unwrap_or_else(|| Repr::Heap(s)); + Self(repr) + } +} + impl<'a> From<Cow<'a, str>> for SmolStr { #[inline] fn from(s: Cow<'a, str>) -> SmolStr { @@ -341,6 +349,16 @@ impl<'a> From<Cow<'a, str>> for SmolStr { } } +impl From<SmolStr> for Arc<str> { + #[inline(always)] + fn from(text: SmolStr) -> Self { + match text.0 { + Repr::Heap(data) => data, + _ => text.as_str().into(), + } + } +} + impl From<SmolStr> for String { #[inline(always)] fn from(text: SmolStr) -> Self { @@ -421,40 +439,45 @@ enum Repr { } impl Repr { - fn new<T>(text: T) -> Self + /// This function tries to create a new Repr::Inline or Repr::Substring + /// If it isn't possible, this function returns None + fn new_on_stack<T>(text: T) -> Option<Self> where T: AsRef<str>, { - { - let text = text.as_ref(); - - let len = text.len(); - if len <= INLINE_CAP { - let mut buf = [0; INLINE_CAP]; - buf[..len].copy_from_slice(text.as_bytes()); - return Repr::Inline { - len: unsafe { transmute(len as u8) }, - buf, - }; - } + let text = text.as_ref(); + + let len = text.len(); + if len <= INLINE_CAP { + let mut buf = [0; INLINE_CAP]; + buf[..len].copy_from_slice(text.as_bytes()); + return Some(Repr::Inline { + len: unsafe { transmute(len as u8) }, + buf, + }); + } - if len <= N_NEWLINES + N_SPACES { - let bytes = text.as_bytes(); - let possible_newline_count = cmp::min(len, N_NEWLINES); - let newlines = bytes[..possible_newline_count] - .iter() - .take_while(|&&b| b == b'\n') - .count(); - let possible_space_count = len - newlines; - if possible_space_count <= N_SPACES && bytes[newlines..].iter().all(|&b| b == b' ') - { - let spaces = possible_space_count; - return Repr::Substring { newlines, spaces }; - } + if len <= N_NEWLINES + N_SPACES { + let bytes = text.as_bytes(); + let possible_newline_count = cmp::min(len, N_NEWLINES); + let newlines = bytes[..possible_newline_count] + .iter() + .take_while(|&&b| b == b'\n') + .count(); + let possible_space_count = len - newlines; + if possible_space_count <= N_SPACES && bytes[newlines..].iter().all(|&b| b == b' ') { + let spaces = possible_space_count; + return Some(Repr::Substring { newlines, spaces }); } } + None + } - Repr::Heap(text.as_ref().into()) + fn new<T>(text: T) -> Self + where + T: AsRef<str>, + { + Self::new_on_stack(text.as_ref()).unwrap_or_else(|| Repr::Heap(text.as_ref().into())) } #[inline(always)] diff --git a/lib/smol_str/tests/test.rs b/lib/smol_str/tests/test.rs index 187b39f001..1fbe7d667d 100644 --- a/lib/smol_str/tests/test.rs +++ b/lib/smol_str/tests/test.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use proptest::{prop_assert, prop_assert_eq, proptest}; use smol_str::SmolStr; @@ -21,7 +23,11 @@ fn assert_traits() { fn conversions() { let s: SmolStr = "Hello, World!".into(); let s: String = s.into(); - assert_eq!(s, "Hello, World!") + assert_eq!(s, "Hello, World!"); + + let s: SmolStr = Arc::<str>::from("Hello, World!").into(); + let s: Arc<str> = s.into(); + assert_eq!(s.as_ref(), "Hello, World!"); } #[test] |