string_interner/backend/bucket/
mod.rs1#![cfg(feature = "backends")]
2
3mod fixed_str;
4mod interned_str;
5
6use self::{fixed_str::FixedString, interned_str::InternedStr};
7use super::Backend;
8use crate::{symbol::expect_valid_symbol, DefaultSymbol, Symbol};
9use alloc::{string::String, vec::Vec};
10use core::{iter::Enumerate, marker::PhantomData, slice};
11
12#[derive(Debug)]
46pub struct BucketBackend<S = DefaultSymbol> {
47 spans: Vec<InternedStr>,
48 head: FixedString,
49 full: Vec<String>,
50 marker: PhantomData<fn() -> S>,
51}
52
53unsafe impl<S> Send for BucketBackend<S> where S: Symbol {}
59
60unsafe impl<S> Sync for BucketBackend<S> where S: Symbol {}
66
67impl<S> Default for BucketBackend<S> {
68 #[cfg_attr(feature = "inline-more", inline)]
69 fn default() -> Self {
70 Self {
71 spans: Vec::new(),
72 head: FixedString::default(),
73 full: Vec::new(),
74 marker: Default::default(),
75 }
76 }
77}
78
79impl<S> Backend for BucketBackend<S>
80where
81 S: Symbol,
82{
83 type Symbol = S;
84 type Iter<'a>
85 = Iter<'a, S>
86 where
87 Self: 'a;
88
89 #[cfg_attr(feature = "inline-more", inline)]
90 fn with_capacity(cap: usize) -> Self {
91 Self {
92 spans: Vec::with_capacity(cap),
93 head: FixedString::with_capacity(cap),
94 full: Vec::new(),
95 marker: Default::default(),
96 }
97 }
98
99 #[inline]
100 fn intern(&mut self, string: &str) -> Self::Symbol {
101 let interned = unsafe { self.alloc(string) };
105 self.push_span(interned)
106 }
107
108 #[cfg_attr(feature = "inline-more", inline)]
109 fn intern_static(&mut self, string: &'static str) -> Self::Symbol {
110 let interned = InternedStr::new(string);
111 self.push_span(interned)
112 }
113
114 fn shrink_to_fit(&mut self) {
115 self.spans.shrink_to_fit();
116 self.full.shrink_to_fit();
119 }
120
121 #[inline]
122 fn resolve(&self, symbol: Self::Symbol) -> Option<&str> {
123 self.spans.get(symbol.to_usize()).map(InternedStr::as_str)
124 }
125
126 #[inline]
127 unsafe fn resolve_unchecked(&self, symbol: Self::Symbol) -> &str {
128 unsafe { self.spans.get_unchecked(symbol.to_usize()).as_str() }
131 }
132
133 #[inline]
134 fn iter(&self) -> Self::Iter<'_> {
135 Iter::new(self)
136 }
137}
138
139impl<S> BucketBackend<S>
140where
141 S: Symbol,
142{
143 fn next_symbol(&self) -> S {
145 expect_valid_symbol(self.spans.len())
146 }
147
148 fn push_span(&mut self, interned: InternedStr) -> S {
150 let symbol = self.next_symbol();
151 self.spans.push(interned);
152 symbol
153 }
154
155 unsafe fn alloc(&mut self, string: &str) -> InternedStr {
157 let cap = self.head.capacity();
158 if cap < self.head.len() + string.len() {
159 let new_cap = (usize::max(cap, string.len()) + 1).next_power_of_two();
160 let new_head = FixedString::with_capacity(new_cap);
161 let old_head = core::mem::replace(&mut self.head, new_head);
162 self.full.push(old_head.finish());
163 }
164 self.head
165 .push_str(string)
166 .expect("encountered invalid head capacity (2)")
167 }
168}
169
170impl<S> Clone for BucketBackend<S> {
171 fn clone(&self) -> Self {
172 let new_head_cap =
175 self.head.capacity() + self.full.iter().fold(0, |lhs, rhs| lhs + rhs.len());
176 let mut head = FixedString::with_capacity(new_head_cap);
177 let mut spans = Vec::with_capacity(self.spans.len());
178 for span in &self.spans {
179 let string = span.as_str();
180 let interned = head
181 .push_str(string)
182 .expect("encountered invalid head capacity");
183 spans.push(interned);
184 }
185 Self {
186 spans,
187 head,
188 full: Vec::new(),
189 marker: Default::default(),
190 }
191 }
192}
193
194impl<S> Eq for BucketBackend<S> where S: Symbol {}
195
196impl<S> PartialEq for BucketBackend<S>
197where
198 S: Symbol,
199{
200 #[cfg_attr(feature = "inline-more", inline)]
201 fn eq(&self, other: &Self) -> bool {
202 self.spans == other.spans
203 }
204}
205
206impl<'a, S> IntoIterator for &'a BucketBackend<S>
207where
208 S: Symbol,
209{
210 type Item = (S, &'a str);
211 type IntoIter = Iter<'a, S>;
212
213 #[cfg_attr(feature = "inline-more", inline)]
214 fn into_iter(self) -> Self::IntoIter {
215 self.iter()
216 }
217}
218
219pub struct Iter<'a, S> {
220 iter: Enumerate<slice::Iter<'a, InternedStr>>,
221 symbol_marker: PhantomData<fn() -> S>,
222}
223
224impl<'a, S> Iter<'a, S> {
225 #[cfg_attr(feature = "inline-more", inline)]
226 pub fn new(backend: &'a BucketBackend<S>) -> Self {
227 Self {
228 iter: backend.spans.iter().enumerate(),
229 symbol_marker: Default::default(),
230 }
231 }
232}
233
234impl<'a, S> Iterator for Iter<'a, S>
235where
236 S: Symbol,
237{
238 type Item = (S, &'a str);
239
240 #[inline]
241 fn size_hint(&self) -> (usize, Option<usize>) {
242 self.iter.size_hint()
243 }
244
245 #[inline]
246 fn next(&mut self) -> Option<Self::Item> {
247 self.iter
248 .next()
249 .map(|(id, interned)| (expect_valid_symbol(id), interned.as_str()))
250 }
251}