lasso2/interface/
mod.rs

1mod boxed;
2mod rodeo;
3mod rodeo_reader;
4mod rodeo_resolver;
5mod tests;
6mod threaded_ref;
7mod threaded_rodeo;
8
9use crate::{Key, LassoResult, Spur};
10#[cfg(feature = "no-std")]
11use alloc::boxed::Box;
12
13/// A generic interface over any underlying interner, allowing storing and accessing
14/// interned strings
15///
16/// Note that because single-threaded [`Rodeo`](crate::Rodeo)s require mutable access to use, this
17/// trait does so as well. For use with [`ThreadedRodeo`](crate::ThreadedRodeo), the trait is
18/// implemented for `&ThreadedRodeo` as well to allow access through shared references.
19pub trait Interner<K = Spur>: Reader<K> + Resolver<K> {
20    /// Get the key for a string, interning it if it does not yet exist
21    ///
22    /// # Panics
23    ///
24    /// Panics if the key's [`try_from_usize`](Key::try_from_usize) function fails. With the default
25    /// keys, this means that you've interned more strings than it can handle. (For [`Spur`] this
26    /// means that `u32::MAX - 1` unique strings were interned)
27    ///
28    fn get_or_intern(&mut self, val: &str) -> K;
29
30    /// Get the key for a string, interning it if it does not yet exist
31    fn try_get_or_intern(&mut self, val: &str) -> LassoResult<K>;
32
33    /// Get the key for a static string, interning it if it does not yet exist
34    ///
35    /// This will not reallocate or copy the given string
36    ///
37    /// # Panics
38    ///
39    /// Panics if the key's [`try_from_usize`](Key::try_from_usize) function fails. With the default
40    /// keys, this means that you've interned more strings than it can handle. (For [`Spur`] this
41    /// means that `u32::MAX - 1` unique strings were interned)
42    ///
43    fn get_or_intern_static(&mut self, val: &'static str) -> K;
44
45    /// Get the key for a static string, interning it if it does not yet exist
46    ///
47    /// This will not reallocate or copy the given string
48    fn try_get_or_intern_static(&mut self, val: &'static str) -> LassoResult<K>;
49}
50
51impl<T, K> Interner<K> for &mut T
52where
53    T: Interner<K>,
54{
55    #[inline]
56    fn get_or_intern(&mut self, val: &str) -> K {
57        <T as Interner<K>>::get_or_intern(self, val)
58    }
59
60    #[inline]
61    fn try_get_or_intern(&mut self, val: &str) -> LassoResult<K> {
62        <T as Interner<K>>::try_get_or_intern(self, val)
63    }
64
65    #[inline]
66    fn get_or_intern_static(&mut self, val: &'static str) -> K {
67        <T as Interner<K>>::get_or_intern_static(self, val)
68    }
69
70    #[inline]
71    fn try_get_or_intern_static(&mut self, val: &'static str) -> LassoResult<K> {
72        <T as Interner<K>>::try_get_or_intern_static(self, val)
73    }
74}
75
76/// A generic interface over interners that can be turned into both a [`Reader`] and a [`Resolver`]
77/// directly.
78pub trait IntoReaderAndResolver<K = Spur>: IntoReader<K> + IntoResolver<K>
79where
80    K: Key,
81{
82}
83
84/// A generic interface over interners that can be turned into a [`Reader`].
85pub trait IntoReader<K = Spur>: Interner<K>
86where
87    K: Key,
88{
89    /// The type of [`Reader`] the interner will be converted into
90    type Reader: Reader<K>;
91
92    /// Consumes the current [`Interner`] and converts it into a [`Reader`] to allow
93    /// contention-free access of the interner from multiple threads
94    #[must_use]
95    fn into_reader(self) -> Self::Reader
96    where
97        Self: 'static;
98
99    /// An implementation detail to allow calling [`Interner::into_reader()`] on dynamically
100    /// dispatched interners
101    #[doc(hidden)]
102    #[must_use]
103    fn into_reader_boxed(self: Box<Self>) -> Self::Reader
104    where
105        Self: 'static;
106}
107
108/// A generic interface that allows using any underlying interner for
109/// both its reading and resolution capabilities, allowing both
110/// `str -> key` and `key -> str` lookups
111pub trait Reader<K = Spur>: Resolver<K> {
112    /// Get a key for the given string value if it exists
113    fn get(&self, val: &str) -> Option<K>;
114
115    /// Returns `true` if the current interner contains the given string
116    fn contains(&self, val: &str) -> bool;
117}
118
119impl<T, K> Reader<K> for &T
120where
121    T: Reader<K>,
122{
123    #[inline]
124    fn get(&self, val: &str) -> Option<K> {
125        <T as Reader<K>>::get(self, val)
126    }
127
128    #[inline]
129    fn contains(&self, val: &str) -> bool {
130        <T as Reader<K>>::contains(self, val)
131    }
132}
133
134impl<T, K> Reader<K> for &mut T
135where
136    T: Reader<K>,
137{
138    #[inline]
139    fn get(&self, val: &str) -> Option<K> {
140        <T as Reader<K>>::get(self, val)
141    }
142
143    #[inline]
144    fn contains(&self, val: &str) -> bool {
145        <T as Reader<K>>::contains(self, val)
146    }
147}
148
149/// A generic interface over [`Reader`]s that can be turned into a [`Resolver`].
150pub trait IntoResolver<K = Spur>: Reader<K>
151where
152    K: Key,
153{
154    /// The type of [`Resolver`] the reader will be converted into
155    type Resolver: Resolver<K>;
156
157    /// Consumes the current [`Reader`] and makes it into a [`Resolver`], allowing
158    /// contention-free access from multiple threads with the lowest possible memory consumption
159    #[must_use]
160    fn into_resolver(self) -> Self::Resolver
161    where
162        Self: 'static;
163
164    /// An implementation detail to allow calling [`Reader::into_resolver()`] on dynamically
165    /// dispatched readers
166    #[doc(hidden)]
167    #[must_use]
168    fn into_resolver_boxed(self: Box<Self>) -> Self::Resolver
169    where
170        Self: 'static;
171}
172
173/// A generic interface that allows using any underlying interner only
174/// for its resolution capabilities, allowing only `key -> str` lookups
175pub trait Resolver<K = Spur> {
176    /// Resolves the given key into a string
177    ///
178    /// # Panics
179    ///
180    /// Panics if the key is not contained in the current [`Resolver`]
181    ///
182    fn resolve<'a>(&'a self, key: &K) -> &'a str;
183
184    /// Attempts to resolve the given key into a string, returning `None`
185    /// if it cannot be found
186    fn try_resolve<'a>(&'a self, key: &K) -> Option<&'a str>;
187
188    /// Resolves a string by its key without preforming bounds checks
189    ///
190    /// # Safety
191    ///
192    /// The key must be valid for the current [`Resolver`]
193    ///
194    unsafe fn resolve_unchecked<'a>(&'a self, key: &K) -> &'a str;
195
196    /// Returns `true` if the current interner contains the given key
197    fn contains_key(&self, key: &K) -> bool;
198
199    /// Gets the number of currently interned strings
200    fn len(&self) -> usize;
201
202    /// Returns `true` if there are no currently interned strings
203    #[cfg_attr(feature = "inline-more", inline)]
204    fn is_empty(&self) -> bool {
205        self.len() == 0
206    }
207}
208
209impl<T, K> Resolver<K> for &T
210where
211    T: Resolver<K>,
212{
213    #[inline]
214    fn resolve<'a>(&'a self, key: &K) -> &'a str {
215        <T as Resolver<K>>::resolve(self, key)
216    }
217
218    #[inline]
219    fn try_resolve<'a>(&'a self, key: &K) -> Option<&'a str> {
220        <T as Resolver<K>>::try_resolve(self, key)
221    }
222
223    #[inline]
224    unsafe fn resolve_unchecked<'a>(&'a self, key: &K) -> &'a str {
225        unsafe { <T as Resolver<K>>::resolve_unchecked(self, key) }
226    }
227
228    #[inline]
229    fn contains_key(&self, key: &K) -> bool {
230        <T as Resolver<K>>::contains_key(self, key)
231    }
232
233    #[inline]
234    fn len(&self) -> usize {
235        <T as Resolver<K>>::len(self)
236    }
237}
238
239impl<T, K> Resolver<K> for &mut T
240where
241    T: Resolver<K>,
242{
243    #[inline]
244    fn resolve<'a>(&'a self, key: &K) -> &'a str {
245        <T as Resolver<K>>::resolve(self, key)
246    }
247
248    #[inline]
249    fn try_resolve<'a>(&'a self, key: &K) -> Option<&'a str> {
250        <T as Resolver<K>>::try_resolve(self, key)
251    }
252
253    #[inline]
254    unsafe fn resolve_unchecked<'a>(&'a self, key: &K) -> &'a str {
255        unsafe { <T as Resolver<K>>::resolve_unchecked(self, key) }
256    }
257
258    #[inline]
259    fn contains_key(&self, key: &K) -> bool {
260        <T as Resolver<K>>::contains_key(self, key)
261    }
262
263    #[inline]
264    fn len(&self) -> usize {
265        <T as Resolver<K>>::len(self)
266    }
267}