1use super::super::branch_meta::BranchMeta;
8
9#[derive(Debug, Copy, Clone)]
13pub(crate) struct ConstSlice<'a, T> {
14 full_slice: &'a [T],
16 start: usize,
18 limit: usize,
20}
21
22impl<'a, T> ConstSlice<'a, T> {
23 pub const fn from_slice(other: &'a [T]) -> Self {
25 ConstSlice {
26 full_slice: other,
27 start: 0,
28 limit: other.len(),
29 }
30 }
31
32 pub const fn from_manual_slice(full_slice: &'a [T], start: usize, limit: usize) -> Self {
34 ConstSlice {
35 full_slice,
36 start,
37 limit,
38 }
39 }
40
41 pub const fn len(&self) -> usize {
43 self.limit - self.start
44 }
45
46 pub const fn get_or_panic(&self, index: usize) -> &T {
48 #[allow(clippy::indexing_slicing)] &self.full_slice[index + self.start]
50 }
51
52 #[cfg(test)]
54 pub const fn first(&self) -> Option<&T> {
55 if self.len() == 0 {
56 None
57 } else {
58 Some(self.get_or_panic(0))
60 }
61 }
62
63 #[cfg(test)]
65 pub const fn get_subslice_or_panic(
66 &self,
67 new_start: usize,
68 new_limit: usize,
69 ) -> ConstSlice<'a, T> {
70 assert!(new_start <= new_limit);
71 assert!(new_limit <= self.len());
72 ConstSlice {
73 full_slice: self.full_slice,
74 start: self.start + new_start,
75 limit: self.start + new_limit,
76 }
77 }
78
79 #[cfg(any(test, feature = "alloc"))]
81 #[allow(clippy::indexing_slicing)] pub fn as_slice(&self) -> &'a [T] {
83 &self.full_slice[self.start..self.limit]
84 }
85}
86
87impl<'a, T> From<&'a [T]> for ConstSlice<'a, T> {
88 fn from(other: &'a [T]) -> Self {
89 Self::from_slice(other)
90 }
91}
92
93#[derive(Debug, Copy, Clone)]
95pub(crate) struct ConstArrayBuilder<const N: usize, T> {
96 full_array: [T; N],
97 start: usize,
98 limit: usize,
99}
100
101impl<const N: usize, T: Default> Default for ConstArrayBuilder<N, T> {
102 fn default() -> Self {
103 Self::new_empty([(); N].map(|_| Default::default()), 0)
104 }
105}
106
107impl<const N: usize, T> ConstArrayBuilder<N, T> {
108 pub const fn new_empty(full_array: [T; N], cursor: usize) -> Self {
112 assert!(cursor <= N);
113 Self {
114 full_array,
115 start: cursor,
116 limit: cursor,
117 }
118 }
119
120 pub const fn from_manual_slice(full_array: [T; N], start: usize, limit: usize) -> Self {
122 assert!(start <= limit);
123 assert!(limit <= N);
124 Self {
125 full_array,
126 start,
127 limit,
128 }
129 }
130
131 pub const fn len(&self) -> usize {
133 self.limit - self.start
134 }
135
136 #[allow(dead_code)]
138 pub const fn is_empty(&self) -> bool {
139 self.len() == 0
140 }
141
142 pub const fn as_const_slice(&self) -> ConstSlice<'_, T> {
144 ConstSlice::from_manual_slice(&self.full_array, self.start, self.limit)
145 }
146
147 #[cfg(any(test, feature = "alloc"))]
149 pub fn as_slice(&self) -> &[T] {
150 &self.full_array[self.start..self.limit]
151 }
152}
153
154impl<const N: usize, T: Copy> ConstArrayBuilder<N, T> {
156 pub const fn const_build_or_panic(self) -> [T; N] {
159 if self.start != 0 || self.limit != N {
160 let actual_len = self.limit - self.start;
161 const PREFIX: &[u8; 31] = b"Buffer too large. Size needed: ";
162 let len_bytes: [u8; PREFIX.len() + crate::helpers::MAX_USIZE_LEN_AS_DIGITS] =
163 crate::helpers::const_fmt_int(*PREFIX, actual_len);
164 let Ok(len_str) = core::str::from_utf8(&len_bytes) else {
165 unreachable!()
166 };
167 panic!("{}", len_str);
168 }
169 self.full_array
170 }
171
172 #[allow(clippy::indexing_slicing)] pub const fn const_push_front_or_panic(&mut self, value: T) {
175 if self.start == 0 {
176 panic!("Buffer too small");
177 }
178 self.start -= 1;
179 self.full_array[self.start] = value;
180 }
181
182 #[allow(clippy::indexing_slicing)] pub const fn const_extend_front_or_panic(&mut self, other: ConstSlice<T>) {
185 if self.start < other.len() {
186 panic!("Buffer too small");
187 }
188 self.start -= other.len();
189 let mut i = self.start;
190 const_for_each!(other, byte, {
191 self.full_array[i] = *byte;
192 i += 1;
193 });
194 }
195}
196
197impl<const N: usize> ConstArrayBuilder<N, u8> {
198 #[allow(clippy::indexing_slicing)] pub(crate) const fn const_bitor_assign_or_panic(&mut self, index: usize, bits: u8) {
201 self.full_array[self.start + index] |= bits;
202 }
203}
204
205impl<const N: usize, T: Copy> ConstArrayBuilder<N, T> {
206 #[cfg(feature = "alloc")]
208 pub fn swap_or_panic(&mut self, i: usize, j: usize) {
209 self.full_array.swap(self.start + i, self.start + j);
210 }
211}
212
213macro_rules! const_for_each {
219 ($safe_const_slice:expr, $item:tt, $inner:expr) => {{
220 let mut i = 0;
221 while i < $safe_const_slice.len() {
222 let $item = $safe_const_slice.get_or_panic(i);
224 $inner;
225 i += 1;
226 }
227 }};
228}
229
230pub(crate) use const_for_each;
231
232pub(crate) struct ConstLengthsStack<const K: usize> {
237 data: [Option<BranchMeta>; K],
238 idx: usize,
239}
240
241impl<const K: usize> core::fmt::Debug for ConstLengthsStack<K> {
242 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
243 self.as_slice().fmt(f)
244 }
245}
246
247impl<const K: usize> ConstLengthsStack<K> {
248 pub const fn new() -> Self {
250 Self {
251 data: [None; K],
252 idx: 0,
253 }
254 }
255
256 pub const fn is_empty(&self) -> bool {
258 self.idx == 0
259 }
260
261 #[allow(clippy::indexing_slicing)] pub const fn push_or_panic(&mut self, meta: BranchMeta) {
264 if self.idx >= K {
265 panic!(concat!(
266 "AsciiTrie Builder: Need more stack (max ",
267 stringify!(K),
268 ")"
269 ));
270 }
271 self.data[self.idx] = Some(meta);
272 self.idx += 1;
273 }
274
275 pub const fn peek_or_panic(&self) -> BranchMeta {
278 if self.idx == 0 {
279 panic!("AsciiTrie Builder: Attempted to peek from an empty stack");
280 }
281 self.get_or_panic(0)
282 }
283
284 #[allow(clippy::indexing_slicing)] const fn get_or_panic(&self, index: usize) -> BranchMeta {
287 if self.idx <= index {
288 panic!("AsciiTrie Builder: Attempted to get too deep in a stack");
289 }
290 match self.data[self.idx - index - 1] {
291 Some(x) => x,
292 None => unreachable!(),
293 }
294 }
295
296 #[allow(clippy::indexing_slicing)] pub const fn pop_many_or_panic(&mut self, len: usize) -> ConstArrayBuilder<256, BranchMeta> {
299 debug_assert!(len <= 256);
300 let mut result = ConstArrayBuilder::new_empty([BranchMeta::default(); 256], 256);
301 let mut ix = 0;
302 loop {
303 if ix == len {
304 break;
305 }
306 let i = self.idx - ix - 1;
307 result.const_push_front_or_panic(match self.data[i] {
308 Some(x) => x,
309 None => panic!("Not enough items in the ConstLengthsStack"),
310 });
311 ix += 1;
312 }
313 self.idx -= len;
314 result
315 }
316
317 fn as_slice(&self) -> &[Option<BranchMeta>] {
319 &self.data[0..self.idx]
320 }
321}
322
323impl<const K: usize> ConstArrayBuilder<K, BranchMeta> {
324 pub const fn map_to_ascii_bytes(&self) -> ConstArrayBuilder<K, u8> {
326 let mut result = ConstArrayBuilder::new_empty([0; K], K);
327 let self_as_slice = self.as_const_slice();
328 const_for_each!(self_as_slice, value, {
329 result.const_push_front_or_panic(value.ascii);
330 });
331 result
332 }
333}