use std::ops::Deref;
use lightningcss::values::string::CowArcStr;
use oxvg_parse::error::Error;
#[cfg(feature = "markup5ever")]
use tendril::SliceExt;
#[derive(Debug, Clone)]
pub enum Atom<'input> {
Static(&'static str),
Cow(CowArcStr<'input>),
#[cfg(feature = "markup5ever")]
NS(string_cache::Atom<xml5ever::NamespaceStaticSet>),
#[cfg(feature = "markup5ever")]
Prefix(string_cache::Atom<xml5ever::PrefixStaticSet>),
#[cfg(feature = "markup5ever")]
Local(string_cache::Atom<xml5ever::LocalNameStaticSet>),
#[cfg(feature = "markup5ever")]
Tendril(tendril::StrTendril),
}
impl Atom<'_> {
pub fn into_owned<'any>(self) -> Atom<'any>
where
'static: 'any,
{
match self {
Self::Static(str) => str.into(),
Self::Cow(cow) => cow.to_string().into(),
#[cfg(feature = "markup5ever")]
Self::NS(ns) => ns.into(),
#[cfg(feature = "markup5ever")]
Self::Prefix(prefix) => prefix.into(),
#[cfg(feature = "markup5ever")]
Self::Local(local) => local.into(),
#[cfg(feature = "markup5ever")]
Self::Tendril(tendril) => tendril.into(),
}
}
}
impl Default for Atom<'_> {
fn default() -> Self {
Self::Static("")
}
}
impl std::hash::Hash for Atom<'_> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.as_str().hash(state);
}
}
impl Deref for Atom<'_> {
type Target = str;
fn deref(&self) -> &Self::Target {
match self {
Self::Static(str) => str,
Self::Cow(str) => str,
#[cfg(feature = "markup5ever")]
Self::NS(str) => str,
#[cfg(feature = "markup5ever")]
Self::Prefix(str) => str,
#[cfg(feature = "markup5ever")]
Self::Local(str) => str,
#[cfg(feature = "markup5ever")]
Self::Tendril(str) => str,
}
}
}
impl Eq for Atom<'_> {}
impl PartialEq for Atom<'_> {
fn eq(&self, other: &Self) -> bool {
**self == **other
}
}
impl Ord for Atom<'_> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl PartialOrd for Atom<'_> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<'input> From<&'input str> for Atom<'input> {
fn from(value: &'input str) -> Self {
Self::Cow(value.into())
}
}
impl From<String> for Atom<'static> {
fn from(value: String) -> Self {
Self::Cow(value.into())
}
}
impl<'input> From<CowArcStr<'input>> for Atom<'input> {
fn from(value: CowArcStr<'input>) -> Self {
Self::Cow(value)
}
}
#[cfg(feature = "parse")]
impl<'input> oxvg_parse::Parse<'input> for Atom<'input> {
fn parse(input: &mut oxvg_parse::Parser<'input>) -> Result<Self, Error<'input>> {
Ok(input.take_slice().into())
}
fn parse_string(input: &'input str) -> Result<Self, Error<'input>> {
Ok(input.into())
}
}
impl std::fmt::Display for Atom<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.deref().fmt(f)
}
}
#[cfg(feature = "serialize")]
impl oxvg_serialize::ToValue for Atom<'_> {
fn write_value<W>(
&self,
dest: &mut oxvg_serialize::Printer<W>,
) -> Result<(), oxvg_serialize::error::PrinterError>
where
W: std::fmt::Write,
{
dest.write_str(self)
}
}
#[cfg(feature = "markup5ever")]
impl From<string_cache::Atom<xml5ever::NamespaceStaticSet>> for Atom<'static> {
fn from(value: string_cache::Atom<xml5ever::NamespaceStaticSet>) -> Self {
Self::NS(value)
}
}
#[cfg(feature = "markup5ever")]
impl From<string_cache::Atom<xml5ever::PrefixStaticSet>> for Atom<'static> {
fn from(value: string_cache::Atom<xml5ever::PrefixStaticSet>) -> Self {
Self::Prefix(value)
}
}
#[cfg(feature = "markup5ever")]
impl From<string_cache::Atom<xml5ever::LocalNameStaticSet>> for Atom<'static> {
fn from(value: string_cache::Atom<xml5ever::LocalNameStaticSet>) -> Self {
Self::Local(value)
}
}
#[cfg(feature = "markup5ever")]
impl From<tendril::StrTendril> for Atom<'static> {
fn from(value: tendril::StrTendril) -> Self {
Self::Tendril(value)
}
}
impl Atom<'_> {
pub fn push_str(&mut self, str: &str) {
fn to_cow<'input>(a: &str, b: &str) -> Atom<'input> {
let mut owned = String::with_capacity(a.len() + b.len());
owned.push_str(a);
owned.push_str(b);
owned.into()
}
#[cfg(feature = "markup5ever")]
fn from_tendril<'input>(mut a: tendril::StrTendril, b: &str) -> Atom<'input> {
a.push_slice(b);
a.into()
}
match self {
Self::Cow(cow) => *self = to_cow(cow, str),
Self::Static(string) => *self = to_cow(string, str),
#[cfg(feature = "markup5ever")]
Self::NS(ns) => *self = from_tendril(ns.to_tendril(), str),
#[cfg(feature = "markup5ever")]
Self::Prefix(prefix) => *self = from_tendril(prefix.to_tendril(), str),
#[cfg(feature = "markup5ever")]
Self::Local(local) => *self = from_tendril(local.to_tendril(), str),
#[cfg(feature = "markup5ever")]
Self::Tendril(tendril) => tendril.push_slice(str),
}
}
pub fn as_str(&self) -> &str {
self
}
}