kalosm_sample/structured_parser/
parse.rs

1use crate::{CreateParserState, SendCreateParserState, SeparatedParser};
2use crate::{
3    IntegerParser, LiteralParser, ParseStatus, Parser, ParserExt, SequenceParser, StringParser,
4};
5
6use super::Either;
7
8/// Data that can be parsed incrementally.
9///
10/// You can derive this trait for unit values, unit enums or structs or implement it manually for custom types.
11///
12/// # Example
13/// ```rust
14/// use kalosm_sample::*;
15///
16/// // You can derive parse for structs with named fields that implement Parse
17/// #[derive(Parse, Clone)]
18/// struct Person {
19///     name: String,
20///     favorite_color: Color,
21/// }
22///
23/// // You can derive parse for enums with only unit variants
24/// #[derive(Parse, Clone)]
25/// enum Color {
26///     Red,
27///     Blue,
28///     Green,
29///     Yellow,
30///     Orange,
31///     Purple,
32///     Pink,
33///     Black,
34/// }
35///
36/// // Or you can implement parse manually for custom types
37/// #[derive(Clone)]
38/// struct MyStruct(i64, String);
39///
40/// impl Parse for MyStruct {
41///     // The only method on parse is new_parser, which returns a parser that outputs the current type
42///     fn new_parser() -> impl kalosm_sample::SendCreateParserState<Output = Self> {
43///         let number_parser = i64::new_parser();
44///         let string_parser = StringParser::new(0..=usize::MAX);
45///         kalosm_sample::LiteralParser::new("MyStruct(")
46///             .ignore_output_then(number_parser)
47///             .then_literal(", ")
48///             .then(string_parser)
49///             .then_literal(")")
50///             .map_output(|(a, b)| Self(a, b))
51///     }
52/// }
53/// ```
54pub trait Parse: Clone + Send + Sync {
55    /// Create a new parser that parses the current type and can be sent between threads.
56    fn new_parser() -> impl SendCreateParserState<Output = Self>;
57}
58
59impl<T: Parse> Parse for Box<T> {
60    fn new_parser() -> impl SendCreateParserState<Output = Self> {
61        T::new_parser().map_output(Box::new)
62    }
63}
64
65macro_rules! int_parser {
66    ($ty:ident, $num:ty, $test:ident) => {
67        #[doc = "A parser for `"]
68        #[doc = stringify!($num)]
69        #[doc = "`."]
70        #[derive(Clone, Debug)]
71        pub struct $ty {
72            parser: IntegerParser,
73        }
74
75        impl $ty {
76            /// Create a new parser.
77            pub fn new() -> Self {
78                Self::default()
79            }
80
81            /// Set the range of the integers that this parser can parse.
82            pub fn with_range(mut self, range: std::ops::RangeInclusive<$num>) -> Self {
83                let start = range.start();
84                let end = range.end();
85                self.parser = IntegerParser::new(*start as i128..=*end as i128);
86                self
87            }
88        }
89
90        impl Default for $ty {
91            fn default() -> Self {
92                Self {
93                    parser: IntegerParser::new((<$num>::MIN as i128)..=(<$num>::MAX as i128)),
94                }
95            }
96        }
97
98        impl CreateParserState for $ty {
99            fn create_parser_state(&self) -> <Self as Parser>::PartialState {
100                self.parser.create_parser_state()
101            }
102        }
103
104        impl Parser for $ty {
105            type Output = $num;
106            type PartialState = <IntegerParser as Parser>::PartialState;
107
108            fn parse<'a>(
109                &self,
110                state: &Self::PartialState,
111                input: &'a [u8],
112            ) -> crate::ParseResult<ParseStatus<'a, Self::PartialState, Self::Output>> {
113                self.parser
114                    .parse(state, input)
115                    .map(|result| result.map(|output| output as $num))
116            }
117        }
118
119        impl Parse for $num {
120            fn new_parser() -> impl SendCreateParserState<Output = Self> {
121                $ty::default()
122            }
123        }
124
125        #[test]
126        fn $test() {
127            let parser = <$num as Parse>::new_parser();
128            let state = parser.create_parser_state();
129            for _ in 0..100 {
130                let input = rand::random::<$num>();
131                let input_str = input.to_string() + "\n";
132                println!("input: {:?}", input_str);
133                let result = parser.parse(&state, input_str.as_bytes());
134                if let ParseStatus::Finished {
135                    result: input,
136                    remaining: b"\n",
137                } = result.unwrap()
138                {
139                    assert_eq!(input, input);
140                } else {
141                    panic!("Parser did not finish");
142                }
143            }
144        }
145    };
146}
147
148int_parser!(U8Parser, u8, test_u8);
149int_parser!(U16Parser, u16, test_u16);
150int_parser!(U32Parser, u32, test_u32);
151int_parser!(U64Parser, u64, test_u64);
152int_parser!(I8Parser, i8, test_i8);
153int_parser!(I16Parser, i16, test_i16);
154int_parser!(I32Parser, i32, test_i32);
155int_parser!(I64Parser, i64, test_i64);
156
157impl Parse for String {
158    fn new_parser() -> impl SendCreateParserState<Output = Self> {
159        StringParser::new(0..=usize::MAX)
160    }
161}
162
163impl<T: Parse + Clone + Send + Sync> Parse for std::vec::Vec<T> {
164    fn new_parser() -> impl SendCreateParserState<Output = Self> {
165        SequenceParser::new(
166            LiteralParser::new("["),
167            SequenceParser::new(
168                SeparatedParser::new(T::new_parser(), LiteralParser::new(", "), 0..=usize::MAX),
169                LiteralParser::new("]"),
170            ),
171        )
172        .map_output(|((), (outputs, ()))| outputs)
173    }
174}
175
176impl<const N: usize, T: Parse + Clone + Send + Sync> Parse for [T; N] {
177    fn new_parser() -> impl SendCreateParserState<Output = Self> {
178        SequenceParser::new(
179            LiteralParser::new("["),
180            SequenceParser::new(
181                SeparatedParser::new(T::new_parser(), LiteralParser::new(", "), N..=N),
182                LiteralParser::new("]"),
183            ),
184        )
185        .map_output(|((), (outputs, ()))| {
186            outputs
187                .try_into()
188                .unwrap_or_else(|_| panic!("Array is not the correct size"))
189        })
190    }
191}
192
193impl<T: Parse> Parse for Option<T> {
194    fn new_parser() -> impl SendCreateParserState<Output = Self> {
195        let parser = T::new_parser();
196        parser
197            .map_output(|output| Some(output))
198            .or(LiteralParser::new("null").map_output(|_| None))
199    }
200}
201
202impl Parse for bool {
203    fn new_parser() -> impl SendCreateParserState<Output = Self> {
204        LiteralParser::new("true")
205            .otherwise(LiteralParser::new("false"))
206            .map_output(|output| matches!(output, Either::Left(_)))
207    }
208}