#![no_std]
#[cfg(doctest)]
#[doc = include_str!("../README.md")]
mod readme_doctests {}
#[cfg(doctest)]
#[doc = include_str!("../README_CN.md")]
mod readme_cn_doctests {}
extern crate alloc;
mod arch;
mod backend;
mod core;
mod raw;
use ::core::borrow::Borrow;
use ::core::cmp::Ordering;
use ::core::fmt;
use ::core::hash::{Hash, Hasher};
use ::core::mem::ManuallyDrop;
use ::core::ops::Deref;
use alloc::borrow::Cow;
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::string::String;
use alloc::sync::Arc;
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Result as ArbitraryResult, Unstructured};
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub use crate::raw::RawParts;
#[repr(transparent)]
pub struct RefStr<'a>(ManuallyDrop<crate::core::RefStrCore<'a, crate::core::SharedBackend>>);
#[repr(transparent)]
pub struct LocalRefStr<'a>(ManuallyDrop<crate::core::RefStrCore<'a, crate::core::LocalBackend>>);
#[repr(transparent)]
pub struct StaticRefStr(ManuallyDrop<crate::core::RefStrCore<'static, crate::core::SharedBackend>>);
#[repr(transparent)]
pub struct LocalStaticRefStr(
ManuallyDrop<crate::core::RefStrCore<'static, crate::core::LocalBackend>>,
);
macro_rules! impl_ref_str_common {
(
impl [$($impl_generics:tt)*] $ty:ty {
lifetime = $lt:lifetime;
backend = $backend:ty;
shared = $shared:ty;
$($methods:tt)*
}
) => {
impl $($impl_generics)* $ty {
#[inline]
const fn from_inner(inner: crate::core::RefStrCore<$lt, $backend>) -> Self {
Self(ManuallyDrop::new(inner))
}
#[inline]
const fn inner(&self) -> &crate::core::RefStrCore<$lt, $backend> {
let ptr = &self.0
as *const ManuallyDrop<crate::core::RefStrCore<$lt, $backend>>
as *const crate::core::RefStrCore<$lt, $backend>;
unsafe { &*ptr }
}
#[inline]
const unsafe fn into_raw_parts_struct(self) -> crate::RawParts {
#[repr(C)]
union View<T> {
outer: ManuallyDrop<T>,
parts: crate::RawParts,
}
let view = View {
outer: ManuallyDrop::new(self),
};
unsafe { view.parts }
}
#[inline]
unsafe fn into_inner(self) -> crate::core::RefStrCore<$lt, $backend> {
unsafe {
<crate::core::RefStrCore<$lt, $backend>>::from_raw_parts_struct(
self.into_raw_parts_struct(),
)
}
}
#[inline]
pub const fn new(s: &$lt str) -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::new(s))
}
#[inline]
pub const fn from_str(s: &$lt str) -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::from_str(s))
}
#[inline]
pub fn from_owned_like<R: AsRef<str>>(s: R) -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::from_owned_like(s))
}
#[inline]
pub const unsafe fn from_raw_parts(parts: crate::RawParts) -> Self {
Self::from_inner(unsafe {
<crate::core::RefStrCore<$lt, $backend>>::from_raw_parts(parts)
})
}
#[inline]
pub fn from_shared(s: $shared) -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::from_shared(s))
}
#[inline]
pub const unsafe fn into_raw_parts(self) -> crate::RawParts {
unsafe { self.into_raw_parts_struct() }
}
#[inline]
pub unsafe fn into_raw(self) -> *const str {
unsafe { self.into_inner().into_raw() }
}
#[inline]
pub fn into_raw_shared(self) -> Option<*const str> {
unsafe { self.into_inner() }.into_raw_shared()
}
#[inline]
pub unsafe fn increment_strong_count(ptr: *const str) {
unsafe {
<crate::core::RefStrCore<$lt, $backend>>::increment_strong_count(ptr);
}
}
#[inline]
pub const fn is_shared(&self) -> bool {
self.inner().is_shared()
}
#[inline]
pub const fn is_borrowed(&self) -> bool {
self.inner().is_borrowed()
}
#[inline]
pub const fn is_inline(&self) -> bool {
self.inner().is_inline()
}
#[inline]
pub const fn is_ascii(&self) -> bool {
self.inner().is_ascii()
}
#[inline]
pub const fn len(&self) -> usize {
self.inner().len()
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.inner().is_empty()
}
#[inline]
pub fn as_str(&self) -> &str {
self.inner().as_str()
}
#[inline]
pub fn into_bytes(self) -> alloc::vec::Vec<u8> {
unsafe { self.into_inner() }.into_bytes()
}
#[inline]
pub fn into_boxed_str(self) -> Box<str> {
unsafe { self.into_inner() }.into_boxed_str()
}
#[inline]
pub fn into_string(self) -> String {
unsafe { self.into_inner() }.into_string()
}
#[inline]
pub fn into_cow(self) -> Cow<$lt, str> {
unsafe { self.into_inner() }.into_cow()
}
#[inline]
pub unsafe fn into_str_unchecked(self) -> &$lt str {
unsafe { self.into_inner().into_str_unchecked() }
}
$($methods)*
}
impl $($impl_generics)* Drop for $ty {
fn drop(&mut self) {
unsafe {
ManuallyDrop::drop(&mut self.0);
}
}
}
impl $($impl_generics)* Default for $ty {
fn default() -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::default())
}
}
impl $($impl_generics)* AsRef<str> for $ty {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl $($impl_generics)* Borrow<str> for $ty {
fn borrow(&self) -> &str {
self.as_str()
}
}
impl $($impl_generics)* Clone for $ty {
fn clone(&self) -> Self {
Self::from_inner(self.inner().clone())
}
}
impl $($impl_generics)* Eq for $ty {}
impl $($impl_generics)* PartialOrd for $ty {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl $($impl_generics)* Ord for $ty {
fn cmp(&self, other: &Self) -> Ordering {
self.as_str().cmp(other.as_str())
}
}
impl $($impl_generics)* Hash for $ty {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_str().hash(state)
}
}
impl $($impl_generics)* Deref for $ty {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl $($impl_generics)* fmt::Debug for $ty {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if f.alternate() {
let state = if self.is_shared() {
"Shared"
} else if self.is_inline() {
"Inline"
} else {
"Borrowed"
};
f.debug_struct(stringify!($ty))
.field("state", &state)
.field("len", &self.len())
.field("value", &self.as_str())
.finish()
} else {
f.debug_tuple(stringify!($ty))
.field(&self.as_str())
.finish()
}
}
}
impl $($impl_generics)* fmt::Display for $ty {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[cfg(feature = "serde")]
impl $($impl_generics)* Serialize for $ty {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(self.as_str())
}
}
};
}
macro_rules! impl_ref_str_non_static {
($name:ident<$lt:lifetime>, $backend:ty, $shared:ty) => {
impl<$lt> From<&$lt str> for $name<$lt> {
fn from(value: &$lt str) -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::from(value))
}
}
impl<$lt> From<&$lt String> for $name<$lt> {
fn from(value: &$lt String) -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::from(value))
}
}
impl<$lt> From<$shared> for $name<$lt> {
fn from(value: $shared) -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::from(value))
}
}
impl<$lt> From<Box<str>> for $name<$lt> {
fn from(value: Box<str>) -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::from(value))
}
}
impl<$lt> From<String> for $name<$lt> {
fn from(value: String) -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::from(value))
}
}
impl<$lt> From<Cow<$lt, str>> for $name<$lt> {
fn from(value: Cow<$lt, str>) -> Self {
Self::from_inner(<crate::core::RefStrCore<$lt, $backend>>::from(value))
}
}
impl<$lt> From<$name<$lt>> for Cow<$lt, str> {
fn from(value: $name<$lt>) -> Self {
value.into_cow()
}
}
#[cfg(feature = "arbitrary")]
impl<$lt> Arbitrary<$lt> for $name<$lt> {
fn arbitrary(u: &mut Unstructured<$lt>) -> ArbitraryResult<Self> {
let value = <&$lt str>::arbitrary(u)?;
if u.arbitrary::<bool>()? {
Ok(Self::from(String::from(value)))
} else {
Ok(Self::from(value))
}
}
}
#[cfg(feature = "serde")]
impl<'de: $lt, $lt> Deserialize<'de> for $name<$lt> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = $name<'de>;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a string")
}
fn visit_borrowed_str<E: serde::de::Error>(
self,
v: &'de str,
) -> Result<Self::Value, E> {
Ok($name::from(v))
}
fn visit_str<E: serde::de::Error>(
self,
v: &str,
) -> Result<Self::Value, E> {
Ok($name::from(String::from(v)))
}
fn visit_string<E: serde::de::Error>(
self,
v: String,
) -> Result<Self::Value, E> {
Ok($name::from(v))
}
}
deserializer.deserialize_str(Visitor)
}
}
};
}
macro_rules! impl_ref_str_static {
($name:ident, $backend:ty, $shared:ty) => {
impl From<&'static str> for $name {
fn from(value: &'static str) -> Self {
Self::from_inner(<crate::core::RefStrCore<'static, $backend>>::from(value))
}
}
impl From<$shared> for $name {
fn from(value: $shared) -> Self {
Self::from_inner(<crate::core::RefStrCore<'static, $backend>>::from(value))
}
}
impl From<Box<str>> for $name {
fn from(value: Box<str>) -> Self {
Self::from_inner(<crate::core::RefStrCore<'static, $backend>>::from(value))
}
}
impl From<String> for $name {
fn from(value: String) -> Self {
Self::from_inner(<crate::core::RefStrCore<'static, $backend>>::from(value))
}
}
impl From<Cow<'static, str>> for $name {
fn from(value: Cow<'static, str>) -> Self {
match value {
Cow::Borrowed(value) => Self::from(value),
Cow::Owned(value) => Self::from(value),
}
}
}
impl From<$name> for Cow<'static, str> {
fn from(value: $name) -> Self {
value.into_cow()
}
}
#[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for $name {
fn arbitrary(u: &mut Unstructured<'a>) -> ArbitraryResult<Self> {
let value = <&str>::arbitrary(u)?;
Ok(Self::from(String::from(value)))
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for $name {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor {
type Value = $name;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a string")
}
fn visit_borrowed_str<E: serde::de::Error>(
self,
v: &'de str,
) -> Result<Self::Value, E> {
Ok($name::from(String::from(v)))
}
fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
Ok($name::from(String::from(v)))
}
fn visit_string<E: serde::de::Error>(
self,
v: String,
) -> Result<Self::Value, E> {
Ok($name::from(v))
}
}
deserializer.deserialize_str(Visitor)
}
}
};
}
macro_rules! impl_ref_str_partial_eqs {
(for $lhs:ty { $([$($impl_generics:tt)*] $rhs:ty => |$lhs_ref:ident, $other:ident| $compare:expr;)+ }) => {
$(
impl_ref_str_partial_eqs!(@single [$($impl_generics)*] $lhs => $rhs, |$lhs_ref, $other| $compare);
)+
};
(@single [] $lhs:ty => $rhs:ty, |$lhs_ref:ident, $other:ident| $compare:expr) => {
impl PartialEq<$rhs> for $lhs {
fn eq(&self, other: &$rhs) -> bool {
let $lhs_ref = self;
let $other = other;
$compare
}
}
impl PartialEq<$rhs> for &$lhs {
fn eq(&self, other: &$rhs) -> bool {
let $lhs_ref = *self;
let $other = other;
$compare
}
}
impl PartialEq<&$rhs> for $lhs {
fn eq(&self, other: &&$rhs) -> bool {
let $lhs_ref = self;
let $other = *other;
$compare
}
}
};
(@single [$($impl_generics:tt)+] $lhs:ty => $rhs:ty, |$lhs_ref:ident, $other:ident| $compare:expr) => {
impl<$($impl_generics)+> PartialEq<$rhs> for $lhs {
fn eq(&self, other: &$rhs) -> bool {
let $lhs_ref = self;
let $other = other;
$compare
}
}
impl<$($impl_generics)+> PartialEq<$rhs> for &$lhs {
fn eq(&self, other: &$rhs) -> bool {
let $lhs_ref = *self;
let $other = other;
$compare
}
}
impl<$($impl_generics)+> PartialEq<&$rhs> for $lhs {
fn eq(&self, other: &&$rhs) -> bool {
let $lhs_ref = self;
let $other = *other;
$compare
}
}
};
}
impl_ref_str_common! {
impl [<'a>] RefStr<'a> {
lifetime = 'a;
backend = crate::core::SharedBackend;
shared = Arc<str>;
#[inline]
pub fn as_cow(&self) -> Cow<'a, str> {
self.inner().as_cow()
}
#[inline]
pub fn to_static_str(&self) -> StaticRefStr {
StaticRefStr::from_inner(self.inner().to_static_core())
}
#[inline]
pub fn into_static_str(self) -> StaticRefStr {
StaticRefStr::from_inner(unsafe { self.into_inner() }.into_static_core())
}
}
}
impl_ref_str_common! {
impl [<'a>] LocalRefStr<'a> {
lifetime = 'a;
backend = crate::core::LocalBackend;
shared = Rc<str>;
#[inline]
pub fn as_cow(&self) -> Cow<'a, str> {
self.inner().as_cow()
}
#[inline]
pub fn to_static_str(&self) -> LocalStaticRefStr {
LocalStaticRefStr::from_inner(self.inner().to_static_core())
}
#[inline]
pub fn into_static_str(self) -> LocalStaticRefStr {
LocalStaticRefStr::from_inner(unsafe { self.into_inner() }.into_static_core())
}
}
}
impl_ref_str_common! {
impl [] StaticRefStr {
lifetime = 'static;
backend = crate::core::SharedBackend;
shared = Arc<str>;
#[inline]
pub fn as_cow(&self) -> Cow<'static, str> {
if let Some(value) = self.inner().borrowed_static_str() {
Cow::Borrowed(value)
} else {
Cow::Owned(String::from(self.as_str()))
}
}
#[inline]
pub const fn from_static(s: &'static str) -> Self {
Self::from_str(s)
}
}
}
impl_ref_str_common! {
impl [] LocalStaticRefStr {
lifetime = 'static;
backend = crate::core::LocalBackend;
shared = Rc<str>;
#[inline]
pub fn as_cow(&self) -> Cow<'static, str> {
if let Some(value) = self.inner().borrowed_static_str() {
Cow::Borrowed(value)
} else {
Cow::Owned(String::from(self.as_str()))
}
}
#[inline]
pub const fn from_static(s: &'static str) -> Self {
Self::from_str(s)
}
}
}
impl_ref_str_non_static!(RefStr<'a>, crate::core::SharedBackend, Arc<str>);
impl_ref_str_non_static!(LocalRefStr<'a>, crate::core::LocalBackend, Rc<str>);
impl_ref_str_static!(StaticRefStr, crate::core::SharedBackend, Arc<str>);
impl_ref_str_static!(LocalStaticRefStr, crate::core::LocalBackend, Rc<str>);
impl_ref_str_partial_eqs! {
for RefStr<'a> {
['a] RefStr<'a> => |lhs, other| lhs.inner() == other.inner();
['a] &str => |lhs, other| lhs.as_str() == *other;
['a] String => |lhs, other| lhs.as_str() == other.as_str();
['a, 'b] Cow<'b, str> => |lhs, other| lhs.as_str() == other.as_ref();
['a] Arc<str> => |lhs, other| lhs.as_str() == other.as_ref();
['a] Rc<str> => |lhs, other| lhs.as_str() == other.as_ref();
}
}
impl_ref_str_partial_eqs! {
for LocalRefStr<'a> {
['a] LocalRefStr<'a> => |lhs, other| lhs.inner() == other.inner();
['a] &str => |lhs, other| lhs.as_str() == *other;
['a] String => |lhs, other| lhs.as_str() == other.as_str();
['a, 'b] Cow<'b, str> => |lhs, other| lhs.as_str() == other.as_ref();
['a] Arc<str> => |lhs, other| lhs.as_str() == other.as_ref();
['a] Rc<str> => |lhs, other| lhs.as_str() == other.as_ref();
}
}
impl_ref_str_partial_eqs! {
for StaticRefStr {
[] StaticRefStr => |lhs, other| lhs.inner() == other.inner();
[] &str => |lhs, other| lhs.as_str() == *other;
[] String => |lhs, other| lhs.as_str() == other.as_str();
['b] Cow<'b, str> => |lhs, other| lhs.as_str() == other.as_ref();
[] Arc<str> => |lhs, other| lhs.as_str() == other.as_ref();
[] Rc<str> => |lhs, other| lhs.as_str() == other.as_ref();
}
}
impl_ref_str_partial_eqs! {
for LocalStaticRefStr {
[] LocalStaticRefStr => |lhs, other| lhs.inner() == other.inner();
[] &str => |lhs, other| lhs.as_str() == *other;
[] String => |lhs, other| lhs.as_str() == other.as_str();
['b] Cow<'b, str> => |lhs, other| lhs.as_str() == other.as_ref();
[] Arc<str> => |lhs, other| lhs.as_str() == other.as_ref();
[] Rc<str> => |lhs, other| lhs.as_str() == other.as_ref();
}
}
impl<'a> From<LocalRefStr<'a>> for RefStr<'a> {
fn from(value: LocalRefStr<'a>) -> Self {
Self::from_inner(
<crate::core::RefStrCore<'a, crate::core::SharedBackend>>::from(unsafe {
value.into_inner()
}),
)
}
}
impl<'a> From<RefStr<'a>> for LocalRefStr<'a> {
fn from(value: RefStr<'a>) -> Self {
Self::from_inner(
<crate::core::RefStrCore<'a, crate::core::LocalBackend>>::from(unsafe {
value.into_inner()
}),
)
}
}
impl From<LocalStaticRefStr> for StaticRefStr {
fn from(value: LocalStaticRefStr) -> Self {
Self::from_inner(
<crate::core::RefStrCore<'static, crate::core::SharedBackend>>::from(unsafe {
value.into_inner()
}),
)
}
}
impl From<StaticRefStr> for LocalStaticRefStr {
fn from(value: StaticRefStr) -> Self {
Self::from_inner(
<crate::core::RefStrCore<'static, crate::core::LocalBackend>>::from(unsafe {
value.into_inner()
}),
)
}
}
impl From<StaticRefStr> for RefStr<'static> {
fn from(value: StaticRefStr) -> Self {
Self::from_inner(unsafe { value.into_inner() })
}
}
impl From<RefStr<'static>> for StaticRefStr {
fn from(value: RefStr<'static>) -> Self {
Self::from_inner(unsafe { value.into_inner() })
}
}
impl From<LocalStaticRefStr> for LocalRefStr<'static> {
fn from(value: LocalStaticRefStr) -> Self {
Self::from_inner(unsafe { value.into_inner() })
}
}
impl From<LocalRefStr<'static>> for LocalStaticRefStr {
fn from(value: LocalRefStr<'static>) -> Self {
Self::from_inner(unsafe { value.into_inner() })
}
}