Skip to content

Commit

Permalink
Merge pull request #34 from epage/backend
Browse files Browse the repository at this point in the history
feat!: Allow configuring the backend
  • Loading branch information
epage authored Mar 29, 2022
2 parents 63d1548 + f580c6d commit fa5b749
Show file tree
Hide file tree
Showing 5 changed files with 360 additions and 238 deletions.
97 changes: 97 additions & 0 deletions src/backend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#[cfg(feature = "arc")]
pub(crate) type DefaultStr = crate::backend::ArcStr;
#[cfg(not(feature = "arc"))]
pub(crate) type DefaultStr = crate::backend::BoxedStr;

/// Fast allocations, O(n) clones
pub type BoxedStr = Box<str>;
static_assertions::assert_eq_size!(DefaultStr, BoxedStr);

/// Cross-thread, O(1) clones
pub type ArcStr = std::sync::Arc<str>;
static_assertions::assert_eq_size!(DefaultStr, ArcStr);

/// O(1) clones
pub type RcStr = std::rc::Rc<str>;
static_assertions::assert_eq_size!(DefaultStr, RcStr);

/// Abstract over different type of heap-allocated strings
pub trait HeapStr: std::fmt::Debug + Clone + private::Sealed {
fn from_str(other: &str) -> Self;
fn from_string(other: String) -> Self;
fn from_boxed_str(other: BoxedStr) -> Self;
fn as_str(&self) -> &str;
}

impl HeapStr for BoxedStr {
#[inline]
fn from_str(other: &str) -> Self {
other.into()
}

#[inline]
fn from_string(other: String) -> Self {
other.into_boxed_str()
}

#[inline]
fn from_boxed_str(other: BoxedStr) -> Self {
other
}

#[inline]
fn as_str(&self) -> &str {
self
}
}

impl HeapStr for ArcStr {
#[inline]
fn from_str(other: &str) -> Self {
other.into()
}

#[inline]
fn from_string(other: String) -> Self {
other.into_boxed_str().into()
}

#[inline]
fn from_boxed_str(other: BoxedStr) -> Self {
other.into()
}

#[inline]
fn as_str(&self) -> &str {
self
}
}

impl HeapStr for RcStr {
#[inline]
fn from_str(other: &str) -> Self {
other.into()
}

#[inline]
fn from_string(other: String) -> Self {
other.into_boxed_str().into()
}

#[inline]
fn from_boxed_str(other: BoxedStr) -> Self {
other.into()
}

#[inline]
fn as_str(&self) -> &str {
self
}
}

pub(crate) mod private {
pub trait Sealed {}
impl Sealed for super::BoxedStr {}
impl Sealed for super::ArcStr {}
impl Sealed for super::RcStr {}
}
26 changes: 22 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
//! Key String: Optimized for map keys.
//!
//! # Examples
//!
//! String creation
//! ```rust
//! // Explicit
//! let literal = kstring::KString::from_static("literal");
//! // Implicit
//! let literal = kstring::KString::from("literal");
//!
//! // Explicit
//! let inline = kstring::KString::try_inline("stack").unwrap();
//! let inline = kstring::KString::from_ref("stack");
//!
//! let formatted: kstring::KStringCow = format!("Hello {} and {}", literal, inline).into();
//! ```
//!
//! # Background
//!
//! Considerations:
Expand All @@ -12,8 +28,8 @@
//!
//! Ramifications:
//! - Inline small strings rather than going to the heap.
//! - Preserve `&'static str` across strings (`KString`),
//! references (`KStringRef`), and lifetime abstractions (`KStringCow`) to avoid
//! - Preserve `&'static str` across strings ([`KString`]),
//! references ([`KStringRef`]), and lifetime abstractions ([`KStringCow`]) to avoid
//! allocating for struct field names.
//! - Use `Box<str>` rather than `String` to use less memory.
//!
Expand All @@ -30,6 +46,8 @@ mod string;
mod string_cow;
mod string_ref;

pub mod backend;

pub use stack::StackString;
pub use string::*;
pub use string_cow::*;
Expand All @@ -45,11 +63,11 @@ mod test {
);
println!(
"Box<str>: {}",
std::mem::size_of::<crate::string::OwnedStr>()
std::mem::size_of::<crate::backend::DefaultStr>()
);
println!(
"Box<Box<str>>: {}",
std::mem::size_of::<Box<crate::string::OwnedStr>>()
std::mem::size_of::<Box<crate::backend::DefaultStr>>()
);
println!("str: {}", std::mem::size_of::<&'static str>());
println!(
Expand Down
Loading

0 comments on commit fa5b749

Please sign in to comment.