Unnamed repository; edit this file 'description' to name the repository.
Merge pull request rust-analyzer/smol_str#58 from msdrigg/master
Lukas Wirth 2023-09-10
parent b04898e · parent 0eed716 · commit 05052c4
-rw-r--r--lib/smol_str/src/lib.rs77
-rw-r--r--lib/smol_str/tests/test.rs8
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]