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}