1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
use std::borrow::Borrow;
use std::cmp::PartialEq;
use std::fmt::{Debug, Display};
use std::hash::Hash;
use std::num::NonZeroUsize;
use std::ops::Deref;
use std::sync::{Arc, Weak};

#[allow(unused)] // for doc
use super::interner::Interner;
use super::typed_interner::TypedInterner;
use crate::global::{self, ev};

/// A shared instance. Equality comparison costs two pointer comparisons.
/// Ordering is by pointer value.
///
/// # Panics
///
/// If an interner was manually constructed, tokens from different interners
/// cannot be compared and attempting to do so causes a panic.
///
/// Since a given [Interner] uses a single [TypedInterner] for each type, this
/// is only possible if an [Interner] or [TypedInterner] was constructed besides
/// the singleton.
#[derive(Clone)]
pub struct Tok<T: Eq + Hash + Clone + Send + Sync + 'static> {
  data: Arc<T>,
  interner: Arc<TypedInterner<T>>,
}
impl<T: Eq + Hash + Clone + Send + Sync + 'static> Tok<T> {
  /// Create a new token. Used exclusively by the interner
  #[must_use]
  pub(crate) fn new(data: Arc<T>, interner: Arc<TypedInterner<T>>) -> Self {
    Self { data, interner }
  }
  /// The pointer value of the token. If this is equal, equality comparison
  /// succeeds.
  #[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")
  }
  /// The pointer value of the interner. If this is different, comparison
  /// panics.
  pub fn interner_id(&self) -> NonZeroUsize {
    ((self.interner.as_ref() as *const _ as usize).try_into())
      .expect("Pointer can always be cast to nonzero")
  }
  /// Cast into usize
  #[must_use]
  pub fn usize(&self) -> usize { self.id().into() }
  /// Panic if the two tokens weren't created with the same interner
  pub fn assert_comparable(&self, other: &Self) {
    assert_eq!(
      self.interner_id(),
      other.interner_id(),
      "Tokens must come from the same interner"
    );
  }
  /// Get the typed interner that owns this token.
  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: Eq + Hash + Clone + Send + Sync + 'static> Tok<Vec<Tok<T>>> {
  /// Extern all elements of the vector in a new vector. If the vector itself
  /// isn't interned, use [ev]
  pub fn ev(&self) -> Vec<T> { ev(&self[..]) }
}

impl<T: Eq + Hash + Clone + Send + Sync + 'static> Tok<Vec<Tok<T>>> {
  /// Add a suffix to the interned vector
  pub fn append(&self, suffix: impl IntoIterator<Item = Tok<T>>) -> Self {
    let i = self.interner();
    i.i(&self.iter().cloned().chain(suffix).collect::<Vec<_>>())
  }

  /// Add a prefix to the interned vector
  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: Eq + Hash + Clone + Send + Sync + 'static> Deref for Tok<T> {
  type Target = T;

  fn deref(&self) -> &Self::Target { self.data.as_ref() }
}

impl<T: Eq + Hash + Clone + Send + Sync + Debug + 'static> Debug for Tok<T> {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "Token({} -> {:?})", self.id(), self.data.as_ref())
  }
}

impl<T: Eq + Hash + Clone + Send + Sync + Display + 'static> Display
  for Tok<T>
{
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "{}", **self)
  }
}

impl<T: Eq + Hash + Clone + Send + Sync + 'static> Eq for Tok<T> {}
impl<T: Eq + Hash + Clone + Send + Sync + 'static> PartialEq for Tok<T> {
  fn eq(&self, other: &Self) -> bool {
    self.assert_comparable(other);
    self.id() == other.id()
  }
}

impl<T: Eq + Hash + Clone + Send + Sync + 'static> Ord for Tok<T> {
  fn cmp(&self, other: &Self) -> std::cmp::Ordering {
    self.assert_comparable(other);
    self.id().cmp(&other.id())
  }
}
impl<T: Eq + Hash + Clone + Send + Sync + 'static> PartialOrd for Tok<T> {
  fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
    Some(self.cmp(other))
  }
}

impl<T: Eq + Hash + Clone + Send + Sync + 'static> Hash for Tok<T> {
  fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
    state.write_usize(self.usize())
  }
}

pub struct WeakTok<T: Eq + Hash + Clone + Send + Sync + 'static> {
  data: Weak<T>,
  interner: Weak<TypedInterner<T>>,
}
impl<T: Eq + Hash + Clone + Send + Sync + 'static> 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()? })
  }
}