use std::borrow::Borrow;
use std::hash::{Hash, Hasher};
use std::num::NonZeroUsize;
use std::ops::Deref;
use std::sync::{Arc, Weak};
use std::{cmp, fmt};
use trait_set::trait_set;
#[allow(unused)] use super::interner::Interner;
use super::typed_interner::TypedInterner;
use crate::global::{self, ev};
trait_set! {
pub trait Internable = Eq + Hash + Clone + Send + Sync + 'static;
}
#[derive(Clone)]
pub struct Tok<T: Internable> {
data: Arc<T>,
interner: Arc<TypedInterner<T>>,
}
impl<T: Internable> Tok<T> {
#[must_use]
pub(crate) fn new(data: Arc<T>, interner: Arc<TypedInterner<T>>) -> Self {
Self { data, interner }
}
#[must_use]
pub fn id(&self) -> NonZeroUsize {
((self.data.as_ref() as *const T as usize).try_into())
.expect("Pointer can always be cast to nonzero")
}
pub fn interner_id(&self) -> NonZeroUsize {
((self.interner.as_ref() as *const _ as usize).try_into())
.expect("Pointer can always be cast to nonzero")
}
#[must_use]
pub fn usize(&self) -> usize { self.id().into() }
pub fn assert_comparable(&self, other: &Self) {
assert_eq!(self.interner_id(), other.interner_id(), "Tokens must come from the same interner");
}
pub fn interner(&self) -> Arc<TypedInterner<T>> { self.interner.clone() }
pub fn i<Q>(q: &Q) -> Self
where
Q: ?Sized + Eq + Hash + ToOwned<Owned = T>,
T: Borrow<Q>,
{
global::i(q)
}
}
impl<T: Internable> Tok<Vec<Tok<T>>> {
pub fn ev(&self) -> Vec<T> { ev(&self[..]) }
}
impl<T: Internable> Tok<Vec<Tok<T>>> {
pub fn append(&self, suffix: impl IntoIterator<Item = Tok<T>>) -> Self {
let i = self.interner();
i.i(&self.iter().cloned().chain(suffix).collect::<Vec<_>>())
}
pub fn prepend(&self, prefix: impl IntoIterator<Item = Tok<T>>) -> Self {
let i = self.interner();
i.i(&prefix.into_iter().chain(self.iter().cloned()).collect::<Vec<_>>())
}
}
impl<T: Internable + AsRef<U>, U: ?Sized> AsRef<U> for Tok<T> {
fn as_ref(&self) -> &U { self.data.as_ref().as_ref() }
}
impl<T: Internable> Borrow<T> for Tok<T> {
fn borrow(&self) -> &T { self.data.as_ref().borrow() }
}
impl<T: Internable> Deref for Tok<T> {
type Target = T;
fn deref(&self) -> &Self::Target { self.data.as_ref() }
}
impl<T: Internable + fmt::Debug> fmt::Debug for Tok<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Token({} -> {:?})", self.id(), self.data.as_ref())
}
}
impl<T: Internable + fmt::Display> fmt::Display for Tok<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", **self) }
}
impl<T: Internable> Eq for Tok<T> {}
impl<T: Internable> cmp::PartialEq for Tok<T> {
fn eq(&self, other: &Self) -> bool {
self.assert_comparable(other);
self.id() == other.id()
}
}
impl<T: Internable> cmp::Ord for Tok<T> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.assert_comparable(other);
self.id().cmp(&other.id())
}
}
impl<T: Internable> cmp::PartialOrd for Tok<T> {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { Some(self.cmp(other)) }
}
impl<T: Internable> Hash for Tok<T> {
fn hash<H: Hasher>(&self, state: &mut H) { state.write_usize(self.usize()) }
}
pub struct WeakTok<T: Internable> {
data: Weak<T>,
interner: Weak<TypedInterner<T>>,
}
impl<T: Internable> WeakTok<T> {
pub fn new(tok: &Tok<T>) -> Self {
Self { data: Arc::downgrade(&tok.data), interner: Arc::downgrade(&tok.interner) }
}
pub fn upgrade(&self) -> Option<Tok<T>> {
Some(Tok { data: self.data.upgrade()?, interner: self.interner.upgrade()? })
}
}
#[cfg(feature = "serde")]
impl<T: serde::Serialize + Internable> serde::Serialize for Tok<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.data.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'a, T: serde::Deserialize<'a> + Internable> serde::Deserialize<'a> for Tok<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'a>,
{
T::deserialize(deserializer).map(|t| crate::i(&t))
}
}
#[cfg(test)]
mod test {
use crate::{i, Tok};
#[test]
fn impls_asref() {
fn foo(_: impl AsRef<str>) {}
let t: Tok<String> = i("Hello World!");
foo(t)
}
}