use std::collections::HashMap;
use std::fmt;
use yog_sync::{OnceLock, RwLock};
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Atom(u32);
#[derive(Clone, Copy)]
pub struct Table {
pub intern: fn(&str) -> u32,
pub name: fn(u32) -> Option<&'static str>,
}
static TABLE: OnceLock<Table> = OnceLock::new();
pub fn install(table: Table) -> bool {
TABLE.set(table).is_ok()
}
fn table() -> &'static Table {
TABLE.get_or_init(|| Table {
intern: local::intern,
name: local::name,
})
}
impl Atom {
pub fn new(name: &str) -> Atom {
Atom((table().intern)(name))
}
pub fn from_number(n: u32) -> Option<Atom> {
(table().name)(n).map(|_| Atom(n))
}
pub fn number(self) -> u32 {
self.0
}
pub fn as_str(self) -> &'static str {
(table().name)(self.0).unwrap_or_default()
}
}
impl fmt::Debug for Atom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Atom({:?})", self.as_str())
}
}
impl fmt::Display for Atom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl From<&str> for Atom {
fn from(name: &str) -> Atom {
Atom::new(name)
}
}
impl From<String> for Atom {
fn from(name: String) -> Atom {
Atom::new(&name)
}
}
impl From<&String> for Atom {
fn from(name: &String) -> Atom {
Atom::new(name)
}
}
impl PartialEq<str> for Atom {
fn eq(&self, other: &str) -> bool {
self.as_str() == other
}
}
impl PartialEq<&str> for Atom {
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl PartialEq<String> for Atom {
fn eq(&self, other: &String) -> bool {
self.as_str() == other
}
}
impl PartialEq<Atom> for String {
fn eq(&self, other: &Atom) -> bool {
self == other.as_str()
}
}
impl std::ops::Deref for Atom {
type Target = str;
fn deref(&self) -> &str {
self.as_str()
}
}
impl Default for Atom {
fn default() -> Atom {
Atom::new("")
}
}
pub mod local;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_name_is_one_atom() {
let a = Atom::new("test:atom_a");
assert_eq!(a, Atom::new("test:atom_a"));
assert_ne!(a, Atom::new("test:atom_b"));
assert_eq!(Atom::from_number(a.number()), Some(a));
assert_eq!(Atom::from_number(u32::MAX), None);
assert_eq!(a.to_string(), "test:atom_a");
}
}