artichoke_core/
intern.rs

1//! Intern [`Symbol`][symbol]s on an interpreter.
2//!
3//! `Symbol`s are immutable byte strings that have the same lifetime as the
4//! interpreter.
5//!
6//! [symbol]: https://ruby-doc.org/core-3.1.2/Symbol.html
7
8use alloc::borrow::Cow;
9
10/// Store and retrieve byte strings that have the same lifetime as the
11/// interpreter.
12///
13/// See the [Ruby `Symbol` type][symbol].
14///
15/// [symbol]: https://ruby-doc.org/core-3.1.2/Symbol.html
16pub trait Intern {
17    /// Concrete type for symbol identifiers.
18    ///
19    /// The symbol identifier enables lookups in the underlying storage.
20    type Symbol: Copy;
21
22    /// Concrete type for errors returned while interning symbols.
23    type Error;
24
25    /// The initial `Symbol` index returned by the interner.
26    ///
27    /// Implementing `Intern` requires that symbol identifiers form an
28    /// arithmetic progression with a common difference of 1. The sequence of
29    /// symbol identifiers must be representable by a `Range<u32>`.
30    const SYMBOL_RANGE_START: Self::Symbol;
31
32    /// Store an immutable byte string for the life of the interpreter.
33    ///
34    /// Returns an identifier that enables retrieving the original bytes.
35    ///
36    /// # Errors
37    ///
38    /// If the symbol store cannot be accessed, an error is returned.
39    ///
40    /// If the symbol table overflows, an error is returned.
41    fn intern_bytes<T>(&mut self, symbol: T) -> Result<Self::Symbol, Self::Error>
42    where
43        T: Into<Cow<'static, [u8]>>;
44
45    /// Check if a byte string is already interned and return its symbol
46    /// identifier.  Return `None` if the string has not been interned before.
47    ///
48    /// Returns an identifier that enables retrieving the original bytes.
49    ///
50    /// # Errors
51    ///
52    /// If the symbol store cannot be accessed, an error is returned.
53    fn check_interned_bytes(&self, symbol: &[u8]) -> Result<Option<Self::Symbol>, Self::Error>;
54
55    /// Store an immutable string for the life of the interpreter.
56    ///
57    /// Returns an identifier that enables retrieving the original bytes.
58    ///
59    /// By default, this method is implemented by delegating to
60    /// [`intern_bytes`].
61    ///
62    /// # Errors
63    ///
64    /// If the symbol store cannot be accessed, an error is returned.
65    ///
66    /// If the symbol table overflows, an error is returned.
67    ///
68    /// [`intern_bytes`]: Self::intern_bytes
69    fn intern_string<T>(&mut self, symbol: T) -> Result<Self::Symbol, Self::Error>
70    where
71        T: Into<Cow<'static, str>>,
72    {
73        match symbol.into() {
74            Cow::Borrowed(string) => self.intern_bytes(string.as_bytes()),
75            Cow::Owned(string) => self.intern_bytes(string.into_bytes()),
76        }
77    }
78
79    /// Check if a string is already interned and return its symbol identifier.
80    /// Return `None` if the string has not been interned before.
81    ///
82    /// Returns an identifier that enables retrieving the original bytes.
83    ///
84    /// By default, this method is implemented by delegating to
85    /// [`check_interned_bytes`].
86    ///
87    /// # Errors
88    ///
89    /// If the symbol store cannot be accessed, an error is returned.
90    ///
91    /// [`check_interned_bytes`]: Self::check_interned_bytes
92    fn check_interned_string(&self, symbol: &str) -> Result<Option<Self::Symbol>, Self::Error> {
93        self.check_interned_bytes(symbol.as_bytes())
94    }
95
96    /// Retrieve the original byte content of an interned byte string.
97    ///
98    /// Returns `None` if the symbol identifier is invalid.
99    ///
100    /// # Errors
101    ///
102    /// If the symbol store cannot be accessed, an error is returned.
103    fn lookup_symbol(&self, symbol: Self::Symbol) -> Result<Option<&[u8]>, Self::Error>;
104
105    /// Retrieve the number of unique strings interned.
106    ///
107    /// This method should return the length of the underlying symbol table.
108    fn symbol_count(&self) -> usize;
109}