ref_str 0.2.1

Compressed borrowed-or-shared string types for no_std Rust.
Documentation
use ::core::borrow::Borrow;
use ::core::cmp::Ordering;
use ::core::fmt;
use ::core::hash::{Hash, Hasher};
use ::core::ops::Deref;
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::string::String;
use alloc::sync::Arc;

use super::{LocalBackend, RefCountBackend, RefStrCore, SharedBackend};
use crate::arch;

impl<'a, B: RefCountBackend> From<&'a str> for RefStrCore<'a, B> {
    fn from(value: &'a str) -> Self {
        Self::new(value)
    }
}

impl<'a, B: RefCountBackend> From<&'a String> for RefStrCore<'a, B> {
    fn from(value: &'a String) -> Self {
        Self::from(value.as_str())
    }
}

impl<'a> From<Rc<str>> for RefStrCore<'a, LocalBackend> {
    fn from(value: Rc<str>) -> Self {
        Self::from_shared(value)
    }
}

impl<'a> From<Arc<str>> for RefStrCore<'a, SharedBackend> {
    fn from(value: Arc<str>) -> Self {
        Self::from_shared(value)
    }
}

impl<'a> From<RefStrCore<'a, LocalBackend>> for RefStrCore<'a, SharedBackend> {
    fn from(value: RefStrCore<'a, LocalBackend>) -> Self {
        if value.is_shared() {
            Self::from_shared(Arc::from(value.as_str()))
        } else {
            let parts = unsafe { value.into_raw_parts() };
            unsafe { Self::from_raw_parts(parts) }
        }
    }
}

impl<'a> From<RefStrCore<'a, SharedBackend>> for RefStrCore<'a, LocalBackend> {
    fn from(value: RefStrCore<'a, SharedBackend>) -> Self {
        if value.is_shared() {
            Self::from_shared(Rc::from(value.as_str()))
        } else {
            let parts = unsafe { value.into_raw_parts() };
            unsafe { Self::from_raw_parts(parts) }
        }
    }
}

impl<'a, B: RefCountBackend> From<Box<str>> for RefStrCore<'a, B> {
    fn from(value: Box<str>) -> Self {
        Self::from_owned_boxed_str(value)
    }
}

impl<'a, B: RefCountBackend> From<String> for RefStrCore<'a, B> {
    fn from(value: String) -> Self {
        Self::from_owned_string(value)
    }
}

impl<'a, B: RefCountBackend> From<RefStrCore<'a, B>> for Cow<'a, str> {
    fn from(value: RefStrCore<'a, B>) -> Self {
        value.into_cow()
    }
}

impl<'a, B: RefCountBackend> From<Cow<'a, str>> for RefStrCore<'a, B> {
    fn from(value: Cow<'a, str>) -> Self {
        match value {
            Cow::Borrowed(s) => Self::from(s),
            Cow::Owned(s) => Self::from(s),
        }
    }
}

impl<'a, B: RefCountBackend> Default for RefStrCore<'a, B> {
    fn default() -> Self {
        Self::from_str("")
    }
}

impl<'a, B: RefCountBackend> AsRef<str> for RefStrCore<'a, B> {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl<'a, B: RefCountBackend> Borrow<str> for RefStrCore<'a, B> {
    fn borrow(&self) -> &str {
        self.as_str()
    }
}

impl<'a, B: RefCountBackend> PartialEq for RefStrCore<'a, B> {
    fn eq(&self, other: &Self) -> bool {
        if self.parts.raw_ptr() == other.parts.raw_ptr() && self.parts.meta() == other.parts.meta()
        {
            return true;
        }

        if self.is_inline() || other.is_inline() {
            return self.as_str() == other.as_str();
        }

        if self.parts.cached_hash() != other.parts.cached_hash() {
            return false;
        }

        if self.len() != other.len() {
            return false;
        }

        self.as_str() == other.as_str()
    }
}

impl<'a, B: RefCountBackend> Eq for RefStrCore<'a, B> {}

impl<'a, B: RefCountBackend> PartialEq<&str> for RefStrCore<'a, B> {
    fn eq(&self, other: &&str) -> bool {
        self.as_str() == *other
    }
}

impl<'a, B: RefCountBackend> PartialEq<String> for RefStrCore<'a, B> {
    fn eq(&self, other: &String) -> bool {
        self.as_str() == other.as_str()
    }
}

impl<'a, B: RefCountBackend> PartialOrd for RefStrCore<'a, B> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl<'a, B: RefCountBackend> Ord for RefStrCore<'a, B> {
    fn cmp(&self, other: &Self) -> Ordering {
        self.as_str().cmp(other.as_str())
    }
}

impl<'a, B: RefCountBackend> Hash for RefStrCore<'a, B> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.as_str().hash(state)
    }
}

impl<'a, B: RefCountBackend> Deref for RefStrCore<'a, B> {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        self.as_str()
    }
}

impl<'a, B: RefCountBackend> fmt::Debug for RefStrCore<'a, B> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if f.alternate() {
            let state = match self.state_tag() {
                arch::StateTag::Borrowed => "Borrowed",
                arch::StateTag::Shared => "Shared",
                arch::StateTag::Inline => "Inline",
            };

            f.debug_struct("RefStrCore")
                .field("state", &state)
                .field("len", &self.len())
                .field("value", &self.as_str())
                .finish()
        } else {
            f.debug_tuple("RefStrCore").field(&self.as_str()).finish()
        }
    }
}

impl<'a, B: RefCountBackend> fmt::Display for RefStrCore<'a, B> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.as_str())
    }
}

impl<'a, B: RefCountBackend> Clone for RefStrCore<'a, B> {
    fn clone(&self) -> Self {
        let parts = self.parts;
        let meta = parts.meta();
        if (meta & arch::NEEDS_DROP_MASK) != 0 {
            let len = arch::decode_borrowed_or_shared_len(meta);
            let fat_ptr = ::core::ptr::slice_from_raw_parts(parts.as_ptr(), len) as *const str;
            unsafe {
                B::increment_strong_count(fat_ptr);
            }
        }

        Self {
            parts,
            _marker: super::PhantomData,
            _backend: super::PhantomData,
        }
    }
}

impl<'a, B: RefCountBackend> Drop for RefStrCore<'a, B> {
    fn drop(&mut self) {
        let parts = self.parts;
        let meta = parts.meta();
        if (meta & arch::NEEDS_DROP_MASK) != 0 {
            let len = arch::decode_borrowed_or_shared_len(meta);
            let fat_ptr = ::core::ptr::slice_from_raw_parts(parts.as_ptr(), len) as *const str;
            unsafe {
                drop(B::from_raw(fat_ptr));
            }
        }
    }
}

impl<'a, B, F, R> From<F> for RefStrCore<'a, B>
where
    B: RefCountBackend,
    F: FnOnce() -> R,
    Self: From<R>,
{
    /// Creates a `RefStrCore` from a closure that returns any type convertible into this type.
    #[inline]
    fn from(f: F) -> Self {
        Self::from(f())
    }
}