Lightweight tagged data library.
1//! Types defining how tag data is stored.
2
3use crate::error::StorageError;
4use crate::label::DefaultLabel;
5use crate::label::Label;
6use std::fmt::Debug;
7use std::hash::BuildHasher;
8use std::marker::PhantomData;
9use std::ops::Deref;
10use std::ops::DerefMut;
11use std::sync::Arc;
12use std::sync::Mutex;
13use std::sync::MutexGuard;
14pub use string_interner::backend::Backend as InternerBackend;
15pub use string_interner::DefaultBackend;
16pub use string_interner::DefaultHashBuilder;
17pub use string_interner::DefaultSymbol;
18pub use string_interner::StringInterner;
19use string_interner::Symbol;
20
21/// Default interner, using the default backend, symbols, and hashing.
22pub type DefaultInterner = StringInterner<DefaultBackend<DefaultSymbol>, DefaultHashBuilder>;
23
24/// Stores the actual tag data.
25///
26/// A [`Storage`] is, essentially, a wrapper around a [`StringInterner`] that handles three
27/// things: 1) Ensuring the interner is always wrapped in an `Arc<Mutex<_>>`, 2) providing
28/// a convenient `lock` method and associated `StorageLockGuard` type to make the API for
29/// _using_ the interner more ergonomic, and 3) keying the storage on the "label" type associated
30/// with it, while enabling the underlying interners to be shared even if the labels are
31/// different.
32pub struct Storage<L = DefaultLabel, B = DefaultBackend<DefaultSymbol>, H = DefaultHashBuilder>(
33 Arc<Mutex<StringInterner<B, H>>>,
34 PhantomData<L>,
35)
36where
37 L: Label,
38 B: InternerBackend,
39 <B as InternerBackend>::Symbol: Symbol,
40 H: BuildHasher;
41
42impl<L, B, H> Storage<L, B, H>
43where
44 L: Label,
45 B: InternerBackend,
46 <B as InternerBackend>::Symbol: Symbol,
47 H: BuildHasher + Default,
48{
49 /// Make a [`Storage`] with a freshly-created [`StringInterner`].
50 pub fn fresh() -> Self {
51 Storage::unique(StringInterner::<B, H>::new())
52 }
53
54 /// Make a [`Storage`] with a freshly-created [`StringInterner`] with the specified capacity.
55 pub fn fresh_with_capacity(cap: usize) -> Self {
56 Storage::unique(StringInterner::<B, H>::with_capacity(cap))
57 }
58}
59
60impl<L, B, H> Storage<L, B, H>
61where
62 L: Label,
63 B: InternerBackend,
64 <B as InternerBackend>::Symbol: Symbol,
65 H: BuildHasher,
66{
67 /// Make a [`Storage`] with a freshly-created [`StringInterner`] with the specified hash builder.
68 pub fn fresh_with_hasher(hash_builder: H) -> Self {
69 Storage::unique(StringInterner::<B, H>::with_hasher(hash_builder))
70 }
71
72 /// Make a [`Storage`] with a freshly-created [`StringInterner`] with the specified capacity and hash builder.
73 pub fn fresh_with_capacity_and_hasher(cap: usize, hash_builder: H) -> Self {
74 Storage::unique(StringInterner::<B, H>::with_capacity_and_hasher(
75 cap,
76 hash_builder,
77 ))
78 }
79
80 /// Take ownership of a singular interner to produce a [`Storage`].
81 pub fn unique(interner: StringInterner<B, H>) -> Self {
82 Storage(Arc::new(Mutex::new(interner)), PhantomData)
83 }
84
85 /// Produce a [`Storage`] which may share its underlying interner.
86 pub fn shared(interner: &Arc<Mutex<StringInterner<B, H>>>) -> Self {
87 Storage(Arc::clone(interner), PhantomData)
88 }
89
90 /// Make a [`Storage`] by copying and sharing the underlying interner from the provided [`Storage`].
91 pub fn shallow_clone<L2>(&self) -> Storage<L2, B, H>
92 where
93 L2: Label,
94 {
95 Storage::shared(self)
96 }
97
98 /// Lock the [`Storage`]'s underlying [`StringInterner`].
99 pub fn lock(&self) -> Result<StorageLock<'_, L, B, H>, StorageError> {
100 self.0
101 .lock()
102 .map(|guard| StorageLock(guard, PhantomData))
103 .map_err(|_| StorageError::CouldNotLock)
104 }
105}
106
107impl<L, B, H> Storage<L, B, H>
108where
109 L: Label,
110 B: InternerBackend + Clone,
111 <B as InternerBackend>::Symbol: Symbol,
112 H: BuildHasher + Clone,
113{
114 /// Make a [`Storage`] by completely copying all data stored in the provided [`Storage`] into a fresh interner.
115 pub fn deep_clone<L2>(&self) -> Result<Storage<L2, B, H>, StorageError>
116 where
117 L2: Label,
118 {
119 Ok(Storage::unique(self.lock()?.clone()))
120 }
121}
122
123impl<L, B, H> Debug for Storage<L, B, H>
124where
125 L: Label,
126 B: InternerBackend + Debug,
127 <B as InternerBackend>::Symbol: Symbol + Debug,
128 H: BuildHasher,
129{
130 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
131 f.debug_struct("Storage").field("0", &self.0).finish()
132 }
133}
134
135impl Default for Storage<DefaultLabel, DefaultBackend<DefaultSymbol>, DefaultHashBuilder> {
136 fn default() -> Self {
137 Storage::unique(DefaultInterner::new())
138 }
139}
140
141impl<L, B, H> Deref for Storage<L, B, H>
142where
143 L: Label,
144 B: InternerBackend,
145 <B as InternerBackend>::Symbol: Symbol,
146 H: BuildHasher,
147{
148 type Target = Arc<Mutex<StringInterner<B, H>>>;
149
150 fn deref(&self) -> &Self::Target {
151 &self.0
152 }
153}
154
155impl<L, B, H> DerefMut for Storage<L, B, H>
156where
157 L: Label,
158 B: InternerBackend,
159 <B as InternerBackend>::Symbol: Symbol,
160 H: BuildHasher,
161{
162 fn deref_mut(&mut self) -> &mut Self::Target {
163 &mut self.0
164 }
165}
166
167impl<L, B, H> From<StringInterner<B, H>> for Storage<L, B, H>
168where
169 L: Label,
170 B: InternerBackend,
171 <B as InternerBackend>::Symbol: Symbol,
172 H: BuildHasher,
173{
174 fn from(interner: StringInterner<B, H>) -> Self {
175 Storage::unique(interner)
176 }
177}
178
179impl<L, B, H> From<&Arc<Mutex<StringInterner<B, H>>>> for Storage<L, B, H>
180where
181 L: Label,
182 B: InternerBackend,
183 <B as InternerBackend>::Symbol: Symbol,
184 H: BuildHasher,
185{
186 fn from(interner: &Arc<Mutex<StringInterner<B, H>>>) -> Self {
187 Storage::shared(interner)
188 }
189}
190
191/// A lock on the underlying [`StringInterner`] in a [`Storage`].
192pub struct StorageLock<'lock, L, B, H>(MutexGuard<'lock, StringInterner<B, H>>, PhantomData<L>)
193where
194 L: Label,
195 B: InternerBackend,
196 <B as InternerBackend>::Symbol: Symbol,
197 H: BuildHasher;
198
199impl<'lock, L, B, H> Deref for StorageLock<'lock, L, B, H>
200where
201 L: Label,
202 B: InternerBackend,
203 <B as InternerBackend>::Symbol: Symbol,
204 H: BuildHasher,
205{
206 type Target = MutexGuard<'lock, StringInterner<B, H>>;
207
208 fn deref(&self) -> &Self::Target {
209 &self.0
210 }
211}
212
213impl<L, B, H> DerefMut for StorageLock<'_, L, B, H>
214where
215 L: Label,
216 B: InternerBackend,
217 <B as InternerBackend>::Symbol: Symbol,
218 H: BuildHasher,
219{
220 fn deref_mut(&mut self) -> &mut Self::Target {
221 &mut self.0
222 }
223}