Lightweight tagged data library.
at main 223 lines 6.5 kB view raw
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}