use core::fmt;
use core::hash::{Hash, Hasher};
use core::ops::Deref;
#[cfg(feature = "alloc")]
use alloc::borrow::{Cow, ToOwned};
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
#[cfg(feature = "alloc")]
use alloc::rc::Rc;
#[cfg(feature = "alloc")]
use alloc::string::String;
use crate::lang::Lang;
use crate::tokens::{FormatInto, Item, Tokens};
#[derive(Clone)]
enum ItemStrKind {
#[cfg(feature = "alloc")]
Box(Box<str>),
Static(&'static str),
}
#[derive(Clone)]
pub struct ItemStr {
kind: ItemStrKind,
}
impl ItemStr {
#[inline]
const fn new(kind: ItemStrKind) -> Self {
Self { kind }
}
pub const fn static_(s: &'static str) -> Self {
Self::new(ItemStrKind::Static(s))
}
}
impl<L> FormatInto<L> for ItemStr
where
L: Lang,
{
#[inline]
fn format_into(self, tokens: &mut Tokens<L>) {
tokens.append(Item::literal(self));
}
}
impl<L> FormatInto<L> for &ItemStr
where
L: Lang,
{
#[inline]
fn format_into(self, tokens: &mut Tokens<L>) {
tokens.append(Item::literal(self.clone()));
}
}
impl AsRef<str> for ItemStr {
#[inline]
fn as_ref(&self) -> &str {
match &self.kind {
#[cfg(feature = "alloc")]
ItemStrKind::Box(b) => b,
ItemStrKind::Static(s) => s,
}
}
}
impl Deref for ItemStr {
type Target = str;
fn deref(&self) -> &str {
match &self.kind {
#[cfg(feature = "alloc")]
ItemStrKind::Box(b) => b,
ItemStrKind::Static(s) => s,
}
}
}
#[cfg(feature = "alloc")]
impl From<Box<str>> for ItemStr {
#[inline]
fn from(value: Box<str>) -> Self {
Self::new(ItemStrKind::Box(value))
}
}
impl<'a> From<&'a ItemStr> for ItemStr {
#[inline]
fn from(value: &'a ItemStr) -> Self {
value.clone()
}
}
#[cfg(feature = "alloc")]
impl<'a> From<&'a String> for ItemStr {
#[inline]
fn from(value: &'a String) -> Self {
value.clone().into()
}
}
#[cfg(feature = "alloc")]
impl From<String> for ItemStr {
#[inline]
fn from(value: String) -> Self {
Self::new(ItemStrKind::Box(value.into_boxed_str()))
}
}
#[cfg(feature = "alloc")]
impl<'a> From<&'a str> for ItemStr {
#[inline]
fn from(value: &'a str) -> Self {
Self::new(ItemStrKind::Box(value.to_owned().into_boxed_str()))
}
}
#[cfg(feature = "alloc")]
impl<'a, 'b> From<&'b &'a str> for ItemStr {
#[inline]
fn from(value: &'b &'a str) -> Self {
Self::new(ItemStrKind::Box((*value).to_owned().into_boxed_str()))
}
}
#[cfg(feature = "alloc")]
impl<'a> From<Cow<'a, str>> for ItemStr {
#[inline]
fn from(value: Cow<'a, str>) -> Self {
Self::new(ItemStrKind::Box(match value {
Cow::Owned(string) => string.into_boxed_str(),
Cow::Borrowed(string) => string.to_owned().into_boxed_str(),
}))
}
}
#[cfg(feature = "alloc")]
impl<'a, 'b> From<&'b Cow<'a, str>> for ItemStr {
#[inline]
fn from(value: &'b Cow<'a, str>) -> Self {
Self::new(ItemStrKind::Box(match value {
Cow::Owned(string) => string.clone().into_boxed_str(),
Cow::Borrowed(string) => (*string).to_owned().into_boxed_str(),
}))
}
}
#[cfg(feature = "alloc")]
impl From<Rc<String>> for ItemStr {
#[inline]
fn from(value: Rc<String>) -> Self {
Self::new(ItemStrKind::Box((*value).clone().into()))
}
}
impl fmt::Debug for ItemStr {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.as_ref().fmt(fmt)
}
}
impl fmt::Display for ItemStr {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.as_ref().fmt(fmt)
}
}
impl PartialEq for ItemStr {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_ref() == other.as_ref()
}
}
impl Eq for ItemStr {}
impl PartialOrd for ItemStr {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for ItemStr {
#[inline]
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
self.as_ref().cmp(other.as_ref())
}
}
impl Hash for ItemStr {
#[inline]
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.as_ref().hash(state);
}
}