Skip to content

Commit

Permalink
Merge pull request #58 from msdrigg/master
Browse files Browse the repository at this point in the history
  • Loading branch information
Veykril authored Sep 10, 2023
2 parents f927bdb + 2c54bb6 commit 7d1b60c
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 28 deletions.
77 changes: 50 additions & 27 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,13 +334,31 @@ 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 {
SmolStr::new(s)
}
}

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 {
Expand Down Expand Up @@ -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)]
Expand Down
8 changes: 7 additions & 1 deletion tests/test.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use proptest::{prop_assert, prop_assert_eq, proptest};

use smol_str::SmolStr;
Expand All @@ -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]
Expand Down

0 comments on commit 7d1b60c

Please sign in to comment.