Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ std = ["serde?/std"]
is_variant = ["derive_more/is_variant"]
constructors = ["derive_more/constructor"]
index = ["derive_more/index", "derive_more/index_mut"]
smol_str = ["dep:smol_str"]
compact_str = ["dep:compact_str"]

[dependencies]
derive_more = { version = "2.1", default-features = false, optional = true }
Expand All @@ -27,6 +29,8 @@ serde = { version = "1.0", features = [
"rc",
"alloc",
], default-features = false, optional = true }
smol_str = { version = "0.3", default-features = false, optional = true }
compact_str = { version = "0.9", default-features = false, optional = true }

[dev-dependencies]
serde_json = "1.0"
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ usage is a concern, such as embedded systems or real-time applications.
- [x] Supports comparison and ordering operations.
- [x] Supports serialization/deserialization with **[serde]**
> **Note**: Requires the `serde` feature flag to be enabled.
- [x] Supports conversions with **[smol_str]**
> **Note**: Requires the `smol_str` feature flag to be enabled.
- [x] Supports conversions with **[compact_str]**
> **Note**: Requires the `compact_str` feature flag to be enabled.

```rust
use moos::InlineStr;
Expand Down Expand Up @@ -191,6 +195,8 @@ match InlineStr::try_from(long_string) {
[Nicholas Berlette]: https://github.com/nberlette "Follow @nberlette on GitHub for more cool stuff!"
[`MAX_INLINE_STR_LEN`]: #max_inline_str_len
[serde]: https://crates.io/crates/serde "Serialization framework for Rust"
[smol_str]: https://crates.io/crates/smol_str "Small-string optimization string type"
[compact_str]: https://crates.io/crates/compact_str "Compact heap-avoiding string type"
[moos]: https://crates.io/crates/moos "moos on crates.io"
[GitHub]: https://github.com/nberlette/moos "moos on GitHub"
[Issues]: https://github.com/nberlette/moos/issues "moos issues on GitHub"
Expand Down
122 changes: 122 additions & 0 deletions src/cow_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,13 @@ impl<'i> AsRef<str> for CowStr<'i> {
}
}

impl<'i> AsRef<[u8]> for CowStr<'i> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}

impl<'i> AsMut<str> for CowStr<'i> {
#[inline(always)]
fn as_mut(&mut self) -> &mut str {
Expand Down Expand Up @@ -367,13 +374,34 @@ impl<'i> From<String> for CowStr<'i> {
}
}

impl<'i> From<Box<str>> for CowStr<'i> {
#[inline(always)]
fn from(s: Box<str>) -> Self {
CowStr::Owned(s)
}
}

impl<'i> From<&'i String> for CowStr<'i> {
#[inline(always)]
fn from(s: &'i String) -> Self {
CowStr::Borrowed(s.as_str())
}
}

impl<'i> From<char> for CowStr<'i> {
#[inline(always)]
fn from(c: char) -> Self {
CowStr::Inlined(c.into())
}
}

impl<'i> From<InlineStr> for CowStr<'i> {
#[inline(always)]
fn from(s: InlineStr) -> Self {
CowStr::Inlined(s)
}
}

impl<'i> From<Cow<'i, str>> for CowStr<'i> {
#[inline(always)]
fn from(s: Cow<'i, str>) -> Self {
Expand Down Expand Up @@ -409,6 +437,62 @@ impl<'i> From<CowStr<'i>> for String {
}
}

#[cfg(feature = "smol_str")]
mod smol_str_impl {
use smol_str::SmolStr;

use super::*;

impl<'i> From<SmolStr> for CowStr<'i> {
#[inline(always)]
fn from(s: SmolStr) -> Self {
CowStr::Owned(s.to_string().into_boxed_str())
}
}

impl<'i> From<&'i SmolStr> for CowStr<'i> {
#[inline(always)]
fn from(s: &'i SmolStr) -> Self {
CowStr::Borrowed(s.as_str())
}
}

impl<'i> From<CowStr<'i>> for SmolStr {
#[inline(always)]
fn from(s: CowStr<'i>) -> Self {
SmolStr::new(s.as_str())
}
}
}

#[cfg(feature = "compact_str")]
mod compact_str_impl {
use compact_str::CompactString;

use super::*;

impl<'i> From<CompactString> for CowStr<'i> {
#[inline(always)]
fn from(s: CompactString) -> Self {
CowStr::Owned(s.to_string().into_boxed_str())
}
}

impl<'i> From<&'i CompactString> for CowStr<'i> {
#[inline(always)]
fn from(s: &'i CompactString) -> Self {
CowStr::Borrowed(s.as_str())
}
}

impl<'i> From<CowStr<'i>> for CompactString {
#[inline(always)]
fn from(s: CowStr<'i>) -> Self {
CompactString::from(s.as_str())
}
}
}

#[cfg(not(feature = "is_variant"))]
impl<'i> CowStr<'i> {
/// Returns `true` if the `CowStr` is the `Owned` variant.
Expand Down Expand Up @@ -660,6 +744,44 @@ mod tests {
assert!(variant_eq(&actual, &expected));
}

#[test]
fn from_core_types() {
let boxed: Box<str> = "boxed".to_string().into_boxed_str();
let cow = CowStr::from(boxed);
assert!(cow.is_owned());
assert_eq!(cow.as_str(), "boxed");

let s = "string".to_string();
let cow = CowStr::from(&s);
assert!(cow.is_borrowed());
assert_eq!(cow.as_str(), "string");

let inline = InlineStr::try_from("inline").unwrap();
let cow = CowStr::from(inline);
assert!(cow.is_inlined());
assert_eq!(cow.as_str(), "inline");
}

#[cfg(feature = "smol_str")]
#[test]
fn smol_str_conversions() {
let smol = smol_str::SmolStr::new("smol");
let cow = CowStr::from(smol.clone());
assert_eq!(cow.as_str(), "smol");
let smol_back = smol_str::SmolStr::from(cow);
assert_eq!(smol_back, smol);
}

#[cfg(feature = "compact_str")]
#[test]
fn compact_str_conversions() {
let compact = compact_str::CompactString::from("compact");
let cow = CowStr::from(compact.clone());
assert_eq!(cow.as_str(), "compact");
let compact_back = compact_str::CompactString::from(cow);
assert_eq!(compact_back, compact);
}

fn variant_eq<T>(a: &T, b: &T) -> bool {
std::mem::discriminant(a) == std::mem::discriminant(b)
}
Expand Down
85 changes: 84 additions & 1 deletion src/inline_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub struct StringTooLongError;
///
/// # fn main() -> Result<(), StringTooLongError> {
/// let inline_str: InlineStr = "Hello".parse()?;
/// assert_eq!(inline_str.as_ref(), "Hello");
/// assert_eq!(inline_str.as_str(), "Hello");
/// assert_eq!(inline_str.len(), 5);
///
/// // This will fail because the string is too long:
Expand Down Expand Up @@ -224,6 +224,13 @@ impl AsRef<str> for InlineStr {
}
}

impl AsRef<[u8]> for InlineStr {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}

impl AsMut<str> for InlineStr {
#[inline(always)]
fn as_mut(&mut self) -> &mut str {
Expand Down Expand Up @@ -296,6 +303,13 @@ impl From<String> for InlineStr {
}
}

impl From<CowStr<'_>> for InlineStr {
#[inline(always)]
fn from(s: CowStr<'_>) -> Self {
InlineStr::from(s.into_string())
}
}

impl TryFrom<&str> for InlineStr {
type Error = StringTooLongError;

Expand All @@ -312,6 +326,48 @@ impl TryFrom<&str> for InlineStr {
}
}

#[cfg(feature = "smol_str")]
mod smol_str_impl {
use smol_str::SmolStr;

use super::*;

impl From<SmolStr> for InlineStr {
#[inline(always)]
fn from(s: SmolStr) -> Self {
InlineStr::from(s.as_str().to_string())
}
}

impl From<InlineStr> for SmolStr {
#[inline(always)]
fn from(s: InlineStr) -> Self {
SmolStr::new(s.as_str())
}
}
}

#[cfg(feature = "compact_str")]
mod compact_str_impl {
use compact_str::CompactString;

use super::*;

impl From<CompactString> for InlineStr {
#[inline(always)]
fn from(s: CompactString) -> Self {
InlineStr::from(s.to_string())
}
}

impl From<InlineStr> for CompactString {
#[inline(always)]
fn from(s: InlineStr) -> Self {
CompactString::from(s.as_str())
}
}
}

impl Hash for InlineStr {
#[inline(always)]
fn hash<H: Hasher>(&self, state: &mut H) {
Expand Down Expand Up @@ -640,4 +696,31 @@ mod tests {
}
assert_eq!(s, "HELLO");
}

#[test]
fn inline_str_from_cow_str() {
let cow = CowStr::Borrowed("abcdef");
let inline = InlineStr::from(cow);
assert_eq!(inline, "abcdef");
}

#[cfg(feature = "smol_str")]
#[test]
fn smol_str_conversions() {
let smol = smol_str::SmolStr::new("smol");
let inline = InlineStr::from(smol.clone());
assert_eq!(inline, "smol");
let smol_back = smol_str::SmolStr::from(inline);
assert_eq!(smol_back, smol);
}

#[cfg(feature = "compact_str")]
#[test]
fn compact_str_conversions() {
let compact = compact_str::CompactString::from("compact");
let inline = InlineStr::from(compact.clone());
assert_eq!(inline, "compact");
let compact_back = compact_str::CompactString::from(inline);
assert_eq!(compact_back, compact);
}
}
Loading