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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
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)] // for doc
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;
}

/// 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: Internable> {
  data: Arc<T>,
  interner: Arc<TypedInterner<T>>,
}
impl<T: Internable> 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: Internable> 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: Internable> 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: 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)
  }
}