udled_tokenizers/
numeric.rs

1use alloc::string::ToString;
2use udled::{
3    tokenizers::{opt, Digit, Peek},
4    AsBytes, AsChar, AsSlice, AsStr, Buffer, Error, Item, Reader, Span, Tokenizer, TokenizerExt,
5};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8pub struct Integer;
9
10impl<'input, B> Tokenizer<'input, B> for Integer
11where
12    B: Buffer<'input>,
13    B::Item: AsChar,
14{
15    type Token = Item<i128>;
16
17    fn to_token<'a>(&self, reader: &mut Reader<'_, 'input, B>) -> Result<Self::Token, Error> {
18        let start = reader.position();
19        let mut val: i128 = 0;
20        let base = 10;
21
22        let sign = if reader.eat('-').is_ok() { -1 } else { 1 };
23
24        loop {
25            let ch = reader.parse(Digit(base))?;
26
27            val = (base as i128) * val + (ch.value as i128);
28
29            if !reader.is(Digit(base)) {
30                break;
31            }
32        }
33
34        return Ok(Item::new(Span::new(start, reader.position()), val * sign));
35    }
36
37    fn peek(&self, reader: &mut Reader<'_, 'input, B>) -> bool {
38        reader.is(Peek((opt('-'), Digit(10))))
39    }
40}
41
42#[derive(Debug, Clone, Copy, Default)]
43pub struct Float;
44
45impl<'input, B> Tokenizer<'input, B> for Float
46where
47    B: Buffer<'input>,
48    B::Item: AsChar,
49    B::Source: AsBytes<'input>,
50{
51    type Token = Item<f64>;
52
53    fn to_token<'a>(&self, reader: &mut Reader<'_, 'input, B>) -> Result<Self::Token, Error> {
54        let span = reader.parse(
55            (
56                Integer,
57                '.',
58                Digit(10).many(),
59                ('e'.or('E'), opt('-'), Digit(10).many()).optional(),
60            )
61                .spanned(),
62        )?;
63
64        let string = reader.buffer().source().as_bytes();
65        let string = unsafe { core::str::from_utf8_unchecked(string) };
66        let string = span.slice(string).unwrap();
67
68        let float: f64 = string
69            .parse()
70            .map_err(|err: core::num::ParseFloatError| reader.error(err.to_string()))?;
71
72        Ok(Item::new(span, float))
73    }
74
75    fn peek(&self, reader: &mut Reader<'_, 'input, B>) -> bool {
76        reader.is(Peek((Integer, '.')))
77    }
78}
79
80#[cfg(test)]
81mod test {
82    use udled::Input;
83
84    use super::{Float, Integer};
85
86    #[test]
87    fn integer() {
88        let mut input = Input::new("10203 0 42");
89
90        let (a, _, b, _, c) = input.parse((Integer, ' ', Integer, ' ', Integer)).unwrap();
91
92        assert_eq!(a.value, 10203);
93        assert_eq!(b.value, 0);
94        assert_eq!(c.value, 42);
95    }
96
97    // #[test]
98    // fn int() {
99    //     let mut input = Input::new("0x202 0b11 42");
100
101    //     let (a, _, b, _, c) = input.parse((Int, Ws, Int, Ws, Int)).unwrap();
102
103    //     assert_eq!(a.value, 0x202);
104    //     assert_eq!(b.value, 0b11);
105    //     assert_eq!(c.value, 42);
106    // }
107
108    #[test]
109    fn float() {
110        let mut input = Input::new("1.0000033 2003.303 12.03e-20");
111
112        let (a, _, b, _, c) = input.parse((Float, ' ', Float, ' ', Float)).unwrap();
113
114        assert_eq!(a.value, 1.0000033);
115        assert_eq!(b.value, 2003.303);
116        assert_eq!(c.value, 12.03e-20);
117    }
118}