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}