1#[derive(Clone, Copy, Debug)]
18pub struct DigitsUnds<'a> {
19 bytes: &'a [u8],
20 digits: usize,
21}
22
23impl<'a> DigitsUnds<'a> {
24 pub const EMPTY: DigitsUnds<'a> = DigitsUnds::new(&[]);
25
26 pub const fn new(bytes: &'a [u8]) -> DigitsUnds<'a> {
27 let mut digits = 0;
28 let mut leading_unds = 0;
29 let mut trailing_unds = 0;
30 let mut rem_bytes = bytes;
31 while let Some((&byte, rem)) = rem_bytes.split_first() {
32 rem_bytes = rem;
33
34 if byte == b'_' {
35 trailing_unds += 1;
36 } else {
37 if digits == 0 {
38 leading_unds = trailing_unds;
39 }
40 digits += 1;
41 trailing_unds = 0;
42 }
43 }
44 let without_trailing_unds = bytes.split_at(bytes.len() - trailing_unds).0;
45 let without_leading_unds = without_trailing_unds.split_at(leading_unds).1;
46 DigitsUnds {
47 bytes: without_leading_unds,
48 digits,
49 }
50 }
51
52 #[inline]
53 pub const fn len(self) -> usize {
54 self.digits
55 }
56
57 #[inline]
58 pub const fn is_empty(self) -> bool {
59 self.digits == 0
60 }
61
62 pub const fn split_at(self, mid: usize) -> (DigitsUnds<'a>, DigitsUnds<'a>) {
63 let mut remaining_digits = mid;
64 let mut unds = 0;
65 let mut rem_bytes = self.bytes;
66 while let Some((&byte, rem)) = rem_bytes.split_first() {
67 rem_bytes = rem;
68
69 if byte == b'_' {
70 unds += 1;
71 } else {
72 remaining_digits -= 1;
73 if remaining_digits == 0 {
74 break;
75 }
76 }
77 }
78 if remaining_digits > 0 {
79 panic!("index out of bounds");
80 }
81 let first = DigitsUnds {
82 bytes: self.bytes.split_at(mid + unds).0,
83 digits: mid,
84 };
85
86 while let Some((&b'_', rem)) = rem_bytes.split_first() {
88 rem_bytes = rem;
89 }
90 (
91 first,
92 DigitsUnds {
93 bytes: rem_bytes,
94 digits: self.digits - mid,
95 },
96 )
97 }
98
99 #[inline]
100 pub const fn split_first(self) -> Option<(u8, DigitsUnds<'a>)> {
101 let Some((&first, mut rem_bytes)) = self.bytes.split_first() else {
102 return None;
103 };
104
105 debug_assert!(first != b'_');
107
108 while let Some((&b'_', rem)) = rem_bytes.split_first() {
110 rem_bytes = rem;
111 }
112 Some((
113 first,
114 DigitsUnds {
115 bytes: rem_bytes,
116 digits: self.digits - 1,
117 },
118 ))
119 }
120
121 #[inline]
122 const fn split_last(self) -> Option<(u8, DigitsUnds<'a>)> {
123 let Some((&last, mut rem_bytes)) = self.bytes.split_last() else {
124 return None;
125 };
126
127 debug_assert!(last != b'_');
129
130 while let Some((&b'_', rem)) = rem_bytes.split_last() {
132 rem_bytes = rem;
133 }
134 Some((
135 last,
136 DigitsUnds {
137 bytes: rem_bytes,
138 digits: self.digits - 1,
139 },
140 ))
141 }
142
143 const fn split_leading_zeros(self) -> (usize, DigitsUnds<'a>) {
144 let mut zeros = 0;
145 let mut rem = self;
146 while let Some((b'0', rest)) = rem.split_first() {
147 zeros += 1;
148 rem = rest;
149 }
150 (zeros, rem)
151 }
152
153 const fn split_trailing_zeros(self) -> (usize, DigitsUnds<'a>) {
154 let mut zeros = 0;
155 let mut rem = self;
156 while let Some((b'0', rest)) = rem.split_last() {
157 zeros += 1;
158 rem = rest;
159 }
160 (zeros, rem)
161 }
162}
163
164#[derive(Clone, Copy, Debug)]
165pub struct DigitsExp<'a> {
166 leading_zeros: usize,
167 part1: DigitsUnds<'a>,
168 part2: DigitsUnds<'a>,
169 trailing_zeros: usize,
170}
171
172impl<'a> DigitsExp<'a> {
173 const EMPTY: DigitsExp<'a> = DigitsExp {
174 leading_zeros: 0,
175 part1: DigitsUnds::EMPTY,
176 part2: DigitsUnds::EMPTY,
177 trailing_zeros: 0,
178 };
179
180 const fn new1(digits: DigitsUnds<'a>) -> DigitsExp<'a> {
181 let (leading_zeros, rest) = digits.split_leading_zeros();
182 let (trailing_zeros, rest) = rest.split_trailing_zeros();
183 DigitsExp {
184 leading_zeros,
185 part1: rest,
186 part2: DigitsUnds::EMPTY,
187 trailing_zeros,
188 }
189 }
190
191 const fn new2(digits1: DigitsUnds<'a>, digits2: DigitsUnds<'a>) -> DigitsExp<'a> {
192 let (mut leading_zeros, mut digits1) = digits1.split_leading_zeros();
193 let digits2 = if digits1.is_empty() {
194 let (more_leading_zeros, new_digits1) = digits2.split_leading_zeros();
195 leading_zeros += more_leading_zeros;
196 digits1 = new_digits1;
197 DigitsUnds::EMPTY
198 } else {
199 digits2
200 };
201 let (mut trailing_zeros, digits2) = digits2.split_trailing_zeros();
202 if digits2.is_empty() {
203 let (more_trailing_zeros, new_digits1) = digits1.split_trailing_zeros();
204 trailing_zeros += more_trailing_zeros;
205 digits1 = new_digits1;
206 }
207 DigitsExp {
208 leading_zeros,
209 part1: digits1,
210 part2: digits2,
211 trailing_zeros,
212 }
213 }
214
215 pub const fn new_int_frac(
217 int: DigitsUnds<'a>,
218 frac: DigitsUnds<'a>,
219 exp: i32,
220 ) -> Option<(DigitsExp<'a>, DigitsExp<'a>)> {
221 if int.len() > usize::MAX - frac.len() {
222 return None;
223 }
224 let abs_exp = exp.unsigned_abs() as usize;
225 if abs_exp as u32 != exp.unsigned_abs() {
226 return None;
227 }
228
229 let (mut int, mut frac) = if exp == 0 {
230 (DigitsExp::new1(int), DigitsExp::new1(frac))
231 } else if exp < 0 {
232 if let Some(extra_zeros) = abs_exp.checked_sub(int.len()) {
233 let mut frac = DigitsExp::new2(int, frac);
234 frac.trailing_zeros = 0;
235 if extra_zeros > usize::MAX - frac.len() {
236 return None;
237 }
238 frac.leading_zeros += extra_zeros;
239 (DigitsExp::EMPTY, frac)
240 } else {
241 let int = int.split_at(int.len() - abs_exp);
242 (DigitsExp::new1(int.0), DigitsExp::new2(int.1, frac))
243 }
244 } else {
245 if let Some(extra_zeros) = abs_exp.checked_sub(frac.len()) {
247 let mut int = DigitsExp::new2(int, frac);
248 int.leading_zeros = 0;
249 if extra_zeros > usize::MAX - int.len() {
250 return None;
251 }
252 int.trailing_zeros += extra_zeros;
253 (int, DigitsExp::EMPTY)
254 } else {
255 let frac = frac.split_at(abs_exp);
256 (DigitsExp::new2(int, frac.0), DigitsExp::new1(frac.1))
257 }
258 };
259 int.leading_zeros = 0;
260 if int.part1.is_empty() && int.part2.is_empty() {
261 int.trailing_zeros = 0;
262 }
263 frac.trailing_zeros = 0;
264 if frac.part2.is_empty() && frac.part1.is_empty() {
265 frac.leading_zeros = 0;
266 }
267 Some((int, frac))
268 }
269
270 #[inline]
271 pub const fn len(self) -> usize {
272 self.leading_zeros + self.part1.len() + self.part2.len() + self.trailing_zeros
273 }
274
275 #[inline]
276 pub const fn is_empty(self) -> bool {
277 self.len() == 0
278 }
279
280 pub const fn split_at(self, mut mid: usize) -> (DigitsExp<'a>, DigitsExp<'a>) {
281 let mut first = DigitsExp::EMPTY;
282 let mut last = self;
283 if mid == 0 {
284 return (first, last);
285 }
286
287 if mid < self.leading_zeros {
288 (first.leading_zeros, last.leading_zeros) = (mid, self.leading_zeros - mid);
289 return (first, last);
290 }
291
292 (first.leading_zeros, last.leading_zeros) = (self.leading_zeros, 0);
293 mid -= self.leading_zeros;
294 if mid == 0 {
295 return (first, last);
296 }
297
298 if mid < self.part1.len() {
299 (first.part1, last.part1) = self.part1.split_at(mid);
300 return (first, last);
301 }
302
303 first.part1 = self.part1;
304 last.part1 = self.part2;
305 last.part2 = DigitsUnds::EMPTY;
306 mid -= self.part1.len();
307 if mid == 0 {
308 return (first, last);
309 }
310
311 if mid < self.part2.len() {
312 (first.part2, last.part1) = self.part2.split_at(mid);
313 return (first, last);
314 }
315
316 first.part2 = self.part2;
317 last.leading_zeros = self.trailing_zeros;
318 last.part1 = DigitsUnds::EMPTY;
319 last.trailing_zeros = 0;
320 mid -= self.part2.len();
321 if mid == 0 {
322 return (first, last);
323 }
324
325 if mid < self.trailing_zeros {
326 (first.trailing_zeros, last.leading_zeros) = (mid, self.trailing_zeros - mid);
327 return (first, last);
328 }
329
330 (first.trailing_zeros, last.leading_zeros) = (self.trailing_zeros, 0);
331 mid -= self.trailing_zeros;
332 if mid == 0 {
333 return (first, last);
334 }
335
336 panic!("index out of bounds");
337 }
338
339 #[inline]
341 pub const fn split_first(self) -> Option<(u8, DigitsExp<'a>)> {
342 if self.leading_zeros > 0 {
343 return Some((
344 b'0',
345 DigitsExp {
346 leading_zeros: self.leading_zeros - 1,
347 ..self
348 },
349 ));
350 }
351 if let Some((first, rest)) = self.part1.split_first() {
352 return Some((
353 first,
354 DigitsExp {
355 part1: rest,
356 ..self
357 },
358 ));
359 }
360 if let Some((first, rest)) = self.part2.split_first() {
361 return Some((
362 first,
363 DigitsExp {
364 part2: rest,
365 ..self
366 },
367 ));
368 }
369 if self.trailing_zeros > 0 {
370 return Some((
371 b'0',
372 DigitsExp {
373 trailing_zeros: self.trailing_zeros - 1,
374 ..self
375 },
376 ));
377 }
378 None
379 }
380}