1 // This file is part of ICU4X. For terms of use, please see the file
2 // called LICENSE at the top level of the ICU4X source tree
3 // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5 pub(crate) trait MaybeSplitAt<T> {
6 /// Like slice::split_at but debug-panics and returns an empty second slice
7 /// if the index is out of range.
debug_split_at(&self, mid: usize) -> (&Self, &Self)8 fn debug_split_at(&self, mid: usize) -> (&Self, &Self);
9 }
10
11 impl<T> MaybeSplitAt<T> for [T] {
12 #[inline]
debug_split_at(&self, mid: usize) -> (&Self, &Self)13 fn debug_split_at(&self, mid: usize) -> (&Self, &Self) {
14 self.split_at_checked(mid).unwrap_or_else(|| {
15 debug_assert!(false, "debug_split_at: {mid} expected to be in range");
16 (self, &[])
17 })
18 }
19 }
20
21 pub(crate) trait DebugUnwrapOr<T> {
22 /// Unwraps the option or panics in debug mode, returning the `gigo_value`
debug_unwrap_or(self, gigo_value: T) -> T23 fn debug_unwrap_or(self, gigo_value: T) -> T;
24 }
25
26 impl<T> DebugUnwrapOr<T> for Option<T> {
27 #[inline]
debug_unwrap_or(self, gigo_value: T) -> T28 fn debug_unwrap_or(self, gigo_value: T) -> T {
29 match self {
30 Some(x) => x,
31 None => {
32 debug_assert!(false, "debug_unwrap_or called on a None value");
33 gigo_value
34 }
35 }
36 }
37 }
38
39 macro_rules! debug_unwrap {
40 ($expr:expr, return $retval:expr, $($arg:tt)+) => {
41 match $expr {
42 Some(x) => x,
43 None => {
44 debug_assert!(false, $($arg)*);
45 return $retval;
46 }
47 }
48 };
49 ($expr:expr, return $retval:expr) => {
50 debug_unwrap!($expr, return $retval, "invalid trie")
51 };
52 ($expr:expr, break, $($arg:tt)+) => {
53 match $expr {
54 Some(x) => x,
55 None => {
56 debug_assert!(false, $($arg)*);
57 break;
58 }
59 }
60 };
61 ($expr:expr, break) => {
62 debug_unwrap!($expr, break, "invalid trie")
63 };
64 ($expr:expr, $($arg:tt)+) => {
65 debug_unwrap!($expr, return (), $($arg)*)
66 };
67 ($expr:expr) => {
68 debug_unwrap!($expr, return ())
69 };
70 }
71
72 pub(crate) use debug_unwrap;
73
74 /// The maximum number of base-10 digits required for rendering a usize.
75 /// Note: 24/10 is an approximation of 8*log10(2)
76 pub(crate) const MAX_USIZE_LEN_AS_DIGITS: usize = core::mem::size_of::<usize>() * 24 / 10 + 1;
77
78 /// Formats a usize as a string of length N, padded with spaces,
79 /// with the given prefix.
80 ///
81 /// If the string is too short, the function may panic. To prevent
82 /// this, N should be MAX_USIZE_LEN_AS_DIGITS larger than M.
const_fmt_int<const M: usize, const N: usize>( prefix: [u8; M], value: usize, ) -> [u8; N]83 pub(crate) const fn const_fmt_int<const M: usize, const N: usize>(
84 prefix: [u8; M],
85 value: usize,
86 ) -> [u8; N] {
87 let mut output = [b' '; N];
88 let mut i = 0;
89 while i < M {
90 output[i] = prefix[i];
91 i += 1;
92 }
93 let mut int_only = [b' '; MAX_USIZE_LEN_AS_DIGITS];
94 let mut value = value;
95 let mut i = MAX_USIZE_LEN_AS_DIGITS - 1;
96 loop {
97 let x = (value % 10) as u8;
98 int_only[i] = x + b'0';
99 value /= 10;
100 if value == 0 {
101 break;
102 }
103 i -= 1;
104 }
105 let mut j = M;
106 while i < MAX_USIZE_LEN_AS_DIGITS {
107 output[j] = int_only[i];
108 j += 1;
109 i += 1;
110 }
111 output
112 }
113
114 #[test]
test_const_fmt_int()115 fn test_const_fmt_int() {
116 assert_eq!(*b"123", const_fmt_int::<0, 3>(*b"", 123));
117 assert_eq!(*b"123 ", const_fmt_int::<0, 6>(*b"", 123));
118 assert_eq!(*b"abc123", const_fmt_int::<3, 6>(*b"abc", 123));
119 }
120