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}