// This file is part of ICU4X. For terms of use, please see the file // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). pub(crate) trait MaybeSplitAt { /// Like slice::split_at but debug-panics and returns an empty second slice /// if the index is out of range. fn debug_split_at(&self, mid: usize) -> (&Self, &Self); } impl MaybeSplitAt for [T] { #[inline] fn debug_split_at(&self, mid: usize) -> (&Self, &Self) { self.split_at_checked(mid).unwrap_or_else(|| { debug_assert!(false, "debug_split_at: {mid} expected to be in range"); (self, &[]) }) } } pub(crate) trait DebugUnwrapOr { /// Unwraps the option or panics in debug mode, returning the `gigo_value` fn debug_unwrap_or(self, gigo_value: T) -> T; } impl DebugUnwrapOr for Option { #[inline] fn debug_unwrap_or(self, gigo_value: T) -> T { match self { Some(x) => x, None => { debug_assert!(false, "debug_unwrap_or called on a None value"); gigo_value } } } } macro_rules! debug_unwrap { ($expr:expr, return $retval:expr, $($arg:tt)+) => { match $expr { Some(x) => x, None => { debug_assert!(false, $($arg)*); return $retval; } } }; ($expr:expr, return $retval:expr) => { debug_unwrap!($expr, return $retval, "invalid trie") }; ($expr:expr, break, $($arg:tt)+) => { match $expr { Some(x) => x, None => { debug_assert!(false, $($arg)*); break; } } }; ($expr:expr, break) => { debug_unwrap!($expr, break, "invalid trie") }; ($expr:expr, $($arg:tt)+) => { debug_unwrap!($expr, return (), $($arg)*) }; ($expr:expr) => { debug_unwrap!($expr, return ()) }; } 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)); }