Skip to content

Commit

Permalink
Print required length in ZeroTrie error (#4466)
Browse files Browse the repository at this point in the history
  • Loading branch information
sffc authored Dec 18, 2023
1 parent d602a40 commit 6cfe436
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 6 deletions.
13 changes: 10 additions & 3 deletions experimental/zerotrie/src/builder/konst/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,15 +163,22 @@ impl<const N: usize, T: Copy> ConstArrayBuilder<N, T> {
/// fully initialized.
pub const fn const_take_or_panic(self) -> [T; N] {
if self.start != 0 || self.limit != N {
panic!("AsciiTrieBuilder buffer too large");
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
}

/// Prepends an element to the front of the builder, panicking if there is no room.
pub const fn const_push_front_or_panic(mut self, value: T) -> Self {
if self.start == 0 {
panic!("AsciiTrieBuilder buffer too small");
panic!("Buffer too small");
}
self.start -= 1;
self.full_array[self.start] = value;
Expand All @@ -181,7 +188,7 @@ impl<const N: usize, T: Copy> ConstArrayBuilder<N, T> {
/// Prepends multiple elements to the front of the builder, panicking if there is no room.
pub const fn const_extend_front_or_panic(mut self, other: ConstSlice<T>) -> Self {
if self.start < other.len() {
panic!("AsciiTrieBuilder buffer too small");
panic!("Buffer too small");
}
self.start -= other.len();
let mut i = self.start;
Expand Down
18 changes: 15 additions & 3 deletions experimental/zerotrie/src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,13 @@ use super::ZeroTrieSimpleAscii;
impl<const N: usize> ZeroTrieSimpleAscii<[u8; N]> {
/// **Const Constructor:** Creates an [`ZeroTrieSimpleAscii`] from a sorted slice of keys and values.
///
/// This function needs to know the exact length of the resulting trie at compile time.
/// This function needs to know the exact length of the resulting trie at compile time. To
/// figure out `N`, first set `N` to be too large (say 0xFFFF), then look at the resulting
/// compile error which will tell you how to set `N`, like this:
///
/// > the evaluated program panicked at 'Buffer too large. Size needed: 17'
///
/// That error message says you need to set `N` to 17.
///
/// Also see [`Self::from_sorted_str_tuples`].
///
Expand Down Expand Up @@ -213,7 +219,7 @@ impl<const N: usize> ZeroTrieSimpleAscii<[u8; N]> {
/// Panics if capacity is too large:
///
/// ```compile_fail
/// # use zerotrie::{ZeroTrieSimpleAscii, AsciiStr};
/// # use zerotrie::ZeroTrieSimpleAscii;
/// const TRIE: ZeroTrieSimpleAscii<[u8; 20]> = ZeroTrieSimpleAscii::from_sorted_u8_tuples(&[
/// (b"bar", 2),
/// (b"bazzoo", 3),
Expand All @@ -232,7 +238,13 @@ impl<const N: usize> ZeroTrieSimpleAscii<[u8; N]> {

/// **Const Constructor:** Creates an [`ZeroTrieSimpleAscii`] from a sorted slice of keys and values.
///
/// This function needs to know the exact length of the resulting trie at compile time.
/// This function needs to know the exact length of the resulting trie at compile time. To
/// figure out `N`, first set `N` to be too large (say 0xFFFF), then look at the resulting
/// compile error which will tell you how to set `N`, like this:
///
/// > the evaluated program panicked at 'Buffer too large. Size needed: 17'
///
/// That error message says you need to set `N` to 17.
///
/// Also see [`Self::from_sorted_u8_tuples`].
///
Expand Down
47 changes: 47 additions & 0 deletions experimental/zerotrie/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,50 @@ macro_rules! debug_unwrap {
}

pub(crate) use debug_unwrap;

/// The maximum number of base-10 digits required for rendering a usize.
/// Note: 24/10 is an approximation of 8*log10(2)
pub(crate) const MAX_USIZE_LEN_AS_DIGITS: usize = core::mem::size_of::<usize>() * 24 / 10 + 1;

/// Formats a usize as a string of length N, padded with spaces,
/// with the given prefix.
///
/// If the string is too short, the function may panic. To prevent
/// this, N should be MAX_USIZE_LEN_AS_DIGITS larger than M.
pub(crate) const fn const_fmt_int<const M: usize, const N: usize>(
prefix: [u8; M],
value: usize,
) -> [u8; N] {
let mut output = [b' '; N];
let mut i = 0;
while i < M {
output[i] = prefix[i];
i += 1;
}
let mut int_only = [b' '; MAX_USIZE_LEN_AS_DIGITS];
let mut value = value;
let mut i = MAX_USIZE_LEN_AS_DIGITS - 1;
loop {
let x = (value % 10) as u8;
int_only[i] = x + b'0';
value /= 10;
if value == 0 {
break;
}
i -= 1;
}
let mut j = M;
while i < MAX_USIZE_LEN_AS_DIGITS {
output[j] = int_only[i];
j += 1;
i += 1;
}
output
}

#[test]
fn test_const_fmt_int() {
assert_eq!(*b"123", const_fmt_int::<0, 3>(*b"", 123));
assert_eq!(*b"123 ", const_fmt_int::<0, 6>(*b"", 123));
assert_eq!(*b"abc123", const_fmt_int::<3, 6>(*b"abc", 123));
}

0 comments on commit 6cfe436

Please sign in to comment.