smt_scope/formatter/
parse.rs

1use std::str::FromStr;
2
3use crate::NonMaxU32;
4
5use super::{defns::*, defns_const::*, error::*};
6
7macro_rules! map_opt {
8    ($e:expr, $s:pat => $t:expr) => {
9        match $e {
10            Some($s) => Some($t),
11            None => None,
12        }
13    };
14    ($s:ident => $t:expr) => {
15        map_opt!($s, $s => $t)
16    };
17    ($e:expr, $s:pat => $t:expr, $d:expr) => {
18        match $e {
19            Some($s) => $t,
20            None => $d,
21        }
22    };
23    ($s:ident => $t:expr, $d:expr) => {
24        map_opt!($s, $s => $t, $d)
25    };
26    ($e:expr, Err($d:expr)) => {
27        match $e {
28            Some(s) => s,
29            None => return Err($d),
30        }
31    };
32}
33
34macro_rules! map_res {
35    ($e:expr) => {
36        map_res!($e, s => s, err => return Err(err))
37    };
38    ($e:expr, $err:ident => $f:expr) => {
39        map_res!($e, s => s, $err => return Err($f))
40    };
41    ($e:expr, $s:pat => $t:expr, $err:ident => $f:expr) => {
42        match $e {
43            Ok($s) => $t,
44            Err($err) => $f,
45        }
46    };
47}
48
49macro_rules! panic {
50    () => {
51        loop {
52            #[allow(unconditional_panic, clippy::out_of_bounds_indexing)]
53            [][0]
54        }
55    };
56}
57
58// Const parsing
59
60impl ChildIndex {
61    pub const fn parse(s: &str) -> ResultFormatterConst<'_, ([Option<Self>; 8], Self)> {
62        let tail = ConstOperations::strip_prefix(s, '#');
63        let s = map_opt!(tail, Err(ParseErrorConst::missing_hash(s)));
64        let rest = ConstOperations::split(s, ':');
65        let (_, mut last, mut rest) = rest.next::<false>();
66        let mut path: [Option<ChildIndex>; 8] = [None; 8];
67        let mut idx = 0;
68        while let Some(split) = rest {
69            path[idx] = Some(map_res!(Self::parse_single(last)));
70            idx += 1;
71            if idx >= 8 {
72                return Err(ParseErrorConst::too_many_children(s));
73            }
74            (_, last, rest) = split.next::<false>();
75        }
76        Ok((path, map_res!(Self::parse_single(last))))
77    }
78
79    pub const fn parse_single(s: &str) -> ResultFormatterConst<'_, Self> {
80        let index = map_res!(ConstOperations::parse_i32(s));
81        let index = map_opt!(
82            nonmax::NonMaxI32::new(index),
83            Err(ParseErrorConst::invalid_number(s))
84        );
85        Ok(Self(index))
86    }
87}
88
89impl ChildRange {
90    pub const fn parse(s: &str) -> ResultFormatterConst<'_, Self> {
91        let split = ConstOperations::split_2_first(s, '.', '.');
92        let (from, to) = map_opt!(split, Err(ParseErrorConst::missing_range(s)));
93        let (path, from) = map_res!(ChildIndex::parse(from));
94        let to = map_res!(ChildIndex::parse_single(to));
95        Ok(ChildRange { path, from, to })
96    }
97}
98
99impl BindPowerPair {
100    pub const fn parse(s: &str) -> ResultFormatterConst<'_, (bool, Self)> {
101        let split = ConstOperations::split(s, ',');
102        let (_, first, split) = split.next::<false>();
103        let first = map_res!(ConstOperations::parse_u32(first));
104        let (second, split) = ConstOperations::split_more(split);
105        let second = map_opt!(second => map_res!(ConstOperations::parse_u32(second)));
106        match (second, split) {
107            (.., Some(split)) => Err(ParseErrorConst::too_many_control(split)),
108            (None, ..) => Ok((false, BindPowerPair::symmetric(first))),
109            (Some(second), None) => Ok((true, BindPowerPair::asymmetric(first, second))),
110        }
111    }
112}
113
114impl SubFormatterSingle {
115    // `#x:y:a|n,m`
116    pub const fn parse(s: &str) -> ResultFormatterConst<'_, Self> {
117        let split = ConstOperations::split(s, SEPARATOR_CHARACTER);
118        let (_, index, split) = split.next::<false>();
119        let (path, index) = map_res!(ChildIndex::parse(index));
120        let bind_power = map_opt!(
121            split => map_res!(BindPowerPair::parse(split.remainder())).1,
122            BindPowerPair::symmetric(DEFAULT_BIND_POWER)
123        );
124        Ok(Self {
125            path,
126            index,
127            bind_power,
128        })
129    }
130}
131
132impl<'a> SubFormatterRepeatConst<'a> {
133    pub const fn parse(s: &'a str) -> ResultFormatterConst<'a, Self> {
134        let split = ConstOperations::split(s, CONTROL_CHARACTER);
135        let (_, left, sep) = split.next::<false>();
136
137        // $(`#x:y:a..b|n|m,o,|p`$
138        let left = ConstOperations::split(left, SEPARATOR_CHARACTER);
139        let (_, range, split) = left.next::<false>();
140        let range = map_res!(ChildRange::parse(range));
141        let (left, middle, right) = map_res!(Self::parse_triple(split));
142
143        // $`(|, |)`)$
144        let mut left_sep = SubFormatterRepeatSeparator::default();
145        let mut middle_sep = SubFormatterRepeatSeparator::default();
146        let mut right_sep = SubFormatterRepeatSeparator::default();
147        if let Some(sep) = sep {
148            let sep = ConstOperations::split(sep.remainder(), SEPARATOR_CHARACTER);
149            let (separator_deduplicate, separator, sep) = sep.next::<true>();
150            if let Some(sep_two) = sep {
151                left_sep.separator_deduplicate = separator_deduplicate;
152                left_sep.separator = separator;
153                let (separator_deduplicate, separator, sep) = sep_two.next::<true>();
154                let sep =
155                    map_opt!(sep => sep, return Err(ParseErrorConst::too_many_control(sep_two)));
156                middle_sep.separator_deduplicate = separator_deduplicate;
157                middle_sep.separator = separator;
158                let (separator_deduplicate, separator, sep) = sep.next::<true>();
159                #[allow(unreachable_code, clippy::diverging_sub_expression)]
160                {
161                    map_opt!(sep => return Err(ParseErrorConst::too_many_control(sep)));
162                }
163                right_sep.separator_deduplicate = separator_deduplicate;
164                right_sep.separator = separator;
165            } else {
166                middle_sep.separator_deduplicate = separator_deduplicate;
167                middle_sep.separator = separator;
168            }
169        }
170        Ok(Self {
171            range,
172            left_sep,
173            middle_sep,
174            right_sep,
175            left,
176            middle,
177            right,
178        })
179    }
180    /// Could have any of: ``, `n`, `n,n`, `n|n`, `n,n|n`, `n|n,n`, `n|n|n`, `n|n,n|n`
181    const fn parse_triple(
182        split: Option<ConstSplit<'a, 1>>,
183    ) -> ResultFormatterConst<'a, (BindPower, BindPowerPair, BindPower)> {
184        const DEFAULT: BindPowerPair = BindPowerPair::symmetric(DEFAULT_BIND_POWER);
185        let split =
186            map_opt!(split => split, return Ok((DEFAULT_BIND_POWER, DEFAULT, DEFAULT_BIND_POWER)));
187        let (_, first, split) = split.next::<false>();
188        let (pair, fst) = map_res!(BindPowerPair::parse(first));
189        if pair {
190            // `n,n` or `n,n|n`
191            let split =
192                map_opt!(split => split, return Ok((DEFAULT_BIND_POWER, fst, DEFAULT_BIND_POWER)));
193            let (_, second, split) = split.next::<false>();
194            #[allow(unreachable_code, clippy::diverging_sub_expression)]
195            {
196                map_opt!(split => return Err(ParseErrorConst::too_many_control(split)));
197            }
198            let (pair, snd) = map_res!(BindPowerPair::parse(second));
199            return if pair {
200                Err(ParseErrorConst::unexpected_pair(second))
201            } else {
202                // snd.left == snd.right
203                let snd = snd.left;
204                Ok((DEFAULT_BIND_POWER, fst, snd))
205            };
206        }
207        // fst.left == fst.right
208        let split = map_opt!(split => split, return Ok((fst.left, fst, fst.right)));
209        let fst = fst.left;
210        // `n|n`, `n|n,n`, `n|n|n` or `n|n,n|n`
211        let (_, second, split) = split.next::<false>();
212        let (pair, snd) = map_res!(BindPowerPair::parse(second));
213        let split = map_opt!(split => split, return Ok(if pair {
214            (fst, snd, DEFAULT_BIND_POWER)
215        } else {
216            // snd.left == snd.right
217            let snd = snd.left;
218            (fst, DEFAULT, snd)
219        }));
220        // `n|n|n` or `n|n,n|n`
221        let (_, third, split) = split.next::<false>();
222        #[allow(unreachable_code, clippy::diverging_sub_expression)]
223        {
224            map_opt!(split => return Err(ParseErrorConst::too_many_control(split)));
225        }
226        let (pair, thrd) = map_res!(BindPowerPair::parse(third));
227        if pair {
228            Err(ParseErrorConst::unexpected_pair(third))
229        } else {
230            // thrd.left == thrd.right
231            let thrd = thrd.left;
232            Ok((fst, snd, thrd))
233        }
234    }
235}
236
237impl<'a> SubFormatterConst<'a> {
238    pub const fn parse_control(s: &'a str) -> ResultFormatterConst<'a, (Self, &'a str)> {
239        if let Some(s) = ConstOperations::strip_prefix(s, '[') {
240            let split = ConstOperations::split_2(s, ']', CONTROL_CHARACTER);
241            let (_, control, split) = split.next::<false>();
242            let split = map_opt!(split, Err(ParseErrorConst::missing_control(s, "]$")));
243            let control = map_res!(SubFormatterSingle::parse(control));
244            return Ok((Self::Single(control), split.remainder()));
245        }
246        if let Some(s) = ConstOperations::strip_prefix(s, '(') {
247            let split = ConstOperations::split_2(s, ')', CONTROL_CHARACTER);
248            let (_, control, split) = split.next::<false>();
249            let split = map_opt!(split, Err(ParseErrorConst::missing_control(s, ")$")));
250            let control = map_res!(SubFormatterRepeatConst::parse(control));
251            return Ok((Self::Repeat(control), split.remainder()));
252        }
253        if let Some(s) = ConstOperations::strip_prefix(s, '{') {
254            let split = ConstOperations::split_2(s, '}', CONTROL_CHARACTER);
255            let (_, inner, split) = split.next::<false>();
256            let split = map_opt!(split, Err(ParseErrorConst::missing_control(s, "}$")));
257            let capture = map_res!(ConstOperations::parse_u32(inner));
258            if capture >= i32::MIN as u32 {
259                return Err(ParseErrorConst::capture_overflow(inner));
260            }
261            let capture = map_opt!(NonMaxU32::new(capture), s => s, panic!());
262            return Ok((Self::Capture(capture), split.remainder()));
263        }
264        Err(ParseErrorConst::incorrect_control(s))
265    }
266    pub const fn parse_one(s: &'a str) -> SubFormatterConstParseOneResult<'a> {
267        let split = ConstOperations::split(s, CONTROL_CHARACTER);
268        let (control_deduplicate, first, rest) = split.next::<true>();
269        let first = if first.is_empty() {
270            None
271        } else {
272            Some(SubFormatterString {
273                data: first,
274                control_deduplicate,
275            })
276        };
277        let rest = map_opt!(rest => map_res!(Self::parse_control(rest.remainder())));
278        Ok((first, rest))
279    }
280}
281
282pub type SubFormatterConstParseOneResult<'a> = ResultFormatterConst<
283    'a,
284    (
285        Option<SubFormatterString<'a>>,
286        Option<(SubFormatterConst<'a>, &'a str)>,
287    ),
288>;
289
290impl<'a> FormatterConst<'a> {
291    const INIT: Option<SubFormatterConst<'a>> = None;
292    pub const fn parse(full: &'a str) -> ResultFormatterConst<'a, Self> {
293        let mut s = full;
294        let mut bind_power = BindPowerPair::symmetric(DEFAULT_BIND_POWER);
295        if let Some(rest) = ConstOperations::strip_prefix(s, CONTROL_CHARACTER) {
296            let (left, rest) = map_opt!(
297                ConstOperations::split_first(rest, CONTROL_CHARACTER),
298                Err(ParseErrorConst::missing_control(rest, "$"))
299            );
300            let left = map_res!(ConstOperations::parse_u32(left));
301            bind_power.left = left;
302            s = rest;
303        }
304        if let Some(rest) = ConstOperations::strip_suffix(s, CONTROL_CHARACTER) {
305            let (right, rest) = map_opt!(
306                ConstOperations::split_last(rest, CONTROL_CHARACTER),
307                Err(ParseErrorConst::missing_control(rest, "$"))
308            );
309            let right = map_res!(ConstOperations::parse_u32(right));
310            bind_power.right = right;
311            s = rest;
312        }
313
314        let mut outputs = [Self::INIT; 64];
315        let mut idx = 0;
316        loop {
317            let (str, ctrl) = map_res!(SubFormatterConst::parse_one(s));
318            if let Some(str) = str {
319                outputs[idx] = Some(SubFormatterConst::String(str));
320                idx += 1;
321            }
322            let Some((ctrl, rest)) = ctrl else {
323                break;
324            };
325            outputs[idx] = Some(ctrl);
326            idx += 1;
327            s = rest;
328        }
329        Ok(Self {
330            bind_power,
331            outputs,
332        })
333    }
334}
335
336impl<'a> MatcherConst<'a> {
337    pub const fn parse(s: &'a str) -> ResultMatcherConst<'a, Self> {
338        let (s, children) = map_res!(Self::parse_children(s));
339        let regex = map_opt!(ConstOperations::strip_prefix(s, '/'), s => ConstOperations::strip_suffix(s, '/'), None);
340        let (data, kind) = if let Some(regex) = regex {
341            (regex, MatcherKindConst::Regex)
342        } else {
343            (s, MatcherKindConst::Exact)
344        };
345        Ok(Self {
346            data,
347            children,
348            kind,
349        })
350    }
351    pub const fn parse_children(
352        s: &'a str,
353    ) -> ResultMatcherConst<'a, (&'a str, Option<NonMaxU32>)> {
354        let mut has_bracket = true;
355        let s = map_opt!(ConstOperations::strip_prefix(s, '('), s => s, { has_bracket = false; s });
356        let mut s = match ConstOperations::strip_suffix(s, ')') {
357            Some(s) if has_bracket => s,
358            None if !has_bracket => return Ok((s, None)),
359            Some(s) => return Err(ParseErrorConst::invalid_children_spec(s)),
360            None => return Err(ParseErrorConst::invalid_children_spec(s)),
361        };
362        let mut children = NonMaxU32::ZERO;
363        while let Some(rest) = ConstOperations::strip_suffix(s, '_') {
364            let Some(rest) = ConstOperations::strip_suffix(rest, ' ') else {
365                break;
366            };
367            let new = NonMaxU32::new(children.get() + 1);
368            children = map_opt!(new, Err(ParseErrorConst::invalid_children_spec(s)));
369            s = rest;
370        }
371        Ok((s, Some(children)))
372    }
373}
374
375impl<'a> TermDisplayConst<'a> {
376    pub const fn parse(m: &'a str, f: &'a str) -> ResultConst<'a, Self> {
377        let matcher = map_res!(MatcherConst::parse(m), err => ParseErrorConst::matcher(err));
378        let formatter = map_res!(FormatterConst::parse(f), err => ParseErrorConst::formatter(err));
379        if matches!(matcher.kind, MatcherKindConst::Exact) && formatter.max_capture().is_some() {
380            return Err(ParseErrorConst::invalid_capture(m));
381        }
382        Ok(Self { matcher, formatter })
383    }
384}
385
386// Non-const parsing
387
388impl FromStr for ChildIndex {
389    type Err = FormatterParseError;
390    fn from_str(s: &str) -> Result<Self, Self::Err> {
391        Ok(Self::parse_single(s)?)
392    }
393}
394
395impl FromStr for ChildRange {
396    type Err = FormatterParseError;
397    fn from_str(s: &str) -> Result<Self, Self::Err> {
398        Ok(Self::parse(s)?)
399    }
400}
401
402impl FromStr for SubFormatterSingle {
403    type Err = FormatterParseError;
404    fn from_str(s: &str) -> Result<Self, Self::Err> {
405        Ok(Self::parse(s)?)
406    }
407}
408
409impl FromStr for SubFormatterRepeat {
410    type Err = FormatterParseError;
411    fn from_str(s: &str) -> Result<Self, Self::Err> {
412        let self_ = SubFormatterRepeatConst::parse(s)?;
413        self_.try_into()
414    }
415}
416
417impl FromStr for Formatter {
418    type Err = FormatterParseError;
419    fn from_str(s: &str) -> Result<Self, Self::Err> {
420        FormatterConst::parse(s)?.try_into()
421    }
422}
423
424impl FromStr for FallbackFormatter {
425    type Err = FallbackParseError;
426    fn from_str(s: &str) -> Result<Self, Self::Err> {
427        FallbackFormatter::new(s.parse().map_err(FallbackParseError::FormatterParseError)?)
428    }
429}
430
431impl FromStr for Matcher {
432    type Err = ConversionError;
433    fn from_str(s: &str) -> Result<Self, Self::Err> {
434        Ok(MatcherConst::parse(s)
435            .map_err(ParseError::from)?
436            .try_into()?)
437    }
438}
439
440// Helpers for const parsing
441
442#[derive(Debug, Clone, Copy)]
443pub(super) struct ConstSplit<'a, const N: usize>(&'a str, [u8; N]);
444
445struct Check<const SKIP_DOUBLE: bool, const N: usize>;
446impl<const SKIP_DOUBLE: bool, const N: usize> Check<SKIP_DOUBLE, N> {
447    #[allow(clippy::no_effect)]
448    const CHECK_N_SIZE: () = {
449        ["N must be 1 or 2"][!(N == 1 || N == 2) as usize];
450        ["N must be 1 when SKIP_DOUBLE"][!(N == 1 || !SKIP_DOUBLE) as usize];
451    };
452}
453
454impl<'a, const N: usize> ConstSplit<'a, N> {
455    #[allow(path_statements, clippy::no_effect)]
456    const fn next<const SKIP_DOUBLE: bool>(self) -> (bool, &'a str, Option<Self>) {
457        Check::<SKIP_DOUBLE, N>::CHECK_N_SIZE;
458
459        let full = self.0.as_bytes();
460        let mut s = full;
461        let mut skipped = false;
462        let mut idx = 0;
463        let reached_sep = loop {
464            match s {
465                [] => break None,
466                [b, n, r @ ..] if N == 1 && SKIP_DOUBLE && *b == self.1[0] && *n == self.1[0] => {
467                    skipped = true;
468                    idx += 2;
469                    s = r;
470                }
471                [b, r @ ..] if N == 1 => {
472                    s = r;
473                    if *b == self.1[0] {
474                        break Some(idx);
475                    }
476                    idx += 1;
477                }
478                [_] if N >= 2 => break None,
479                [b1, r @ ..] if N >= 2 => {
480                    s = r;
481                    if *b1 == self.1[0] {
482                        let [b2, r @ ..] = r else { panic!() };
483                        if *b2 == self.1[1] {
484                            s = r;
485                            break Some(idx);
486                        }
487                    }
488                    idx += 1;
489                }
490                _ => panic!(),
491            }
492        };
493        match reached_sep {
494            Some(reached_sep) => {
495                let (part, _) = full.split_at(reached_sep);
496                let part = unsafe { std::str::from_utf8_unchecked(part) };
497                let rest = unsafe { std::str::from_utf8_unchecked(s) };
498                (skipped, part, Some(ConstSplit(rest, self.1)))
499            }
500            None => (skipped, self.0, None),
501        }
502    }
503    #[allow(path_statements, clippy::no_effect)]
504    const fn prev<const SKIP_DOUBLE: bool>(self) -> (bool, &'a str, Option<Self>) {
505        Check::<SKIP_DOUBLE, N>::CHECK_N_SIZE;
506
507        let full = self.0.as_bytes();
508        let mut s = full;
509        let mut skipped = false;
510        let mut idx = s.len();
511        let reached_sep = loop {
512            match s {
513                [] => break None,
514                [r @ .., b, n] if N == 1 && SKIP_DOUBLE && *b == self.1[0] && *n == self.1[0] => {
515                    skipped = true;
516                    idx -= 2;
517                    s = r;
518                }
519                [r @ .., b] if N == 1 => {
520                    s = r;
521                    if *b == self.1[0] {
522                        break Some(idx);
523                    }
524                    idx -= 1;
525                }
526                [_] if N >= 2 => break None,
527                [r @ .., b2] if N >= 2 => {
528                    s = r;
529                    if *b2 == self.1[1] {
530                        let [r @ .., b1] = r else { panic!() };
531                        if *b1 == self.1[1] {
532                            s = r;
533                            break Some(idx);
534                        }
535                    }
536                    idx -= 1;
537                }
538                _ => panic!(),
539            }
540        };
541        match reached_sep {
542            Some(reached_sep) => {
543                let (_, part) = full.split_at(reached_sep);
544                let part = unsafe { std::str::from_utf8_unchecked(part) };
545                let rest = unsafe { std::str::from_utf8_unchecked(s) };
546                (skipped, part, Some(ConstSplit(rest, self.1)))
547            }
548            None => (skipped, self.0, None),
549        }
550    }
551    pub(super) const fn remainder(self) -> &'a str {
552        self.0
553    }
554}
555impl ConstSplit<'_, 1> {
556    pub(super) const fn control(self) -> char {
557        self.1[0] as char
558    }
559}
560
561struct ConstOperations;
562impl ConstOperations {
563    #[allow(clippy::unnecessary_operation)]
564    const fn char_as_ascii(c: char) -> u8 {
565        ["Character must be an ASCII byte"][!c.is_ascii() as usize];
566        c as u8
567    }
568
569    const fn strip_prefix(s: &str, prefix: char) -> Option<&str> {
570        let prefix = Self::char_as_ascii(prefix);
571        match s.as_bytes() {
572            [b, s @ ..] if *b == prefix => Some(unsafe { std::str::from_utf8_unchecked(s) }),
573            _ => None,
574        }
575    }
576    const fn strip_suffix(s: &str, suffix: char) -> Option<&str> {
577        let suffix = Self::char_as_ascii(suffix);
578        match s.as_bytes() {
579            [s @ .., b] if *b == suffix => Some(unsafe { std::str::from_utf8_unchecked(s) }),
580            _ => None,
581        }
582    }
583
584    const fn split(s: &str, sep: char) -> ConstSplit<'_, 1> {
585        let sep = Self::char_as_ascii(sep);
586        ConstSplit(s, [sep])
587    }
588    const fn split_2(s: &str, sep1: char, sep2: char) -> ConstSplit<'_, 2> {
589        let sep1 = Self::char_as_ascii(sep1);
590        let sep2 = Self::char_as_ascii(sep2);
591        ConstSplit(s, [sep1, sep2])
592    }
593
594    const fn split_more<const N: usize>(
595        s: Option<ConstSplit<'_, N>>,
596    ) -> (Option<&str>, Option<ConstSplit<'_, N>>) {
597        map_opt!(s => {
598            let (_, part, split) = s.next::<false>();
599            (Some(part), split)
600        }, (None, None))
601    }
602    const fn split_first(s: &'_ str, sep: char) -> Option<(&'_ str, &'_ str)> {
603        let split = Self::split(s, sep);
604        let (_, first, split) = split.next::<false>();
605        map_opt!(split => (first, split.remainder()))
606    }
607    const fn split_last(s: &'_ str, sep: char) -> Option<(&'_ str, &'_ str)> {
608        let split = Self::split(s, sep);
609        let (_, last, split) = split.prev::<false>();
610        map_opt!(split => (last, split.remainder()))
611    }
612    const fn split_2_first(s: &'_ str, sep1: char, sep2: char) -> Option<(&'_ str, &'_ str)> {
613        let split = Self::split_2(s, sep1, sep2);
614        let (_, first, split) = split.next::<false>();
615        map_opt!(split => (first, split.remainder()))
616    }
617
618    const fn parse_i32(full: &str) -> ResultFormatterConst<'_, i32> {
619        let neg = Self::strip_prefix(full, '-');
620        let is_neg = neg.is_some();
621        let s = map_opt!(neg => neg, full);
622        if s.is_empty() {
623            return Err(ParseErrorConst::invalid_number(full));
624        }
625        let leading_zero = Self::strip_prefix(s, '0');
626        if let Some(leading_zero) = leading_zero {
627            return if is_neg || !leading_zero.is_empty() {
628                Err(ParseErrorConst::invalid_number(s))
629            } else {
630                Ok(0)
631            };
632        }
633        let mut s = s.as_bytes();
634
635        let mut num = 0;
636        while !s.is_empty() {
637            match s {
638                [b @ b'0'..=b'9', r @ ..] => {
639                    num *= 10;
640                    let delta = (*b - b'0') as i32;
641                    if is_neg {
642                        num -= delta;
643                    } else {
644                        num += delta;
645                    }
646                    s = r;
647                }
648                _ => {
649                    let s = unsafe { std::str::from_utf8_unchecked(s) };
650                    return Err(ParseErrorConst::invalid_number(s));
651                }
652            }
653        }
654        Ok(num)
655    }
656    const fn parse_u32(full: &str) -> ResultFormatterConst<'_, u32> {
657        let data = map_res!(Self::parse_i32(full));
658        Ok(data as u32)
659    }
660}