#![allow(clippy::unreadable_literal)]
#[doc(hidden)]
pub extern crate once_cell;
use std::{
borrow::Cow,
fmt::{self, Display, Formatter},
hash::Hash,
ops::Deref,
rc::Rc,
};
use once_cell::sync::Lazy;
use serde::Serializer;
pub use self::{atom as js_word, Atom as JsWord};
#[derive(Clone, Default)]
#[cfg_attr(feature = "rkyv-impl", derive(rkyv::bytecheck::CheckBytes))]
#[cfg_attr(feature = "rkyv-impl", repr(C))]
pub struct Atom(hstr::Atom);
unsafe impl Sync for Atom {}
impl Atom {
pub fn new<'i, S>(s: S) -> Self
where
S: Into<Cow<'i, str>>,
{
Atom(hstr::Atom::from(s.into()))
}
#[inline]
pub fn to_ascii_lowercase(&self) -> Self {
Self(self.0.to_ascii_lowercase())
}
}
impl Deref for Atom {
type Target = str;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
macro_rules! impl_eq {
($T:ty) => {
impl PartialEq<$T> for Atom {
fn eq(&self, other: &$T) -> bool {
&**self == &**other
}
}
};
}
macro_rules! impl_from {
($T:ty) => {
impl From<$T> for Atom {
fn from(s: $T) -> Self {
Atom::new(s)
}
}
};
}
macro_rules! impl_from_deref {
($T:ty) => {
impl From<$T> for Atom {
fn from(s: $T) -> Self {
Atom::new(&*s)
}
}
};
}
impl PartialEq<str> for Atom {
fn eq(&self, other: &str) -> bool {
&**self == other
}
}
impl_eq!(&'_ str);
impl_eq!(Box<str>);
impl_eq!(std::sync::Arc<str>);
impl_eq!(Rc<str>);
impl_eq!(Cow<'_, str>);
impl_eq!(String);
impl_from!(&'_ str);
impl_from_deref!(Box<str>);
impl_from_deref!(Cow<'_, str>);
impl_from!(String);
impl AsRef<str> for Atom {
fn as_ref(&self) -> &str {
self
}
}
impl fmt::Debug for Atom {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&**self, f)
}
}
impl Display for Atom {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&**self, f)
}
}
impl PartialOrd for Atom {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Atom {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
(**self).cmp(&**other)
}
}
impl PartialEq for Atom {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl Eq for Atom {}
impl Hash for Atom {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state)
}
}
impl serde::ser::Serialize for Atom {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(self)
}
}
impl<'de> serde::de::Deserialize<'de> for Atom {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
String::deserialize(deserializer).map(Self::new)
}
}
#[macro_export]
macro_rules! atom {
($s:tt) => {{
static CACHE: $crate::CahcedAtom = $crate::CahcedAtom::new(|| $crate::Atom::new($s));
$crate::Atom::clone(&*CACHE)
}};
}
#[macro_export]
macro_rules! lazy_atom {
($s:tt) => {{
static CACHE: $crate::CahcedAtom = $crate::CahcedAtom::new(|| $crate::Atom::new($s));
$crate::Atom::clone(&*CACHE)
}};
}
impl PartialEq<Atom> for str {
fn eq(&self, other: &Atom) -> bool {
*self == **other
}
}
#[cfg(feature = "rkyv-impl")]
impl rkyv::Archive for Atom {
type Archived = rkyv::string::ArchivedString;
type Resolver = rkyv::string::StringResolver;
#[allow(clippy::unit_arg)]
unsafe fn resolve(&self, pos: usize, resolver: Self::Resolver, out: *mut Self::Archived) {
rkyv::string::ArchivedString::resolve_from_str(self, pos, resolver, out)
}
}
#[cfg(feature = "rkyv-impl")]
impl<S: rkyv::ser::Serializer + ?Sized> rkyv::Serialize<S> for Atom {
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
String::serialize(&self.to_string(), serializer)
}
}
#[cfg(feature = "rkyv-impl")]
impl<D> rkyv::Deserialize<Atom, D> for rkyv::string::ArchivedString
where
D: ?Sized + rkyv::Fallible,
{
fn deserialize(&self, deserializer: &mut D) -> Result<Atom, <D as rkyv::Fallible>::Error> {
let s: String = self.deserialize(deserializer)?;
Ok(Atom::new(s))
}
}
#[doc(hidden)]
pub type CahcedAtom = Lazy<Atom>;
pub type StaticString = Atom;
#[derive(Default)]
pub struct AtomStore(hstr::AtomStore);
impl AtomStore {
#[inline]
pub fn atom<'a>(&mut self, s: impl Into<Cow<'a, str>>) -> Atom {
Atom(self.0.atom(s))
}
}