use alloc::borrow::{Cow, Borrow};
use alloc::{string::String, boxed::Box};
use core::ops::Deref;
use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
use core::fmt;
use crate::UncasedStr;
#[cfg_attr(nightly, doc(cfg(feature = "alloc")))]
#[derive(Clone, Debug)]
pub struct Uncased<'s> {
#[doc(hidden)]
pub string: Cow<'s, str>
}
impl<'s> Uncased<'s> {
#[inline(always)]
pub fn new<S: Into<Cow<'s, str>>>(string: S) -> Uncased<'s> {
Uncased { string: string.into() }
}
#[inline(always)]
pub const fn from_borrowed(string: &'s str) -> Uncased<'s> {
Uncased { string: Cow::Borrowed(string) }
}
#[inline(always)]
pub const fn from_owned(string: String) -> Uncased<'s> {
Uncased { string: Cow::Owned(string) }
}
#[inline(always)]
pub fn as_uncased_str(&self) -> &UncasedStr {
self.as_ref()
}
#[inline(always)]
pub fn into_string(self) -> String {
self.string.into_owned()
}
#[inline(always)]
pub fn into_owned(self) -> Uncased<'static> {
match self.string {
Cow::Owned(string) => Uncased::new(string),
Cow::Borrowed(str) => Uncased::new(String::from(str)),
}
}
#[inline(always)]
pub fn into_boxed_uncased(self) -> Box<UncasedStr> {
unsafe {
let raw_str = Box::into_raw(self.string.into_owned().into_boxed_str());
Box::from_raw(raw_str as *mut UncasedStr)
}
}
#[doc(hidden)]
#[inline(always)]
pub fn into_cow(self) -> Cow<'s, str> {
self.string
}
}
impl Deref for Uncased<'_> {
type Target = UncasedStr;
#[inline(always)]
fn deref(&self) -> &UncasedStr {
UncasedStr::new(self.string.borrow())
}
}
impl AsRef<UncasedStr> for Uncased<'_> {
#[inline(always)]
fn as_ref(&self) -> &UncasedStr {
UncasedStr::new(self.string.borrow())
}
}
impl AsRef<str> for Uncased<'_> {
#[inline(always)]
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl AsRef<[u8]> for Uncased<'_> {
#[inline(always)]
fn as_ref(&self) -> &[u8] {
self.as_str().as_bytes()
}
}
impl Borrow<UncasedStr> for Uncased<'_> {
#[inline(always)]
fn borrow(&self) -> &UncasedStr {
self.as_str().into()
}
}
impl<'s, 'c: 's> From<&'c UncasedStr> for Uncased<'s> {
#[inline(always)]
fn from(string: &'c UncasedStr) -> Self {
Uncased::new(string.as_str())
}
}
impl<'s, 'c: 's> From<&'c str> for Uncased<'s> {
#[inline(always)]
fn from(string: &'c str) -> Self {
Uncased::new(string)
}
}
impl From<String> for Uncased<'static> {
#[inline(always)]
fn from(string: String) -> Self {
Uncased::new(string)
}
}
impl<'s, 'c: 's> From<Cow<'c, str>> for Uncased<'s> {
#[inline(always)]
fn from(string: Cow<'c, str>) -> Self {
Uncased::new(string)
}
}
impl fmt::Display for Uncased<'_> {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.string.fmt(f)
}
}
macro_rules! impl_partial_eq {
($other:ty $([$o_i:ident])? = $this:ty $([$t_i:ident])?) => (
impl PartialEq<$other> for $this {
#[inline(always)]
fn eq(&self, other: &$other) -> bool {
self $(.$t_i())? .eq(other $(.$o_i())?)
}
}
)
}
impl_partial_eq!(Uncased<'_> [as_uncased_str] = Uncased<'_> [as_uncased_str]);
impl_partial_eq!(str = Uncased<'_> [as_uncased_str]);
impl_partial_eq!(Uncased<'_> [as_uncased_str] = str);
impl_partial_eq!(&str = Uncased<'_> [as_uncased_str]);
impl_partial_eq!(Uncased<'_> [as_uncased_str] = &str);
impl_partial_eq!(String [as_str] = Uncased<'_> [as_uncased_str]);
impl_partial_eq!(Uncased<'_> [as_uncased_str] = String [as_str]);
impl_partial_eq!(String [as_str] = &Uncased<'_> [as_uncased_str]);
impl_partial_eq!(&Uncased<'_> [as_uncased_str] = String [as_str]);
macro_rules! impl_partial_ord {
($other:ty $([$o_i:ident])? >< $this:ty $([$t_i:ident])?) => (
impl PartialOrd<$other> for $this {
#[inline(always)]
fn partial_cmp(&self, other: &$other) -> Option<Ordering> {
let this: &UncasedStr = self$(.$t_i())?.into();
let other: &UncasedStr = other$(.$o_i())?.into();
this.partial_cmp(other)
}
}
)
}
impl Ord for Uncased<'_> {
fn cmp(&self, other: &Self) -> Ordering {
self.as_uncased_str().cmp(other.as_uncased_str())
}
}
impl_partial_ord!(Uncased<'_> [as_uncased_str] >< Uncased<'_> [as_uncased_str]);
impl_partial_ord!(str >< Uncased<'_> [as_uncased_str]);
impl_partial_ord!(Uncased<'_> [as_uncased_str] >< str);
impl_partial_ord!(String [as_str] >< Uncased<'_> [as_uncased_str]);
impl_partial_ord!(Uncased<'_> [as_uncased_str] >< String [as_str]);
impl_partial_ord!(String [as_str] >< &Uncased<'_> [as_uncased_str]);
impl_partial_ord!(&Uncased<'_> [as_uncased_str] >< String [as_str]);
impl Eq for Uncased<'_> { }
impl Hash for Uncased<'_> {
#[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) {
self.as_uncased_str().hash(hasher)
}
}