#![allow(clippy::unreadable_literal)]
#[doc(hidden)]
pub extern crate once_cell;
use std::{
borrow::{Borrow, Cow},
fmt::{self, Display, Formatter},
hash::Hash,
ops::Deref,
rc::Rc,
sync::Arc,
};
use rustc_hash::FxHashSet;
use serde::Serializer;
include!(concat!(env!("OUT_DIR"), "/js_word.rs"));
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(
feature = "rkyv",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)]
#[cfg_attr(feature = "rkyv", archive_attr(repr(C), derive(bytecheck::CheckBytes)))]
pub struct Atom(Arc<str>);
impl Atom {
pub fn new<S>(s: S) -> Self
where
Arc<str>: From<S>,
{
Self(s.into())
}
}
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.0 == **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.0 == other
}
}
impl_eq!(&'_ str);
impl_eq!(Box<str>);
impl_eq!(Arc<str>);
impl_eq!(Rc<str>);
impl_eq!(Cow<'_, str>);
impl_eq!(String);
impl_eq!(JsWord);
impl_from!(&'_ str);
impl_from!(Box<str>);
impl_from!(Arc<str>);
impl_from!(Cow<'_, str>);
impl_from!(String);
impl From<JsWord> for Atom {
fn from(v: JsWord) -> Self {
Self::new(&*v)
}
}
impl AsRef<str> for Atom {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Borrow<str> for Atom {
fn borrow(&self) -> &str {
&self.0
}
}
impl fmt::Debug for Atom {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&*self.0, f)
}
}
impl Display for Atom {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.0, f)
}
}
impl Default for Atom {
fn default() -> Self {
atom!("")
}
}
#[derive(Debug, Default, Clone)]
pub struct AtomGenerator {
inner: FxHashSet<Atom>,
}
impl AtomGenerator {
pub fn intern<S>(&mut self, s: S) -> Atom
where
Arc<str>: From<S>,
S: Eq + Hash,
S: AsRef<str>,
{
if let Some(v) = self.inner.get(s.as_ref()).cloned() {
return v;
}
let new = Atom::new(s);
self.inner.insert(new.clone());
new
}
}
impl serde::ser::Serialize for Atom {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.0)
}
}
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:literal) => {{
static CACHE: $crate::once_cell::sync::Lazy<$crate::Atom> =
$crate::once_cell::sync::Lazy::new(|| $crate::Atom::new($s));
$crate::Atom::clone(&*CACHE)
}};
}
#[test]
fn _assert() {
let mut g = AtomGenerator::default();
g.intern("str");
g.intern(String::new());
}
impl PartialEq<Atom> for str {
fn eq(&self, other: &Atom) -> bool {
*self == **other
}
}