use super::super::branch_meta::BranchMeta;
#[derive(Debug, Copy, Clone)]
pub(crate) struct ConstSlice<'a, T> {
full_slice: &'a [T],
start: usize,
limit: usize,
}
impl<'a, T> ConstSlice<'a, T> {
pub const fn from_slice(other: &'a [T]) -> Self {
ConstSlice {
full_slice: other,
start: 0,
limit: other.len(),
}
}
pub const fn from_manual_slice(full_slice: &'a [T], start: usize, limit: usize) -> Self {
ConstSlice {
full_slice,
start,
limit,
}
}
pub const fn len(&self) -> usize {
self.limit - self.start
}
pub const fn get_or_panic(&self, index: usize) -> &T {
#[allow(clippy::indexing_slicing)] &self.full_slice[index + self.start]
}
#[cfg(test)]
pub const fn first(&self) -> Option<&T> {
if self.len() == 0 {
None
} else {
Some(self.get_or_panic(0))
}
}
#[cfg(test)]
pub const fn get_subslice_or_panic(
&self,
new_start: usize,
new_limit: usize,
) -> ConstSlice<'a, T> {
assert!(new_start <= new_limit);
assert!(new_limit <= self.len());
ConstSlice {
full_slice: self.full_slice,
start: self.start + new_start,
limit: self.start + new_limit,
}
}
#[cfg(any(test, feature = "alloc"))]
#[allow(clippy::indexing_slicing)] pub fn as_slice(&self) -> &'a [T] {
&self.full_slice[self.start..self.limit]
}
}
impl<'a, T> From<&'a [T]> for ConstSlice<'a, T> {
fn from(other: &'a [T]) -> Self {
Self::from_slice(other)
}
}
#[derive(Debug, Copy, Clone)]
pub(crate) struct ConstArrayBuilder<const N: usize, T> {
full_array: [T; N],
start: usize,
limit: usize,
}
impl<const N: usize, T: Default> Default for ConstArrayBuilder<N, T> {
fn default() -> Self {
Self::new_empty([(); N].map(|_| Default::default()), 0)
}
}
impl<const N: usize, T> ConstArrayBuilder<N, T> {
pub const fn new_empty(full_array: [T; N], cursor: usize) -> Self {
assert!(cursor <= N);
Self {
full_array,
start: cursor,
limit: cursor,
}
}
pub const fn from_manual_slice(full_array: [T; N], start: usize, limit: usize) -> Self {
assert!(start <= limit);
assert!(limit <= N);
Self {
full_array,
start,
limit,
}
}
pub const fn len(&self) -> usize {
self.limit - self.start
}
#[allow(dead_code)]
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub const fn as_const_slice(&self) -> ConstSlice<'_, T> {
ConstSlice::from_manual_slice(&self.full_array, self.start, self.limit)
}
#[cfg(any(test, feature = "alloc"))]
pub fn as_slice(&self) -> &[T] {
&self.full_array[self.start..self.limit]
}
}
impl<const N: usize, T: Copy> ConstArrayBuilder<N, T> {
pub const fn const_build_or_panic(self) -> [T; N] {
if self.start != 0 || self.limit != N {
let actual_len = self.limit - self.start;
const PREFIX: &[u8; 31] = b"Buffer too large. Size needed: ";
let len_bytes: [u8; PREFIX.len() + crate::helpers::MAX_USIZE_LEN_AS_DIGITS] =
crate::helpers::const_fmt_int(*PREFIX, actual_len);
let Ok(len_str) = core::str::from_utf8(&len_bytes) else {
unreachable!()
};
panic!("{}", len_str);
}
self.full_array
}
#[allow(clippy::indexing_slicing)] pub const fn const_push_front_or_panic(&mut self, value: T) {
if self.start == 0 {
panic!("Buffer too small");
}
self.start -= 1;
self.full_array[self.start] = value;
}
#[allow(clippy::indexing_slicing)] pub const fn const_extend_front_or_panic(&mut self, other: ConstSlice<T>) {
if self.start < other.len() {
panic!("Buffer too small");
}
self.start -= other.len();
let mut i = self.start;
const_for_each!(other, byte, {
self.full_array[i] = *byte;
i += 1;
});
}
}
impl<const N: usize> ConstArrayBuilder<N, u8> {
#[allow(clippy::indexing_slicing)] pub(crate) const fn const_bitor_assign_or_panic(&mut self, index: usize, bits: u8) {
self.full_array[self.start + index] |= bits;
}
}
impl<const N: usize, T: Copy> ConstArrayBuilder<N, T> {
#[cfg(feature = "alloc")]
pub fn swap_or_panic(&mut self, i: usize, j: usize) {
self.full_array.swap(self.start + i, self.start + j);
}
}
macro_rules! const_for_each {
($safe_const_slice:expr, $item:tt, $inner:expr) => {{
let mut i = 0;
while i < $safe_const_slice.len() {
let $item = $safe_const_slice.get_or_panic(i);
$inner;
i += 1;
}
}};
}
pub(crate) use const_for_each;
pub(crate) struct ConstLengthsStack<const K: usize> {
data: [Option<BranchMeta>; K],
idx: usize,
}
impl<const K: usize> core::fmt::Debug for ConstLengthsStack<K> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.as_slice().fmt(f)
}
}
impl<const K: usize> ConstLengthsStack<K> {
pub const fn new() -> Self {
Self {
data: [None; K],
idx: 0,
}
}
pub const fn is_empty(&self) -> bool {
self.idx == 0
}
#[allow(clippy::indexing_slicing)] pub const fn push_or_panic(&mut self, meta: BranchMeta) {
if self.idx >= K {
panic!(concat!(
"AsciiTrie Builder: Need more stack (max ",
stringify!(K),
")"
));
}
self.data[self.idx] = Some(meta);
self.idx += 1;
}
pub const fn peek_or_panic(&self) -> BranchMeta {
if self.idx == 0 {
panic!("AsciiTrie Builder: Attempted to peek from an empty stack");
}
self.get_or_panic(0)
}
#[allow(clippy::indexing_slicing)] const fn get_or_panic(&self, index: usize) -> BranchMeta {
if self.idx <= index {
panic!("AsciiTrie Builder: Attempted to get too deep in a stack");
}
match self.data[self.idx - index - 1] {
Some(x) => x,
None => unreachable!(),
}
}
#[allow(clippy::indexing_slicing)] pub const fn pop_many_or_panic(&mut self, len: usize) -> ConstArrayBuilder<256, BranchMeta> {
debug_assert!(len <= 256);
let mut result = ConstArrayBuilder::new_empty([BranchMeta::default(); 256], 256);
let mut ix = 0;
loop {
if ix == len {
break;
}
let i = self.idx - ix - 1;
result.const_push_front_or_panic(match self.data[i] {
Some(x) => x,
None => panic!("Not enough items in the ConstLengthsStack"),
});
ix += 1;
}
self.idx -= len;
result
}
fn as_slice(&self) -> &[Option<BranchMeta>] {
&self.data[0..self.idx]
}
}
impl<const K: usize> ConstArrayBuilder<K, BranchMeta> {
pub const fn map_to_ascii_bytes(&self) -> ConstArrayBuilder<K, u8> {
let mut result = ConstArrayBuilder::new_empty([0; K], K);
let self_as_slice = self.as_const_slice();
const_for_each!(self_as_slice, value, {
result.const_push_front_or_panic(value.ascii);
});
result
}
}