Skip to main content

cstree/interning/
traits.rs

1use core::fmt;
2
3use super::TokenKey;
4
5/// Common interface for all intern keys via conversion to and from `u32`.
6///
7/// # Safety
8/// Implementations must guarantee that keys can round-trip in both directions: going from `Self` to `u32` to `Self` and
9/// going from `u32` to `Self` to `u32` must each yield the original value.
10pub unsafe trait InternKey: Copy + Eq + fmt::Debug {
11    /// Convert `self` into its raw representation.
12    fn into_u32(self) -> u32;
13
14    /// Try to reconstruct an intern key from its raw representation.
15    /// Returns `None` if `key` is not a valid key.
16    fn try_from_u32(key: u32) -> Option<Self>;
17}
18
19/// The read-only part of an interner.
20/// Allows to perform lookups of intern keys to resolve them to their interned text.
21pub trait Resolver<Key: InternKey = TokenKey> {
22    /// Tries to resolve the given `key` and return its interned text.
23    ///
24    /// If `self` does not contain any text for `key`, `None` is returned.
25    fn try_resolve(&self, key: Key) -> Option<&str>;
26
27    /// Resolves `key` to its interned text.
28    ///
29    /// # Panics
30    /// Panics if there is no text for `key`.
31    ///
32    /// Compatibility implementations for interners from other crates may also panic if `key` cannot be converted to the
33    /// key type of the external interner. Please ensure you configure any external interners appropriately (for
34    /// example by choosing an appropriately sized key type).
35    fn resolve(&self, key: Key) -> &str {
36        self.try_resolve(key)
37            .unwrap_or_else(|| panic!("failed to resolve `{key:?}`"))
38    }
39}
40
41impl<R: Resolver> Resolver for &R {
42    fn try_resolve(&self, key: TokenKey) -> Option<&str> {
43        (**self).try_resolve(key)
44    }
45
46    fn resolve(&self, key: TokenKey) -> &str {
47        (**self).resolve(key)
48    }
49}
50
51impl<R: Resolver> Resolver for &mut R {
52    fn try_resolve(&self, key: TokenKey) -> Option<&str> {
53        (**self).try_resolve(key)
54    }
55
56    fn resolve(&self, key: TokenKey) -> &str {
57        (**self).resolve(key)
58    }
59}
60
61/// A full interner, which can intern new strings returning intern keys and also resolve intern keys to the interned
62/// value.
63///
64/// **Note:** Because single-threaded interners may require mutable access, the methods on this trait take `&mut self`.
65/// In order to use a multi- (or single)-threaded interner that allows access through a shared reference, it is
66/// implemented for `&MultiThreadedTokenInterner` and `Arc<MultiThreadedTokenInterner>`, allowing it
67/// to be used with a `&mut &MultiThreadedTokenInterner` and `&mut Arc<MultiThreadTokenInterner>`.
68pub trait Interner<Key: InternKey = TokenKey>: Resolver<Key> {
69    /// Represents possible ways in which interning may fail.
70    /// For example, this might be running out of fresh intern keys, or failure to allocate sufficient space for a new
71    /// value.
72    type Error;
73
74    /// Interns `text` and returns a new intern key for it.
75    /// If `text` was already previously interned, it will not be used and the existing intern key for its value will be
76    /// returned.
77    fn try_get_or_intern(&mut self, text: &str) -> Result<Key, Self::Error>;
78
79    /// Interns `text` and returns a new intern key for it.
80    ///
81    /// # Panics
82    /// Panics if the internment process raises an [`Error`](Interner::Error).
83    fn get_or_intern(&mut self, text: &str) -> Key {
84        self.try_get_or_intern(text)
85            .unwrap_or_else(|_| panic!("failed to intern `{text:?}`"))
86    }
87}
88
89impl<I: Interner> Interner for &mut I {
90    type Error = I::Error;
91
92    fn try_get_or_intern(&mut self, text: &str) -> Result<TokenKey, Self::Error> {
93        (**self).try_get_or_intern(text)
94    }
95
96    fn get_or_intern(&mut self, text: &str) -> TokenKey {
97        (**self).get_or_intern(text)
98    }
99}