konst/parsing/
primitive_parsing.rs

1use crate::string;
2
3use super::{ErrorKind, ParseDirection, ParseError, Parser};
4
5impl<'a> Parser<'a> {
6    /// Parses a `u128` until a non-digit is reached.
7    ///
8    /// This method mutates the parser in place on success, leaving it unmodified on error.
9    ///
10    /// To parse an integer from an entire string (erroring on non-digit bytes),
11    /// you can use [`u128::from_str_radix`]
12    ///
13    /// You also can use the [`parse_type`](crate::parsing::parse_type)
14    /// macro to parse a `u128`, and other [`HasParser`](crate::parsing::HasParser) types.
15    ///
16    /// # Example
17    ///
18    /// ```rust
19    /// use konst::{
20    ///     parsing::{Parser, ParseError},
21    ///     result, try_,
22    /// };
23    ///
24    /// {
25    ///     let mut parser = Parser::new("12345");
26    ///     let num = result::unwrap!(parser.parse_u128());
27    ///     assert_eq!(num, 12345);
28    ///     assert!(parser.is_empty());
29    /// }
30    ///
31    /// /// Parses a `[u128; 2]` from a parser starting with `"<number>;<number>", eg: `"100;400"`.
32    /// const fn parse_pair<'a>(parser: &mut Parser<'a>) -> Result<[u128; 2], ParseError<'a>> {
33    ///     let mut ret = [0; 2];
34    ///     
35    ///     ret[0] = try_!(parser.parse_u128());
36    ///     
37    ///     // parsing the `;``between the integers.
38    ///     //
39    ///     // Note that because we don't use `.trim_start()` afterwards,
40    ///     // this can't be followed by spaces.
41    ///     try_!(parser.strip_prefix(";"));
42    ///     
43    ///     ret[1] = try_!(parser.parse_u128());
44    ///     
45    ///     Ok(ret)
46    /// }
47    /// const PAIR: [u128; 2] = {
48    ///     let parser = &mut Parser::new("1365;6789");
49    ///     result::unwrap!(parse_pair(parser))
50    /// };
51    ///
52    /// assert_eq!(PAIR[0], 1365);
53    /// assert_eq!(PAIR[1], 6789);
54    ///
55    ///
56    /// ```
57    ///
58    pub const fn parse_u128(&mut self) -> Result<u128, ParseError<'a>> {
59        parse_integer! {unsigned, (u128, u128), self}
60    }
61    /// Parses a `i128` until a non-digit is reached.
62    ///
63    /// This method mutates the parser in place on success, leaving it unmodified on error.
64    ///
65    /// To parse an integer from an entire string (erroring on non-digit bytes),
66    /// you can use [`i128::from_str_radix`]
67    ///
68    /// You also can use the [`parse_type`](crate::parsing::parse_type)
69    /// macro to parse a `i128`, and other [`HasParser`](crate::parsing::HasParser) types.
70    ///
71    /// # Example
72    ///
73    /// ```rust
74    /// use konst::{Parser, result};
75    ///
76    /// {
77    ///     let mut parser = Parser::new("12345");
78    ///     let num = result::unwrap!(parser.parse_i128());
79    ///     assert_eq!(num, 12345);
80    ///     assert!(parser.is_empty());
81    /// }
82    /// {
83    ///     let mut parser = Parser::new("-54321;6789");
84    ///     
85    ///     assert_eq!(result::unwrap!(parser.parse_i128()), -54321);
86    ///     assert_eq!(parser.remainder(), ";6789");
87    ///
88    ///     _ = parser.strip_prefix(";");
89    ///     assert_eq!(parser.remainder(), "6789");
90    ///
91    ///     assert_eq!(result::unwrap!(parser.parse_i128()), 6789);
92    ///     assert!(parser.is_empty());
93    /// }
94    ///
95    /// ```
96    ///
97    pub const fn parse_i128(&mut self) -> Result<i128, ParseError<'a>> {
98        parse_integer! {signed, (i128, u128), self}
99    }
100    /// Parses a `u64` until a non-digit is reached.
101    ///
102    /// This method mutates the parser in place on success, leaving it unmodified on error.
103    ///
104    /// To parse an integer from an entire string (erroring on non-digit bytes),
105    /// you can use [`u64::from_str_radix`]
106    ///
107    /// You also can use the [`parse_type`](crate::parsing::parse_type)
108    /// macro to parse a `u64`, and other [`HasParser`](crate::parsing::HasParser) types.
109    ///
110    /// # Example
111    ///
112    /// For an example for how to use this method,
113    /// you can look at the docs for the [`Parser::parse_u128`](#method.parse_u128) method.
114    ///
115    pub const fn parse_u64(&mut self) -> Result<u64, ParseError<'a>> {
116        parse_integer! {unsigned, (u64, u64), self}
117    }
118    /// Parses a `i64` until a non-digit is reached.
119    ///
120    /// This method mutates the parser in place on success, leaving it unmodified on error.
121    ///
122    /// To parse an integer from an entire string (erroring on non-digit bytes),
123    /// you can use [`i64::from_str_radix`]
124    ///
125    /// You also can use the [`parse_type`](crate::parsing::parse_type)
126    /// macro to parse a `i64`, and other [`HasParser`](crate::parsing::HasParser) types.
127    ///
128    /// # Example
129    ///
130    /// For an example for how to use this method,
131    /// you can look at the docs for the [`Parser::parse_i128`](#method.parse_i128) method.
132    ///
133    pub const fn parse_i64(&mut self) -> Result<i64, ParseError<'a>> {
134        parse_integer! {signed, (i64, u64), self}
135    }
136    /// Parses a `u32` until a non-digit is reached.
137    ///
138    /// This method mutates the parser in place on success, leaving it unmodified on error.
139    ///
140    /// To parse an integer from an entire string (erroring on non-digit bytes),
141    /// you can use [`u32::from_str_radix`]
142    ///
143    /// You also can use the [`parse_type`](crate::parsing::parse_type)
144    /// macro to parse a `u32`, and other [`HasParser`](crate::parsing::HasParser) types.
145    ///
146    /// # Example
147    ///
148    /// For an example for how to use this method,
149    /// you can look at the docs for the [`Parser::parse_u128`](#method.parse_u128) method.
150    ///
151    pub const fn parse_u32(&mut self) -> Result<u32, ParseError<'a>> {
152        parse_integer! {unsigned, (u32, u32), self}
153    }
154    /// Parses a `i32` until a non-digit is reached.
155    ///
156    /// This method mutates the parser in place on success, leaving it unmodified on error.
157    ///
158    /// To parse an integer from an entire string (erroring on non-digit bytes),
159    /// you can use [`i32::from_str_radix`]
160    ///
161    /// You also can use the [`parse_type`](crate::parsing::parse_type)
162    /// macro to parse a `i32`, and other [`HasParser`](crate::parsing::HasParser) types.
163    ///
164    /// # Example
165    ///
166    /// For an example for how to use this method,
167    /// you can look at the docs for the [`Parser::parse_i128`](#method.parse_i128) method.
168    ///
169    pub const fn parse_i32(&mut self) -> Result<i32, ParseError<'a>> {
170        parse_integer! {signed, (i32, u32), self}
171    }
172    /// Parses a `u16` until a non-digit is reached.
173    ///
174    /// This method mutates the parser in place on success, leaving it unmodified on error.
175    ///
176    /// To parse an integer from an entire string (erroring on non-digit bytes),
177    /// you can use [`u16::from_str_radix`]
178    ///
179    /// You also can use the [`parse_type`](crate::parsing::parse_type)
180    /// macro to parse a `u16`, and other [`HasParser`](crate::parsing::HasParser) types.
181    ///
182    /// # Example
183    ///
184    /// For an example for how to use this method,
185    /// you can look at the docs for the [`Parser::parse_u128`](#method.parse_u128) method.
186    ///
187    pub const fn parse_u16(&mut self) -> Result<u16, ParseError<'a>> {
188        parse_integer! {unsigned, (u16, u16), self}
189    }
190    /// Parses a `i16` until a non-digit is reached.
191    ///
192    /// This method mutates the parser in place on success, leaving it unmodified on error.
193    ///
194    /// To parse an integer from an entire string (erroring on non-digit bytes),
195    /// you can use [`i16::from_str_radix`]
196    ///
197    /// You also can use the [`parse_type`](crate::parsing::parse_type)
198    /// macro to parse a `i16`, and other [`HasParser`](crate::parsing::HasParser) types.
199    ///
200    /// # Example
201    ///
202    /// For an example for how to use this method,
203    /// you can look at the docs for the [`Parser::parse_i128`](#method.parse_i128) method.
204    ///
205    pub const fn parse_i16(&mut self) -> Result<i16, ParseError<'a>> {
206        parse_integer! {signed, (i16, u16), self}
207    }
208    /// Parses a `u8` until a non-digit is reached.
209    ///
210    /// This method mutates the parser in place on success, leaving it unmodified on error.
211    ///
212    /// To parse an integer from an entire string (erroring on non-digit bytes),
213    /// you can use [`u8::from_str_radix`]
214    ///
215    /// You also can use the [`parse_type`](crate::parsing::parse_type)
216    /// macro to parse a `u8`, and other [`HasParser`](crate::parsing::HasParser) types.
217    ///
218    /// # Example
219    ///
220    /// For an example for how to use this method,
221    /// you can look at the docs for the [`Parser::parse_u128`](#method.parse_u128) method.
222    ///
223    pub const fn parse_u8(&mut self) -> Result<u8, ParseError<'a>> {
224        parse_integer! {unsigned, (u8, u8), self}
225    }
226    /// Parses a `i8` until a non-digit is reached.
227    ///
228    /// This method mutates the parser in place on success, leaving it unmodified on error.
229    ///
230    /// To parse an integer from an entire string (erroring on non-digit bytes),
231    /// you can use [`i8::from_str_radix`]
232    ///
233    /// You also can use the [`parse_type`](crate::parsing::parse_type)
234    /// macro to parse a `i8`, and other [`HasParser`](crate::parsing::HasParser) types.
235    ///
236    /// # Example
237    ///
238    /// For an example for how to use this method,
239    /// you can look at the docs for the [`Parser::parse_i128`](#method.parse_i128) method.
240    ///
241    pub const fn parse_i8(&mut self) -> Result<i8, ParseError<'a>> {
242        parse_integer! {signed, (i8, u8), self}
243    }
244    /// Parses a `usize` until a non-digit is reached.
245    ///
246    /// This method mutates the parser in place on success, leaving it unmodified on error.
247    ///
248    /// To parse an integer from an entire string (erroring on non-digit bytes),
249    /// you can use [`usize::from_str_radix`]
250    ///
251    /// You also can use the [`parse_type`](crate::parsing::parse_type)
252    /// macro to parse a `usize`, and other [`HasParser`](crate::parsing::HasParser) types.
253    ///
254    pub const fn parse_usize(&mut self) -> Result<usize, ParseError<'a>> {
255        parse_integer! {unsigned, (usize, usize), self}
256    }
257    /// Parses a `isize` until a non-digit is reached.
258    ///
259    /// This method mutates the parser in place on success, leaving it unmodified on error.
260    ///
261    /// To parse an integer from an entire string (erroring on non-digit bytes),
262    /// you can use [`isize::from_str_radix`]
263    ///
264    /// You also can use the [`parse_type`](crate::parsing::parse_type)
265    /// macro to parse a `isize`, and other [`HasParser`](crate::parsing::HasParser) types.
266    ///
267    /// # Example
268    ///
269    /// For an example for how to use this method,
270    /// you can look at the docs for the [`Parser::parse_i128`](#method.parse_i128) method.
271    ///
272    pub const fn parse_isize(&mut self) -> Result<isize, ParseError<'a>> {
273        parse_integer! {signed, (isize, usize), self}
274    }
275}
276
277macro_rules! parse_integer {
278    ($signedness:ident, ($type:ty, $uns:ty), $parser:ident) => (try_parsing! {
279        $parser, FromStart, ret;{
280            let mut num: $uns;
281
282            let mut bytes = $parser.str.as_bytes();
283
284            parse_integer! {@parse_signed $signedness, ($type, $uns), bytes, num, sign}
285
286            while let [byte @ b'0'..=b'9', rem @ ..] = bytes {
287                bytes = rem;
288
289                let (next_mul, overflowed_mul) = num.overflowing_mul(10);
290                let (next_add, overflowed_add) = next_mul.overflowing_add((*byte - b'0') as $uns);
291
292                if overflowed_mul | overflowed_add {
293                    throw!(ErrorKind::ParseInteger)
294                }
295
296                num = next_add;
297            }
298
299            parse_integer! {@apply_sign $signedness, ($type, $uns), num, sign}
300
301            $parser.str = string::str_from($parser.str, $parser.str.len() - bytes.len());
302
303            num
304        }
305    });
306    (@parse_signed signed, ($type:ty, $uns:ty), $bytes:ident, $num:ident, $isneg:ident) => {
307        let $isneg = if let [b'-', rem @ ..] = $bytes {
308            $bytes = rem;
309            true
310        } else {
311            false
312        };
313
314        parse_integer!(@parse_signed unsigned, ($type, $uns), $bytes, $num, $isneg)
315    };
316    (@parse_signed unsigned, ($type:ty, $uns:ty), $bytes:ident, $num:ident, $isneg:ident) => {
317        $num = if let [byte @ b'0'..=b'9', rem @ ..] = $bytes {
318            $bytes = rem;
319            (*byte - b'0') as $uns
320        } else {
321            throw!(ErrorKind::ParseInteger)
322        };
323    };
324    (@apply_sign signed, ($type:ty, $uns:ty), $num:ident, $isneg:ident) => {
325        const MAX_POS: $uns = <$type>::MAX as $uns;
326        const MAX_NEG: $uns = <$type>::MIN as $uns;
327
328        let $num = if $isneg {
329            if $num <= MAX_NEG {
330                ($num as $type).wrapping_neg()
331            } else {
332                throw!(ErrorKind::ParseInteger)
333            }
334        } else {
335            if $num <= MAX_POS {
336                $num as $type
337            } else {
338                throw!(ErrorKind::ParseInteger)
339            }
340        };
341    };
342    (@apply_sign unsigned, ($type:ty, $uns:ty), $num:ident, $isneg:ident) => {};
343}
344use parse_integer;
345
346////////////////////////////////////////////////////////////////////////////////
347
348impl<'a> Parser<'a> {
349    /// Parses a `bool`.
350    ///
351    /// This method mutates the parser in place on success, leaving it unmodified on error.
352    ///
353    /// To parse a bool from an entire string
354    /// (erroring if the string isn't exactly `"true"` or `"false"`),
355    /// you can use [`primitive::parse_bool`]
356    ///
357    /// You also can use the [`parse_type`](crate::parsing::parse_type)
358    /// macro to parse a `bool`, and other [`HasParser`](crate::parsing::HasParser) types.
359    ///
360    /// # Example
361    ///
362    /// ```rust
363    /// use konst::{Parser, result};
364    ///
365    /// {
366    ///     let mut parser = Parser::new("falsemorestring");
367    ///     let boolean = result::unwrap!(parser.parse_bool());
368    ///     assert_eq!(boolean, false);
369    ///     assert_eq!(parser.remainder(), "morestring");
370    /// }
371    /// {
372    ///     let mut parser = Parser::new("truefoo");
373    ///     let boolean = result::unwrap!(parser.parse_bool());
374    ///     assert_eq!(boolean, true);
375    ///     assert_eq!(parser.remainder(), "foo");
376    /// }
377    ///
378    /// ```
379    ///
380    /// [`primitive::parse_bool`]: crate::primitive::parse_bool
381    pub const fn parse_bool(&mut self) -> Result<bool, ParseError<'a>> {
382        try_parsing! {self, FromStart, ret;
383            match self.str.as_bytes() {
384                [b't', b'r', b'u', b'e', ..] => {
385                    self.str = string::str_from(self.str, 4);
386                    true
387                }
388                [b'f', b'a', b'l', b's', b'e', ..] => {
389                    self.str = string::str_from(self.str, 5);
390                    false
391                }
392                _ => throw!(ErrorKind::ParseBool),
393            }
394        }
395    }
396}