use core::{borrow::Borrow, cmp, fmt, hash::Hash, hash::Hasher, mem, ops::Deref, str::FromStr};
use alloc::{borrow::Cow, boxed::Box, string::String};
#[cfg(feature = "std")]
use std::ffi::OsStr;
use crate::{CharString, Repr, ReserveError, UnwrapWithMsg};
#[repr(transparent)]
pub struct CharStr(Repr);
const _: () = {
assert!(size_of::<CharStr>() == size_of::<[usize; 2]>());
assert!(size_of::<Option<CharStr>>() == size_of::<[usize; 2]>());
assert!(align_of::<CharStr>() == align_of::<usize>());
assert!(align_of::<Option<CharStr>>() == align_of::<usize>());
};
impl CharStr {
pub const INLINE_CAPACITY: usize = crate::repr::MAX_INLINE_SIZE;
#[inline]
pub const fn new() -> Self {
Self(Repr::new())
}
#[inline]
pub const fn from_static_str(text: &'static str) -> Self {
match Repr::from_static_str(text) {
Ok(repr) => Self(repr),
Err(_) => panic!("text is too long"),
}
}
#[inline]
pub fn try_from_str(text: &str) -> Result<Self, ReserveError> {
Repr::from_exact_str(text).map(Self)
}
#[inline]
pub fn concat<T: AsRef<str>>(slices: &[T]) -> Self {
Self::try_concat(slices).unwrap_with_msg()
}
#[inline]
pub fn try_concat<T: AsRef<str>>(slices: &[T]) -> Result<Self, ReserveError> {
Self::try_join(slices, "")
}
#[inline]
pub fn join<T: AsRef<str>>(slices: &[T], separator: &str) -> Self {
Self::try_join(slices, separator).unwrap_with_msg()
}
#[inline]
pub fn try_join<T: AsRef<str>>(slices: &[T], separator: &str) -> Result<Self, ReserveError> {
Repr::from_exact_joined_slices(slices, separator).map(Self)
}
#[inline]
pub const fn as_str(&self) -> &str {
self.0.as_str()
}
#[inline]
pub const fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
#[inline]
pub const fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub const fn is_empty(&self) -> bool {
self.0.is_empty()
}
#[inline]
pub const fn is_heap_allocated(&self) -> bool {
self.0.is_heap_buffer()
}
#[cfg(feature = "get-size")]
pub(crate) fn heap_allocation_size(&self) -> usize {
self.0.heap_allocation_size()
}
#[inline]
pub fn into_char_string(self) -> CharString {
self.try_into_char_string().unwrap_with_msg()
}
#[inline]
pub fn try_into_char_string(mut self) -> Result<CharString, ReserveError> {
self.0.make_growable()?;
Ok(CharString::from_repr(mem::replace(&mut self.0, Repr::new())))
}
pub(crate) fn from_repr(repr: Repr) -> Self {
debug_assert!(!repr.is_growable_heap_buffer());
Self(repr)
}
}
impl Clone for CharStr {
#[inline]
fn clone(&self) -> Self {
Self(self.0.make_shallow_clone())
}
#[inline]
fn clone_from(&mut self, source: &Self) {
self.0.replace_inner(source.0.make_shallow_clone());
}
}
impl Drop for CharStr {
#[inline]
fn drop(&mut self) {
unsafe { self.0.release_for_drop() };
}
}
unsafe impl Send for CharStr {}
unsafe impl Sync for CharStr {}
impl Default for CharStr {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl Deref for CharStr {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl fmt::Debug for CharStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_str(), f)
}
}
impl fmt::Display for CharStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.as_str(), f)
}
}
impl AsRef<str> for CharStr {
#[inline]
fn as_ref(&self) -> &str {
self.as_str()
}
}
#[cfg(feature = "std")]
impl AsRef<OsStr> for CharStr {
#[inline]
fn as_ref(&self) -> &OsStr {
OsStr::new(self.as_str())
}
}
impl AsRef<[u8]> for CharStr {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl Borrow<str> for CharStr {
#[inline]
fn borrow(&self) -> &str {
self.as_str()
}
}
impl Eq for CharStr {}
impl PartialEq for CharStr {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0.content_eq(&other.0)
}
}
impl PartialEq<str> for CharStr {
#[inline]
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<CharStr> for str {
#[inline]
fn eq(&self, other: &CharStr) -> bool {
self == other.as_str()
}
}
impl PartialEq<&str> for CharStr {
#[inline]
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl PartialEq<CharStr> for &str {
#[inline]
fn eq(&self, other: &CharStr) -> bool {
*self == other.as_str()
}
}
impl PartialEq<String> for CharStr {
#[inline]
fn eq(&self, other: &String) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<CharStr> for String {
#[inline]
fn eq(&self, other: &CharStr) -> bool {
self.as_str() == other.as_str()
}
}
impl PartialEq<CharString> for CharStr {
#[inline]
fn eq(&self, other: &CharString) -> bool {
self.0.content_eq(&other.0)
}
}
impl PartialEq<CharStr> for CharString {
#[inline]
fn eq(&self, other: &CharStr) -> bool {
self.0.content_eq(&other.0)
}
}
impl Ord for CharStr {
#[inline]
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.0.content_cmp(&other.0)
}
}
impl PartialOrd for CharStr {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Hash for CharStr {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_str().hash(state);
}
}
impl From<char> for CharStr {
#[inline]
fn from(value: char) -> Self {
Self(Repr::from_char(value))
}
}
impl From<&str> for CharStr {
#[inline]
#[track_caller]
fn from(value: &str) -> Self {
Self::try_from_str(value).unwrap_with_msg()
}
}
impl From<String> for CharStr {
#[inline]
#[track_caller]
fn from(value: String) -> Self {
Self::from(value.as_str())
}
}
impl From<&String> for CharStr {
#[inline]
#[track_caller]
fn from(value: &String) -> Self {
Self::from(value.as_str())
}
}
impl From<Cow<'_, str>> for CharStr {
fn from(value: Cow<'_, str>) -> Self {
Self::from(value.as_ref())
}
}
impl From<Box<str>> for CharStr {
#[inline]
#[track_caller]
fn from(value: Box<str>) -> Self {
Self::from(value.as_ref())
}
}
impl From<&CharStr> for CharStr {
#[inline]
fn from(value: &CharStr) -> Self {
value.clone()
}
}
impl From<CharStr> for String {
#[inline]
fn from(value: CharStr) -> Self {
value.as_str().into()
}
}
impl From<&CharStr> for String {
#[inline]
fn from(value: &CharStr) -> Self {
value.as_str().into()
}
}
impl From<CharString> for CharStr {
#[inline]
fn from(value: CharString) -> Self {
value.freeze()
}
}
impl From<CharStr> for CharString {
#[inline]
fn from(value: CharStr) -> Self {
value.into_char_string()
}
}
impl FromStr for CharStr {
type Err = ReserveError;
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::try_from_str(s)
}
}
impl FromIterator<char> for CharStr {
fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
CharString::from_iter(iter).freeze()
}
}
impl<'a> FromIterator<&'a char> for CharStr {
fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
iter.into_iter().copied().collect()
}
}