1pub trait NumberWidth {
5 fn signed_digit_count(&self, base: u64) -> i64;
9
10 fn signed_width(&self) -> u64 {
21 self.signed_width_base(10)
22 }
23
24 fn signed_width_base(&self, base: u64) -> u64 {
35 let count = match self.signed_digit_count(base) {
36 count if count < 0 => (-count + 1) as u64,
37 count => count as u64,
38 };
39
40 count.max(1)
41 }
42
43 fn width(&self) -> u64 {
57 self.width_base(10)
58 }
59
60 fn width_base(&self, base: u64) -> u64 {
65 (self.signed_digit_count(base).abs() as u64).max(1)
66 }
67}
68
69fn digit_count(num: u64, base: u64) -> u64 {
70 let mut width = 0;
71 let mut cur = num;
72 while cur > 0 {
73 cur /= base;
74 width += 1;
75 }
76 width
77}
78
79#[test]
80fn test_digit_count() {
81 for base in 2..255 {
82 assert_eq!(digit_count(0, base), 0);
84 for num in 1..base {
85 assert_eq!(digit_count(num, base), 1);
86 }
87
88 let mut num: u64 = 1;
90 for i in 1.. {
91 num = match num.checked_mul(base) {
92 Some(num) => num,
93 None => break,
94 };
95 assert_eq!(digit_count(num - 1, base), i);
96 assert_eq!(digit_count(num, base), i + 1);
97 }
98 }
99}
100
101fn signed_digit_count(num: i64, base: u64) -> i64 {
102 let sign = num.signum();
103 let num = num.checked_abs().map(|num| num as u64).unwrap_or(i64::MAX as u64 + 1);
105 let digit_count = digit_count(num, base);
106 digit_count as i64 * sign
107}
108
109#[test]
110fn test_signed_digit_count() {
111 for base in 2..255 {
112 assert_eq!(signed_digit_count(0, base), 0);
114 for num in 1..base {
115 assert_eq!(signed_digit_count(num as i64, base), 1);
116 }
117
118 let mut num: i64 = 1;
120 for i in 1.. {
121 num = match num.checked_mul(base as i64) {
122 Some(num) => num,
123 None => break,
124 };
125
126 assert_eq!(signed_digit_count(num - 1, base), i);
127 assert_eq!(signed_digit_count(num, base), i + 1);
128 }
129
130 let mut num: i64 = -1;
132 for i in 1.. {
133 num = match num.checked_mul(base as i64) {
134 Some(num) => num,
135 None => break,
136 };
137
138 assert_eq!(signed_digit_count(num + 1, base), -i);
139 assert_eq!(signed_digit_count(num, base), -i - 1);
140 }
141 }
142}
143
144#[test]
145fn can_determine_width_u8() {
146 for num in 0..u8::MAX {
147 assert_eq!(num.width() as usize, num.to_string().len());
148 assert_eq!(num.signed_width() as usize, num.to_string().len());
149 }
150}
151
152#[test]
153fn can_determine_width_u16() {
154 for num in 0..u16::MAX {
155 assert_eq!(num.width() as usize, num.to_string().len());
156 assert_eq!(num.signed_width() as usize, num.to_string().len());
157 }
158}
159
160#[test]
161fn can_determine_width_u32() {
162 assert_eq!(0u32.width(), 1);
163 assert_eq!(10u32.width(), 2);
164 assert_eq!(100u32.width(), 3);
165
166 assert_eq!(0x0u32.width_base(16), 1);
167 assert_eq!(0xFu32.width_base(16), 1);
168 assert_eq!(0xFABu32.width_base(16), 3);
169 assert_eq!(0xCAFEu32.width_base(16), 4);
170}
171
172#[test]
173fn can_determine_width_u64() {
174 assert_eq!(0u64.width(), 1);
175 assert_eq!(10u64.width(), 2);
176 assert_eq!(100u64.width(), 3);
177
178 assert_eq!(0x0u64.width_base(16), 1);
179 assert_eq!(0xFu64.width_base(16), 1);
180 assert_eq!(0xFABu64.width_base(16), 3);
181 assert_eq!(0xDEADBEEFu64.width_base(16), 8);
182}
183
184#[test]
185fn can_determine_width_i8() {
186 for num in i8::MIN..i8::MAX {
187 assert_eq!(num.signed_width() as usize, num.to_string().len());
188 if num >= 0 {
189 assert_eq!(num.width() as usize, num.to_string().len());
190 }
191 }
192}
193
194#[test]
195fn can_determine_width_i16() {
196 for num in i16::MIN..i16::MAX {
197 assert_eq!(num.signed_width() as usize, num.to_string().len());
198 if num >= 0 {
199 assert_eq!(num.width() as usize, num.to_string().len());
200 }
201 }
202}
203
204#[test]
205fn can_determine_width_i32() {
206 assert_eq!(0i32.width(), 1);
207 assert_eq!(10i32.width(), 2);
208 assert_eq!(100i32.width(), 3);
209 assert_eq!((-233i32).width(), 3);
210 assert_eq!((-233i32).signed_width(), 4);
211
212 assert_eq!(0x0i32.width_base(16), 1);
213 assert_eq!(0xFi32.width_base(16), 1);
214 assert_eq!(0xFABi32.width_base(16), 3);
215 assert_eq!(0xCAFEi32.width_base(16), 4);
216 assert_eq!((-0xCAFEi32).signed_width_base(16), 5);
217}
218
219#[test]
220fn can_determine_width_i64() {
221 assert_eq!(0i64.width(), 1);
222 assert_eq!(10i64.width(), 2);
223 assert_eq!(100i64.width(), 3);
224 assert_eq!((-233i64).width(), 3);
225 assert_eq!((-233i64).signed_width(), 4);
226
227 assert_eq!(0x0i64.width_base(16), 1);
228 assert_eq!(0xFi64.width_base(16), 1);
229 assert_eq!(0xFABi64.width_base(16), 3);
230 assert_eq!(0xCAFEi64.width_base(16), 4);
231 assert_eq!((-0xCAFEi64).signed_width_base(16), 5);
232}
233
234impl NumberWidth for u8 {
235 fn signed_digit_count(&self, base: u64) -> i64 {
236 digit_count((*self).into(), base) as i64
237 }
238}
239
240impl NumberWidth for u16 {
241 fn signed_digit_count(&self, base: u64) -> i64 {
242 digit_count((*self).into(), base) as i64
243 }
244}
245
246impl NumberWidth for u32 {
247 fn signed_digit_count(&self, base: u64) -> i64 {
248 digit_count((*self).into(), base) as i64
249 }
250}
251
252impl NumberWidth for u64 {
253 fn signed_digit_count(&self, base: u64) -> i64 {
254 digit_count(*self, base) as i64
255 }
256}
257
258impl NumberWidth for i8 {
259 fn signed_digit_count(&self, base: u64) -> i64 {
260 signed_digit_count((*self).into(), base)
261 }
262}
263
264impl NumberWidth for i16 {
265 fn signed_digit_count(&self, base: u64) -> i64 {
266 signed_digit_count((*self).into(), base)
267 }
268}
269
270impl NumberWidth for i32 {
271 fn signed_digit_count(&self, base: u64) -> i64 {
272 signed_digit_count((*self).into(), base)
273 }
274}
275
276impl NumberWidth for i64 {
277 fn signed_digit_count(&self, base: u64) -> i64 {
278 signed_digit_count(*self, base)
279 }
280}