#![allow(clippy::unreadable_literal)]
#[doc(hidden)]
pub extern crate hstr;
#[doc(hidden)]
pub extern crate once_cell;
use std::{
borrow::Cow,
cell::UnsafeCell,
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, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "rkyv-impl", derive(rkyv::bytecheck::CheckBytes))]
#[cfg_attr(feature = "rkyv-impl", repr(C))]
pub struct Atom(hstr::Atom);
#[cfg(feature = "arbitrary")]
#[cfg_attr(docsrs, doc(cfg(feature = "arbitrary")))]
impl<'a> arbitrary::Arbitrary<'a> for Atom {
fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
let sym = u.arbitrary::<String>()?;
if sym.is_empty() {
return Err(arbitrary::Error::NotEnoughData);
}
Ok(Self(hstr::Atom::from(sym)))
}
}
fn _asserts() {
fn _assert_send<T: Send>() {}
fn _assert_sync<T: Sync>() {}
_assert_send::<Atom>();
_assert_sync::<Atom>();
}
impl Atom {
#[inline(always)]
pub fn new<S>(s: S) -> Self
where
hstr::Atom: From<S>,
{
Atom(hstr::Atom::from(s))
}
#[inline]
pub fn to_ascii_lowercase(&self) -> Self {
Self(self.0.to_ascii_lowercase())
}
#[inline]
pub fn as_str(&self) -> &str {
&self.0
}
}
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)
}
}
};
}
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!(Box<str>);
impl_from!(String);
impl_from!(Cow<'_, str>);
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.as_str().cmp(other.as_str())
}
}
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) => {{
$crate::Atom::new($crate::hstr::atom!($s))
}};
}
#[macro_export]
macro_rules! lazy_atom {
($s:tt) => {{
$crate::Atom::new($crate::hstr::atom!($s))
}};
}
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))
}
}
#[derive(Default)]
pub struct AtomStoreCell(UnsafeCell<AtomStore>);
impl AtomStoreCell {
#[inline]
pub fn atom<'a>(&self, s: impl Into<Cow<'a, str>>) -> Atom {
let s: Cow<'a, str> = s.into();
unsafe { (*self.0.get()).atom(s) }
}
}