diff --git a/experimental/zerotrie/src/builder/konst/store.rs b/experimental/zerotrie/src/builder/konst/store.rs index e70c0575313..73c72290b38 100644 --- a/experimental/zerotrie/src/builder/konst/store.rs +++ b/experimental/zerotrie/src/builder/konst/store.rs @@ -163,7 +163,14 @@ impl ConstArrayBuilder { /// 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 } @@ -171,7 +178,7 @@ impl ConstArrayBuilder { /// 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; @@ -181,7 +188,7 @@ impl ConstArrayBuilder { /// 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) -> Self { if self.start < other.len() { - panic!("AsciiTrieBuilder buffer too small"); + panic!("Buffer too small"); } self.start -= other.len(); let mut i = self.start; diff --git a/experimental/zerotrie/src/builder/mod.rs b/experimental/zerotrie/src/builder/mod.rs index ac4fc36b56b..8086cc14dbd 100644 --- a/experimental/zerotrie/src/builder/mod.rs +++ b/experimental/zerotrie/src/builder/mod.rs @@ -159,7 +159,13 @@ use super::ZeroTrieSimpleAscii; impl 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`]. /// @@ -213,7 +219,7 @@ impl 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), @@ -232,7 +238,13 @@ impl 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`]. /// diff --git a/experimental/zerotrie/src/helpers.rs b/experimental/zerotrie/src/helpers.rs index 4bb3abe2ca1..0d24f229138 100644 --- a/experimental/zerotrie/src/helpers.rs +++ b/experimental/zerotrie/src/helpers.rs @@ -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::() * 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( + 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)); +}