Skip to main content

lasso2/
reader.rs

1use crate::{
2    arenas::AnyArena,
3    hasher::RandomState,
4    keys::{Key, Spur},
5    resolver::RodeoResolver,
6    util::{Iter, Strings},
7    Rodeo,
8};
9use alloc::vec::Vec;
10#[cfg(feature = "serialize")]
11use core::hash::{Hash, Hasher};
12use core::{hash::BuildHasher, ops::Index};
13use hashbrown::HashMap;
14
15/// A read-only view of a [`Rodeo`] or [`ThreadedRodeo`] that allows contention-free access to interned strings,
16/// both key to string resolution and string to key lookups
17///
18/// The key and hasher types are the same as the `Rodeo` or `ThreadedRodeo` that created it, can be acquired with the
19/// `into_reader` methods.
20///
21/// [`Rodeo`]: crate::Rodeo
22/// [`ThreadedRodeo`]: crate::ThreadedRodeo
23#[derive(Debug)]
24pub struct RodeoReader<K = Spur, S = RandomState> {
25    // The logic behind this arrangement is more heavily documented inside of
26    // `Rodeo` itself
27    map: HashMap<K, (), ()>,
28    hasher: S,
29    pub(crate) strings: Vec<&'static str>,
30    __arena: AnyArena,
31}
32
33impl<K, S> RodeoReader<K, S> {
34    /// Creates a new RodeoReader
35    ///
36    /// # Safety
37    ///
38    /// The references inside of `strings` must be absolutely unique, meaning
39    /// that no other references to those strings exist
40    ///
41    pub(crate) unsafe fn new(
42        map: HashMap<K, (), ()>,
43        hasher: S,
44        strings: Vec<&'static str>,
45        arena: AnyArena,
46    ) -> Self {
47        Self {
48            map,
49            hasher,
50            strings,
51            __arena: arena,
52        }
53    }
54
55    /// Get the key value of a string, returning `None` if it doesn't exist
56    ///
57    /// # Example
58    ///
59    /// ```rust
60    /// use lasso2::Rodeo;
61    ///
62    /// // ThreadedRodeo is interchangeable for Rodeo here
63    /// let mut rodeo = Rodeo::default();
64    /// let key = rodeo.get_or_intern("Strings of things with wings and dings");
65    ///
66    /// let rodeo = rodeo.into_reader();
67    /// assert_eq!(Some(key), rodeo.get("Strings of things with wings and dings"));
68    ///
69    /// assert_eq!(None, rodeo.get("This string isn't interned"));
70    /// ```
71    ///
72    #[cfg_attr(feature = "inline-more", inline)]
73    pub fn get<T>(&self, val: T) -> Option<K>
74    where
75        T: AsRef<str>,
76        S: BuildHasher,
77        K: Key,
78    {
79        let string_slice: &str = val.as_ref();
80
81        // Make a hash of the requested string
82        let hash = self.hasher.hash_one(string_slice);
83
84        // Get the map's entry that the string should occupy
85        let entry = self.map.raw_entry().from_hash(hash, |key| {
86            // Safety: The index given by `key` will be in bounds of the strings vector
87            let key_string: &str = unsafe { index_unchecked!(self.strings, key.into_usize()) };
88
89            // Compare the requested string against the key's string
90            string_slice == key_string
91        });
92
93        entry.map(|(key, ())| *key)
94    }
95
96    /// Returns `true` if the given string has been interned
97    ///
98    /// # Example
99    ///
100    /// ```rust
101    /// use lasso2::Rodeo;
102    ///
103    /// // ThreadedRodeo is interchangeable for Rodeo here
104    /// let mut rodeo = Rodeo::default();
105    /// let key = rodeo.get_or_intern("Strings of things with wings and dings");
106    ///
107    /// let rodeo = rodeo.into_reader();
108    /// assert!(rodeo.contains("Strings of things with wings and dings"));
109    ///
110    /// assert!(!rodeo.contains("This string isn't interned"));
111    /// ```
112    ///
113    #[cfg_attr(feature = "inline-more", inline)]
114    pub fn contains<T>(&self, val: T) -> bool
115    where
116        T: AsRef<str>,
117        S: BuildHasher,
118        K: Key,
119    {
120        self.get(val).is_some()
121    }
122
123    /// Returns `true` if the given key exists in the current interner
124    ///
125    /// # Example
126    ///
127    /// ```rust
128    /// use lasso2::Rodeo;
129    /// # use lasso2::{Key, Spur};
130    ///
131    /// let mut rodeo = Rodeo::default();
132    /// let key = rodeo.get_or_intern("Strings of things with wings and dings");
133    /// # let key_that_doesnt_exist = Spur::try_from_usize(1000).unwrap();
134    ///
135    /// let rodeo = rodeo.into_reader();
136    /// assert!(rodeo.contains_key(&key));
137    /// assert!(!rodeo.contains_key(&key_that_doesnt_exist));
138    /// ```
139    ///
140    #[cfg_attr(feature = "inline-more", inline)]
141    pub fn contains_key(&self, key: &K) -> bool
142    where
143        K: Key,
144    {
145        key.into_usize() < self.strings.len()
146    }
147
148    /// Resolves a string by its key. Only keys made by the current Resolver or the creator
149    /// of the current Resolver may be used
150    ///
151    /// # Panics
152    ///
153    /// Panics if the key is out of bounds
154    ///
155    /// # Example
156    ///
157    /// ```rust
158    /// use lasso2::Rodeo;
159    ///
160    /// // ThreadedRodeo is interchangeable for Rodeo here
161    /// let mut rodeo = Rodeo::default();
162    /// let key = rodeo.get_or_intern("Strings of things with wings and dings");
163    ///
164    /// let rodeo = rodeo.into_resolver();
165    /// assert_eq!("Strings of things with wings and dings", rodeo.resolve(&key));
166    /// ```
167    ///
168    /// [`Key`]: crate::Key
169    #[cfg_attr(feature = "inline-more", inline)]
170    pub fn resolve<'a>(&'a self, key: &K) -> &'a str
171    where
172        K: Key,
173    {
174        // Safety: The call to get_unchecked's safety relies on the Key::into_usize impl
175        // being symmetric and the caller having not fabricated a key. If the impl is sound
176        // and symmetric, then it will succeed, as the usize used to create it is a valid
177        // index into self.strings
178        unsafe {
179            assert!(key.into_usize() < self.strings.len());
180            self.strings.get_unchecked(key.into_usize())
181        }
182    }
183
184    /// Resolves a string by its key, returning `None` if the key is out of bounds. Only keys
185    /// made by the current Resolver or the creator of the current Resolver may be used
186    ///
187    /// # Example
188    ///
189    /// ```rust
190    /// use lasso2::Rodeo;
191    ///
192    /// // ThreadedRodeo is interchangeable for Rodeo here
193    /// let mut rodeo = Rodeo::default();
194    /// let key = rodeo.get_or_intern("Strings of things with wings and dings");
195    ///
196    /// let rodeo = rodeo.into_resolver();
197    /// assert_eq!(Some("Strings of things with wings and dings"), rodeo.try_resolve(&key));
198    /// ```
199    ///
200    /// [`Key`]: crate::Key
201    #[cfg_attr(feature = "inline-more", inline)]
202    pub fn try_resolve<'a>(&'a self, key: &K) -> Option<&'a str>
203    where
204        K: Key,
205    {
206        // Safety: The call to get_unchecked's safety relies on the Key::into_usize impl
207        // being symmetric and the caller having not fabricated a key. If the impl is sound
208        // and symmetric, then it will succeed, as the usize used to create it is a valid
209        // index into self.strings
210        unsafe {
211            if key.into_usize() < self.strings.len() {
212                Some(self.strings.get_unchecked(key.into_usize()))
213            } else {
214                None
215            }
216        }
217    }
218
219    /// Resolves a string by its key without bounds checks
220    ///
221    /// # Safety
222    ///
223    /// The key must be valid for the current Reader
224    ///
225    /// # Example
226    ///
227    /// ```rust
228    /// use lasso2::Rodeo;
229    ///
230    /// // ThreadedRodeo is interchangeable for Rodeo here
231    /// let mut rodeo = Rodeo::default();
232    /// let key = rodeo.get_or_intern("Strings of things with wings and dings");
233    ///
234    /// let rodeo = rodeo.into_resolver();
235    /// unsafe {
236    ///     assert_eq!("Strings of things with wings and dings", rodeo.resolve_unchecked(&key));
237    /// }
238    /// ```
239    ///
240    /// [`Key`]: crate::Key
241    #[cfg_attr(feature = "inline-more", inline)]
242    pub unsafe fn resolve_unchecked<'a>(&'a self, key: &K) -> &'a str
243    where
244        K: Key,
245    {
246        unsafe { self.strings.get_unchecked(key.into_usize()) }
247    }
248
249    /// Gets the number of interned strings
250    ///
251    /// # Example
252    ///
253    /// ```rust
254    /// use lasso2::Rodeo;
255    ///
256    /// // ThreadedRodeo is interchangeable for Rodeo here
257    /// let mut rodeo = Rodeo::default();
258    /// rodeo.get_or_intern("Documentation often has little hidden bits in it");
259    ///
260    /// let rodeo = rodeo.into_reader();
261    /// assert_eq!(rodeo.len(), 1);
262    /// ```
263    ///
264    #[cfg_attr(feature = "inline-more", inline)]
265    pub fn len(&self) -> usize {
266        self.strings.len()
267    }
268
269    /// Returns `true` if there are no currently interned strings
270    ///
271    /// # Example
272    ///
273    /// ```rust
274    /// use lasso2::Rodeo;
275    ///
276    /// // ThreadedRodeo is interchangeable for Rodeo here
277    /// let rodeo = Rodeo::default();
278    ///
279    /// let rodeo = rodeo.into_reader();
280    /// assert!(rodeo.is_empty());
281    /// ```
282    ///
283    #[cfg_attr(feature = "inline-more", inline)]
284    pub fn is_empty(&self) -> bool {
285        self.len() == 0
286    }
287
288    /// Returns an iterator over the interned strings and their key values
289    #[cfg_attr(feature = "inline-more", inline)]
290    pub fn iter(&self) -> Iter<'_, K> {
291        Iter::from_reader(self)
292    }
293
294    /// Returns an iterator over the interned strings
295    #[cfg_attr(feature = "inline-more", inline)]
296    pub fn strings(&self) -> Strings<'_, K> {
297        Strings::from_reader(self)
298    }
299
300    /// Consumes the current rodeo and makes it into a [`RodeoResolver`], allowing
301    /// contention-free access from multiple threads with the lowest possible memory consumption
302    ///
303    /// # Example
304    ///
305    /// ```rust
306    /// use lasso2::Rodeo;
307    ///
308    /// // ThreadedRodeo is interchangeable for Rodeo here
309    /// let mut rodeo = Rodeo::default();
310    /// let key = rodeo.get_or_intern("Appear weak when you are strong, and strong when you are weak.");
311    /// let reader_rodeo = rodeo.into_reader();
312    ///
313    /// let resolver_rodeo = reader_rodeo.into_resolver();
314    /// assert_eq!(
315    ///     "Appear weak when you are strong, and strong when you are weak.",
316    ///     resolver_rodeo.resolve(&key),
317    /// );
318    /// ```
319    ///
320    /// [`RodeoResolver`]: crate::RodeoResolver
321    #[cfg_attr(feature = "inline-more", inline)]
322    #[must_use]
323    pub fn into_resolver(self) -> RodeoResolver<K> {
324        let RodeoReader {
325            strings, __arena, ..
326        } = self;
327
328        // Safety: The current reader no longer contains references to the strings
329        // in the vec given to RodeoResolver
330        unsafe { RodeoResolver::new(strings, __arena) }
331    }
332}
333
334unsafe impl<K: Sync, S: Sync> Sync for RodeoReader<K, S> {}
335unsafe impl<K: Send, S: Send> Send for RodeoReader<K, S> {}
336
337impl<'a, K: Key, S> IntoIterator for &'a RodeoReader<K, S> {
338    type Item = (K, &'a str);
339    type IntoIter = Iter<'a, K>;
340
341    #[cfg_attr(feature = "inline-more", inline)]
342    fn into_iter(self) -> Self::IntoIter {
343        self.iter()
344    }
345}
346
347impl<K, S> Index<K> for RodeoReader<K, S>
348where
349    K: Key,
350    S: BuildHasher,
351{
352    type Output = str;
353
354    #[cfg_attr(feature = "inline-more", inline)]
355    fn index(&self, idx: K) -> &Self::Output {
356        self.resolve(&idx)
357    }
358}
359
360impl<K, S> Eq for RodeoReader<K, S> {}
361
362impl<K, S> PartialEq<Self> for RodeoReader<K, S> {
363    #[cfg_attr(feature = "inline-more", inline)]
364    fn eq(&self, other: &Self) -> bool {
365        self.strings == other.strings
366    }
367}
368
369impl<K, S> PartialEq<RodeoResolver<K>> for RodeoReader<K, S> {
370    #[cfg_attr(feature = "inline-more", inline)]
371    fn eq(&self, other: &RodeoResolver<K>) -> bool {
372        self.strings == other.strings
373    }
374}
375
376impl<K, S> PartialEq<Rodeo<K, S>> for RodeoReader<K, S> {
377    #[cfg_attr(feature = "inline-more", inline)]
378    fn eq(&self, other: &Rodeo<K, S>) -> bool {
379        self.strings == other.strings
380    }
381}
382
383compile! {
384    if #[feature = "serialize"] {
385        use crate::{Capacity, arenas::Arena};
386        use alloc::string::String;
387        use core::num::NonZeroUsize;
388        use hashbrown::hash_map::RawEntryMut;
389        use serde::{
390            de::{Deserialize, Deserializer},
391            ser::{Serialize, Serializer},
392        };
393    }
394}
395
396#[cfg(feature = "serialize")]
397impl<K, H> Serialize for RodeoReader<K, H> {
398    #[cfg_attr(feature = "inline-more", inline)]
399    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
400    where
401        S: Serializer,
402    {
403        // Serialize all of self as a `Vec<String>`
404        self.strings.serialize(serializer)
405    }
406}
407
408#[cfg(feature = "serialize")]
409impl<'de, K: Key, S: BuildHasher + Default> Deserialize<'de> for RodeoReader<K, S> {
410    #[cfg_attr(feature = "inline-more", inline)]
411    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
412    where
413        D: Deserializer<'de>,
414    {
415        let vector: Vec<String> = Vec::deserialize(deserializer)?;
416        let capacity = {
417            let total_bytes = vector.iter().map(|s| s.len()).sum::<usize>();
418            let total_bytes =
419                NonZeroUsize::new(total_bytes).unwrap_or_else(|| Capacity::default().bytes());
420
421            Capacity::new(vector.len(), total_bytes)
422        };
423
424        let hasher: S = Default::default();
425        let mut strings = Vec::with_capacity(capacity.strings);
426        let mut map = HashMap::with_capacity_and_hasher(capacity.strings, ());
427        let mut arena = Arena::new(capacity.bytes, usize::max_value())
428            .expect("failed to allocate memory for interner");
429
430        for (key, string) in vector.into_iter().enumerate() {
431            let allocated = unsafe {
432                arena
433                    .store_str(&string)
434                    .expect("failed to allocate enough memory")
435            };
436
437            let hash = {
438                let mut state = hasher.build_hasher();
439                allocated.hash(&mut state);
440
441                state.finish()
442            };
443
444            // Get the map's entry that the string should occupy
445            let entry = map.raw_entry_mut().from_hash(hash, |key: &K| {
446                // Safety: The index given by `key` will be in bounds of the strings vector
447                let key_string: &str = unsafe { index_unchecked!(strings, key.into_usize()) };
448
449                // Compare the requested string against the key's string
450                allocated == key_string
451            });
452
453            match entry {
454                RawEntryMut::Occupied(..) => {
455                    debug_assert!(false, "re-interned a key while deserializing");
456                }
457                RawEntryMut::Vacant(entry) => {
458                    // Create the key from the vec's index that the string will hold
459                    let key =
460                        K::try_from_usize(key).expect("failed to create key while deserializing");
461
462                    // Push the allocated string to the strings vector
463                    strings.push(allocated);
464
465                    // Insert the key with the hash of the string that it points to, reusing the hash we made earlier
466                    entry.insert_with_hasher(hash, key, (), |key| {
467                        let key_string: &str =
468                            unsafe { index_unchecked!(strings, key.into_usize()) };
469
470                        let mut state = hasher.build_hasher();
471                        key_string.hash(&mut state);
472
473                        state.finish()
474                    });
475                }
476            }
477        }
478
479        Ok(Self {
480            map,
481            hasher,
482            strings,
483            __arena: AnyArena::Arena(arena),
484        })
485    }
486}
487
488#[cfg(test)]
489mod tests {
490    mod single_threaded {
491        #[cfg(feature = "serialize")]
492        use crate::RodeoReader;
493        use crate::{Key, Rodeo, Spur};
494
495        #[test]
496        fn get() {
497            let mut rodeo = Rodeo::default();
498            let key = rodeo.get_or_intern("A");
499
500            let reader = rodeo.into_reader();
501            assert_eq!(Some(key), reader.get("A"));
502
503            assert!(reader.get("F").is_none());
504        }
505
506        #[test]
507        fn resolve() {
508            let mut rodeo = Rodeo::default();
509            let key = rodeo.get_or_intern("A");
510
511            let reader = rodeo.into_reader();
512            assert_eq!("A", reader.resolve(&key));
513        }
514
515        #[test]
516        #[should_panic]
517        #[cfg(not(miri))]
518        fn resolve_panics() {
519            let reader = Rodeo::default().into_reader();
520            reader.resolve(&Spur::try_from_usize(100).unwrap());
521        }
522
523        #[test]
524        fn try_resolve() {
525            let mut rodeo = Rodeo::default();
526            let key = rodeo.get_or_intern("A");
527
528            let reader = rodeo.into_reader();
529            assert_eq!(Some("A"), reader.try_resolve(&key));
530            assert_eq!(
531                None,
532                reader.try_resolve(&Spur::try_from_usize(100).unwrap())
533            );
534        }
535
536        #[test]
537        fn resolve_unchecked() {
538            let mut rodeo = Rodeo::default();
539            let key = rodeo.get_or_intern("A");
540
541            let reader = rodeo.into_reader();
542            unsafe {
543                assert_eq!("A", reader.resolve_unchecked(&key));
544            }
545        }
546
547        #[test]
548        fn len() {
549            let mut rodeo = Rodeo::default();
550            rodeo.get_or_intern("A");
551            rodeo.get_or_intern("B");
552            rodeo.get_or_intern("C");
553
554            let reader = rodeo.into_reader();
555            assert_eq!(reader.len(), 3);
556        }
557
558        #[test]
559        fn empty() {
560            let rodeo = Rodeo::default();
561            let reader = rodeo.into_reader();
562
563            assert!(reader.is_empty());
564        }
565
566        #[test]
567        fn iter() {
568            let mut rodeo = Rodeo::default();
569            let a = rodeo.get_or_intern("a");
570            let b = rodeo.get_or_intern("b");
571            let c = rodeo.get_or_intern("c");
572
573            let resolver = rodeo.into_reader();
574            let mut iter = resolver.iter();
575
576            assert_eq!(Some((a, "a")), iter.next());
577            assert_eq!(Some((b, "b")), iter.next());
578            assert_eq!(Some((c, "c")), iter.next());
579            assert_eq!(None, iter.next());
580        }
581
582        #[test]
583        fn strings() {
584            let mut rodeo = Rodeo::default();
585            rodeo.get_or_intern("a");
586            rodeo.get_or_intern("b");
587            rodeo.get_or_intern("c");
588
589            let resolver = rodeo.into_reader();
590            let mut iter = resolver.strings();
591
592            assert_eq!(Some("a"), iter.next());
593            assert_eq!(Some("b"), iter.next());
594            assert_eq!(Some("c"), iter.next());
595            assert_eq!(None, iter.next());
596        }
597
598        #[test]
599        fn drops() {
600            let rodeo = Rodeo::default();
601            let _ = rodeo.into_reader();
602        }
603
604        #[test]
605        fn into_resolver() {
606            let mut rodeo = Rodeo::default();
607            let key = rodeo.get_or_intern("A");
608
609            let resolver = rodeo.into_reader().into_resolver();
610            assert_eq!("A", resolver.resolve(&key));
611        }
612
613        #[test]
614        #[cfg(not(any(feature = "no-std", feature = "ahasher")))]
615        fn debug() {
616            let reader = Rodeo::default().into_reader();
617            println!("{:?}", reader);
618        }
619
620        #[test]
621        fn contains() {
622            let mut rodeo = Rodeo::default();
623            rodeo.get_or_intern("");
624            let resolver = rodeo.into_reader();
625
626            assert!(resolver.contains(""));
627            assert!(resolver.contains(""));
628        }
629
630        #[test]
631        fn contains_key() {
632            let mut rodeo = Rodeo::default();
633            let key = rodeo.get_or_intern("");
634            let resolver = rodeo.into_reader();
635
636            assert!(resolver.contains(""));
637            assert!(resolver.contains_key(&key));
638            assert!(!resolver.contains_key(&Spur::try_from_usize(10000).unwrap()));
639        }
640
641        #[test]
642        fn into_iterator() {
643            let rodeo = ["a", "b", "c", "d", "e"]
644                .iter()
645                .collect::<Rodeo>()
646                .into_reader();
647
648            for ((key, string), (expected_key, expected_string)) in rodeo.into_iter().zip(
649                [(0usize, "a"), (1, "b"), (2, "c"), (3, "d"), (4, "e")]
650                    .iter()
651                    .copied(),
652            ) {
653                assert_eq!(key, Spur::try_from_usize(expected_key).unwrap());
654                assert_eq!(string, expected_string);
655            }
656        }
657
658        #[test]
659        fn index() {
660            let mut rodeo = Rodeo::default();
661            let key = rodeo.get_or_intern("A");
662
663            let reader = rodeo.into_reader();
664            assert_eq!("A", &reader[key]);
665        }
666
667        #[test]
668        #[cfg(feature = "serialize")]
669        fn empty_serialize() {
670            let rodeo = Rodeo::default().into_reader();
671
672            let ser = serde_json::to_string(&rodeo).unwrap();
673            let ser2 = serde_json::to_string(&rodeo).unwrap();
674            assert_eq!(ser, ser2);
675
676            let deser: RodeoReader = serde_json::from_str(&ser).unwrap();
677            assert!(deser.is_empty());
678            let deser2: RodeoReader = serde_json::from_str(&ser2).unwrap();
679            assert!(deser2.is_empty());
680        }
681
682        #[test]
683        #[cfg(feature = "serialize")]
684        fn filled_serialize() {
685            let mut rodeo = Rodeo::default();
686            let a = rodeo.get_or_intern("a");
687            let b = rodeo.get_or_intern("b");
688            let c = rodeo.get_or_intern("c");
689            let d = rodeo.get_or_intern("d");
690            let rodeo = rodeo.into_reader();
691
692            let ser = serde_json::to_string(&rodeo).unwrap();
693            let ser2 = serde_json::to_string(&rodeo).unwrap();
694            assert_eq!(ser, ser2);
695
696            let deser: RodeoReader = serde_json::from_str(&ser).unwrap();
697            let deser2: RodeoReader = serde_json::from_str(&ser2).unwrap();
698
699            for (((correct_key, correct_str), (key1, str1)), (key2, str2)) in
700                [(a, "a"), (b, "b"), (c, "c"), (d, "d")]
701                    .iter()
702                    .copied()
703                    .zip(&deser)
704                    .zip(&deser2)
705            {
706                assert_eq!(correct_key, key1);
707                assert_eq!(correct_key, key2);
708
709                assert_eq!(correct_str, str1);
710                assert_eq!(correct_str, str2);
711            }
712        }
713
714        #[test]
715        fn reader_eq() {
716            let a = Rodeo::default();
717            let b = Rodeo::default();
718            assert_eq!(a.into_reader(), b.into_reader());
719
720            let mut a = Rodeo::default();
721            a.get_or_intern("a");
722            a.get_or_intern("b");
723            a.get_or_intern("c");
724            let mut b = Rodeo::default();
725            b.get_or_intern("a");
726            b.get_or_intern("b");
727            b.get_or_intern("c");
728            assert_eq!(a.into_reader(), b.into_reader());
729        }
730
731        #[test]
732        fn resolver_eq() {
733            let a = Rodeo::default();
734            let b = Rodeo::default();
735            assert_eq!(a.into_reader(), b.into_resolver());
736
737            let mut a = Rodeo::default();
738            a.get_or_intern("a");
739            a.get_or_intern("b");
740            a.get_or_intern("c");
741            let mut b = Rodeo::default();
742            b.get_or_intern("a");
743            b.get_or_intern("b");
744            b.get_or_intern("c");
745            assert_eq!(a.into_reader(), b.into_resolver());
746        }
747    }
748
749    #[cfg(all(not(any(miri, feature = "no-std")), feature = "multi-threaded"))]
750    mod multi_threaded {
751        #[cfg(feature = "serialize")]
752        use crate::RodeoReader;
753        use crate::{keys::Key, locks::Arc, Spur, ThreadedRodeo};
754        use std::thread;
755
756        #[test]
757        fn get() {
758            let rodeo = ThreadedRodeo::default();
759            let key = rodeo.get_or_intern("A");
760
761            let reader = rodeo.into_reader();
762            assert_eq!(Some(key), reader.get("A"));
763
764            assert!(reader.get("F").is_none());
765        }
766
767        #[test]
768        #[cfg(not(miri))]
769        fn get_threaded() {
770            let rodeo = ThreadedRodeo::default();
771            let key = rodeo.get_or_intern("A");
772
773            let reader = Arc::new(rodeo.into_reader());
774
775            let moved = Arc::clone(&reader);
776            thread::spawn(move || {
777                assert_eq!(Some(key), moved.get("A"));
778                assert!(moved.get("F").is_none());
779            });
780
781            assert_eq!(Some(key), reader.get("A"));
782            assert!(reader.get("F").is_none());
783        }
784
785        #[test]
786        fn resolve() {
787            let rodeo = ThreadedRodeo::default();
788            let key = rodeo.get_or_intern("A");
789
790            let reader = rodeo.into_reader();
791            assert_eq!("A", reader.resolve(&key));
792        }
793
794        #[test]
795        #[cfg(not(miri))]
796        fn resolve_threaded() {
797            let rodeo = ThreadedRodeo::default();
798            let key = rodeo.get_or_intern("A");
799
800            let reader = Arc::new(rodeo.into_reader());
801
802            let moved = Arc::clone(&reader);
803            thread::spawn(move || {
804                assert_eq!("A", moved.resolve(&key));
805            });
806
807            assert_eq!("A", reader.resolve(&key));
808        }
809
810        #[test]
811        fn len() {
812            let rodeo = ThreadedRodeo::default();
813            rodeo.get_or_intern("A");
814            rodeo.get_or_intern("B");
815            rodeo.get_or_intern("C");
816
817            let reader = rodeo.into_reader();
818            assert_eq!(reader.len(), 3);
819        }
820
821        #[test]
822        fn empty() {
823            let rodeo = ThreadedRodeo::default();
824            let reader = rodeo.into_reader();
825
826            assert!(reader.is_empty());
827        }
828
829        // NOTE: Disabled because `Clone` is not implemented for [`ThreadedRodeo`]
830        // #[test]
831        // fn clone() {
832        //     let rodeo = ThreadedRodeo::default();
833        //     let key = rodeo.get_or_intern("Test");
834
835        //     let reader_rodeo = rodeo.into_reader();
836        //     assert_eq!("Test", reader_rodeo.resolve(&key));
837
838        //     let cloned = reader_rodeo.clone();
839        //     assert_eq!("Test", cloned.resolve(&key));
840
841        //     drop(reader_rodeo);
842
843        //     assert_eq!("Test", cloned.resolve(&key));
844        // }
845
846        #[test]
847        fn iter() {
848            let rodeo = ThreadedRodeo::default();
849            let a = rodeo.get_or_intern("a");
850            let b = rodeo.get_or_intern("b");
851            let c = rodeo.get_or_intern("c");
852
853            let resolver = rodeo.into_resolver();
854            let mut iter = resolver.iter();
855
856            assert_eq!(Some((a, "a")), iter.next());
857            assert_eq!(Some((b, "b")), iter.next());
858            assert_eq!(Some((c, "c")), iter.next());
859            assert_eq!(None, iter.next());
860        }
861
862        #[test]
863        fn strings() {
864            let rodeo = ThreadedRodeo::default();
865            rodeo.get_or_intern("a");
866            rodeo.get_or_intern("b");
867            rodeo.get_or_intern("c");
868
869            let resolver = rodeo.into_resolver();
870            let mut iter = resolver.strings();
871
872            assert_eq!(Some("a"), iter.next());
873            assert_eq!(Some("b"), iter.next());
874            assert_eq!(Some("c"), iter.next());
875            assert_eq!(None, iter.next());
876        }
877
878        #[test]
879        fn drops() {
880            let rodeo = ThreadedRodeo::default();
881            let _ = rodeo.into_reader();
882        }
883
884        #[test]
885        #[cfg(not(miri))]
886        fn drop_threaded() {
887            let rodeo = ThreadedRodeo::default();
888            let reader = Arc::new(rodeo.into_reader());
889
890            let moved = Arc::clone(&reader);
891            thread::spawn(move || {
892                let _ = moved;
893            });
894        }
895
896        #[test]
897        fn into_resolver() {
898            let rodeo = ThreadedRodeo::default();
899            let key = rodeo.get_or_intern("A");
900
901            let resolver = rodeo.into_reader().into_resolver();
902            assert_eq!("A", resolver.resolve(&key));
903        }
904
905        #[test]
906        #[cfg(not(feature = "no-std"))]
907        fn debug() {
908            let reader = ThreadedRodeo::default().into_reader();
909            println!("{:?}", reader);
910        }
911
912        #[test]
913        fn contains() {
914            let rodeo = ThreadedRodeo::default();
915            rodeo.get_or_intern("");
916            let resolver = rodeo.into_reader();
917
918            assert!(resolver.contains(""));
919            assert!(resolver.contains(""));
920        }
921
922        #[test]
923        fn contains_key() {
924            let rodeo = ThreadedRodeo::default();
925            let key = rodeo.get_or_intern("");
926            let resolver = rodeo.into_reader();
927
928            assert!(resolver.contains(""));
929            assert!(resolver.contains_key(&key));
930            assert!(!resolver.contains_key(&Spur::try_from_usize(10000).unwrap()));
931        }
932
933        #[test]
934        fn into_iterator() {
935            let rodeo = ["a", "b", "c", "d", "e"]
936                .iter()
937                .collect::<ThreadedRodeo>()
938                .into_reader();
939
940            for ((key, string), (expected_key, expected_string)) in rodeo.into_iter().zip(
941                [(0usize, "a"), (1, "b"), (2, "c"), (3, "d"), (4, "e")]
942                    .iter()
943                    .copied(),
944            ) {
945                assert_eq!(key, Spur::try_from_usize(expected_key).unwrap());
946                assert_eq!(string, expected_string);
947            }
948        }
949
950        #[test]
951        fn index() {
952            let rodeo = ThreadedRodeo::default();
953            let key = rodeo.get_or_intern("A");
954
955            let reader = rodeo.into_reader();
956            assert_eq!("A", &reader[key]);
957        }
958
959        #[test]
960        #[cfg(feature = "serialize")]
961        fn empty_serialize() {
962            let rodeo = ThreadedRodeo::default().into_reader();
963
964            let ser = serde_json::to_string(&rodeo).unwrap();
965            let ser2 = serde_json::to_string(&rodeo).unwrap();
966            assert_eq!(ser, ser2);
967
968            let deser: RodeoReader = serde_json::from_str(&ser).unwrap();
969            assert!(deser.is_empty());
970            let deser2: RodeoReader = serde_json::from_str(&ser2).unwrap();
971            assert!(deser2.is_empty());
972        }
973
974        #[test]
975        #[cfg(feature = "serialize")]
976        fn filled_serialize() {
977            let rodeo = ThreadedRodeo::default();
978            let a = rodeo.get_or_intern("a");
979            let b = rodeo.get_or_intern("b");
980            let c = rodeo.get_or_intern("c");
981            let d = rodeo.get_or_intern("d");
982            let rodeo = rodeo.into_reader();
983
984            let ser = serde_json::to_string(&rodeo).unwrap();
985            let ser2 = serde_json::to_string(&rodeo).unwrap();
986            assert_eq!(ser, ser2);
987
988            let deser: RodeoReader = serde_json::from_str(&ser).unwrap();
989            let deser2: RodeoReader = serde_json::from_str(&ser2).unwrap();
990
991            for (((correct_key, correct_str), (key1, str1)), (key2, str2)) in
992                [(a, "a"), (b, "b"), (c, "c"), (d, "d")]
993                    .iter()
994                    .copied()
995                    .zip(&deser)
996                    .zip(&deser2)
997            {
998                assert_eq!(correct_key, key1);
999                assert_eq!(correct_key, key2);
1000
1001                assert_eq!(correct_str, str1);
1002                assert_eq!(correct_str, str2);
1003            }
1004        }
1005    }
1006}