1 //! Module containing parsers specialized on byte streams.
2
3 use crate::{
4 error::{self, ParseError, ParseResult::*},
5 parser::{
6 combinator::no_partial,
7 range::{take_fn, TakeRange},
8 repeat::skip_many,
9 token::{satisfy, token, tokens_cmp, Token},
10 },
11 stream::{RangeStream, Stream},
12 Parser,
13 };
14
15 /// Parses a byte and succeeds if the byte is equal to `c`.
16 ///
17 /// ```
18 /// use combine::Parser;
19 /// use combine::parser::byte::byte;
20 /// assert_eq!(byte(b'!').parse(&b"!"[..]), Ok((b'!', &b""[..])));
21 /// assert!(byte(b'A').parse(&b""[..]).is_err());
22 /// assert!(byte(b'A').parse(&b"!"[..]).is_err());
23 /// ```
byte<Input>(c: u8) -> Token<Input> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,24 pub fn byte<Input>(c: u8) -> Token<Input>
25 where
26 Input: Stream<Token = u8>,
27 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
28 {
29 token(c)
30 }
31
32 macro_rules! byte_parser {
33 ($name:ident, $ty:ident, $f: ident) => {{
34 satisfy(|c: u8| c.$f())
35 .expected(stringify!($name))
36 }};
37 ($name:ident, $ty:ident, $f: ident $($args:tt)+) => {{
38 satisfy(|c: u8| c.$f $($args)+)
39 .expected(stringify!($name))
40 }};
41 }
42
43 /// Parses a base-10 digit (0–9).
44 ///
45 /// ```
46 /// use combine::Parser;
47 /// use combine::parser::byte::digit;
48 /// assert_eq!(digit().parse(&b"9"[..]), Ok((b'9', &b""[..])));
49 /// assert!(digit().parse(&b"A"[..]).is_err());
50 /// ```
digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,51 pub fn digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
52 where
53 Input: Stream<Token = u8>,
54 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
55 {
56 byte_parser!(digit, Digit, is_ascii_digit())
57 }
58
59 /// Parses a `b' '`, `b'\t'`, `b'\n'` or `'b\'r'`.
60 ///
61 /// ```
62 /// use combine::Parser;
63 /// use combine::parser::byte::space;
64 /// assert_eq!(space().parse(&b" "[..]), Ok((b' ', &b""[..])));
65 /// assert_eq!(space().parse(&b" "[..]), Ok((b' ', &b" "[..])));
66 /// assert!(space().parse(&b"!"[..]).is_err());
67 /// assert!(space().parse(&b""[..]).is_err());
68 /// ```
space<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,69 pub fn space<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
70 where
71 Input: Stream<Token = u8>,
72 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
73 {
74 byte_parser!(space, Space, is_ascii_whitespace)
75 }
76
77 /// Skips over [`space`] zero or more times
78 ///
79 /// [`space`]: fn.space.html
80 ///
81 /// ```
82 /// use combine::Parser;
83 /// use combine::parser::byte::spaces;
84 /// assert_eq!(spaces().parse(&b""[..]), Ok(((), &b""[..])));
85 /// assert_eq!(spaces().parse(&b" "[..]), Ok(((), &b""[..])));
86 /// ```
spaces<Input>() -> impl Parser<Input, Output = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,87 pub fn spaces<Input>() -> impl Parser<Input, Output = ()>
88 where
89 Input: Stream<Token = u8>,
90 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
91 {
92 skip_many(space()).expected("whitespaces")
93 }
94
95 /// Parses a newline byte (`b'\n'`).
96 ///
97 /// ```
98 /// use combine::Parser;
99 /// use combine::parser::byte::newline;
100 /// assert_eq!(newline().parse(&b"\n"[..]), Ok((b'\n', &b""[..])));
101 /// assert!(newline().parse(&b"\r"[..]).is_err());
102 /// ```
newline<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,103 pub fn newline<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
104 where
105 Input: Stream<Token = u8>,
106 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
107 {
108 satisfy(|ch: u8| ch == b'\n').expected("lf newline")
109 }
110
111 /// Parses carriage return and newline (`&b"\r\n"`), returning the newline byte.
112 ///
113 /// ```
114 /// use combine::Parser;
115 /// use combine::parser::byte::crlf;
116 /// assert_eq!(crlf().parse(&b"\r\n"[..]), Ok((b'\n', &b""[..])));
117 /// assert!(crlf().parse(&b"\r"[..]).is_err());
118 /// assert!(crlf().parse(&b"\n"[..]).is_err());
119 /// ```
crlf<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,120 pub fn crlf<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
121 where
122 Input: Stream<Token = u8>,
123 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
124 {
125 no_partial(satisfy(|ch: u8| ch == b'\r').with(newline())).expected("crlf newline")
126 }
127
128 /// Parses a tab byte (`b'\t'`).
129 ///
130 /// ```
131 /// use combine::Parser;
132 /// use combine::parser::byte::tab;
133 /// assert_eq!(tab().parse(&b"\t"[..]), Ok((b'\t', &b""[..])));
134 /// assert!(tab().parse(&b" "[..]).is_err());
135 /// ```
tab<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,136 pub fn tab<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
137 where
138 Input: Stream<Token = u8>,
139 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
140 {
141 satisfy(|ch| ch == b'\t').expected("tab")
142 }
143
144 /// Parses an uppercase ASCII letter (A–Z).
145 ///
146 /// ```
147 /// use combine::Parser;
148 /// use combine::parser::byte::upper;
149 /// assert_eq!(upper().parse(&b"A"[..]), Ok((b'A', &b""[..])));
150 /// assert!(upper().parse(&b"a"[..]).is_err());
151 /// ```
upper<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,152 pub fn upper<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
153 where
154 Input: Stream<Token = u8>,
155 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
156 {
157 byte_parser!(upper, Upper, is_ascii_uppercase)
158 }
159
160 /// Parses an lowercase ASCII letter (a–z).
161 ///
162 /// ```
163 /// use combine::Parser;
164 /// use combine::parser::byte::lower;
165 /// assert_eq!(lower().parse(&b"a"[..]), Ok((b'a', &b""[..])));
166 /// assert!(lower().parse(&b"A"[..]).is_err());
167 /// ```
lower<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,168 pub fn lower<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
169 where
170 Input: Stream<Token = u8>,
171 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
172 {
173 byte_parser!(lower, Lower, is_ascii_lowercase)
174 }
175
176 /// Parses either an ASCII alphabet letter or digit (a–z, A–Z, 0–9).
177 ///
178 /// ```
179 /// use combine::Parser;
180 /// use combine::parser::byte::alpha_num;
181 /// assert_eq!(alpha_num().parse(&b"A"[..]), Ok((b'A', &b""[..])));
182 /// assert_eq!(alpha_num().parse(&b"1"[..]), Ok((b'1', &b""[..])));
183 /// assert!(alpha_num().parse(&b"!"[..]).is_err());
184 /// ```
alpha_num<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,185 pub fn alpha_num<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
186 where
187 Input: Stream<Token = u8>,
188 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
189 {
190 byte_parser!(alpha_num, AlphaNum, is_ascii_alphanumeric)
191 }
192
193 /// Parses an ASCII alphabet letter (a–z, A–Z).
194 ///
195 /// ```
196 /// use combine::Parser;
197 /// use combine::parser::byte::letter;
198 /// assert_eq!(letter().parse(&b"a"[..]), Ok((b'a', &b""[..])));
199 /// assert_eq!(letter().parse(&b"A"[..]), Ok((b'A', &b""[..])));
200 /// assert!(letter().parse(&b"9"[..]).is_err());
201 /// ```
letter<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,202 pub fn letter<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
203 where
204 Input: Stream<Token = u8>,
205 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
206 {
207 byte_parser!(letter, Letter, is_ascii_alphabetic)
208 }
209
210 /// Parses an octal digit.
211 ///
212 /// ```
213 /// use combine::Parser;
214 /// use combine::parser::byte::oct_digit;
215 /// assert_eq!(oct_digit().parse(&b"7"[..]), Ok((b'7', &b""[..])));
216 /// assert!(oct_digit().parse(&b"8"[..]).is_err());
217 /// ```
oct_digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,218 pub fn oct_digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
219 where
220 Input: Stream<Token = u8>,
221 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
222 {
223 satisfy(|ch| (b'0'..=b'7').contains(&ch)).expected("octal digit")
224 }
225
226 /// Parses an ASCII hexdecimal digit (accepts both uppercase and lowercase).
227 ///
228 /// ```
229 /// use combine::Parser;
230 /// use combine::parser::byte::hex_digit;
231 /// assert_eq!(hex_digit().parse(&b"F"[..]), Ok((b'F', &b""[..])));
232 /// assert!(hex_digit().parse(&b"H"[..]).is_err());
233 /// ```
hex_digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()> where Input: Stream<Token = u8>, Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,234 pub fn hex_digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
235 where
236 Input: Stream<Token = u8>,
237 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
238 {
239 byte_parser!(hex_digit, HexDigit, is_ascii_hexdigit())
240 }
241
242 parser! {
243 /// Parses the bytes `s`.
244 ///
245 /// If you have a stream implementing [`RangeStream`] such as `&[u8]` you can also use the
246 /// [`range`] parser which may be more efficient.
247 ///
248 /// ```
249 /// # extern crate combine;
250 /// # use combine::*;
251 /// # use combine::parser::byte::bytes;
252 /// # fn main() {
253 /// let result = bytes(&b"rust"[..])
254 /// .parse(&b"rust"[..])
255 /// .map(|x| x.0);
256 /// assert_eq!(result, Ok(&b"rust"[..]));
257 /// # }
258 /// ```
259 ///
260 /// [`RangeStream`]: super::super::stream::RangeStream
261 /// [`range`]: super::range::range
262 pub fn bytes['a, 'b, Input](s: &'static [u8])(Input) -> &'a [u8]
263 where [
264 Input: Stream<Token = u8, Range = &'b [u8]>,
265 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
266 ]
267 {
268 bytes_cmp(s, |l: u8, r: u8| l == r)
269 }
270 }
271
272 parser! {
273 /// Parses the bytes `s` using `cmp` to compare each token.
274 ///
275 /// If you have a stream implementing [`RangeStream`] such as `&[u8]` you can also use the
276 /// [`range`] parser which may be more efficient.
277 ///
278 /// ```
279 /// # extern crate combine;
280 /// # use combine::*;
281 /// # use combine::parser::byte::bytes_cmp;
282 /// # use combine::stream::easy::Info;
283 /// # fn main() {
284 /// let result = bytes_cmp(&b"abc"[..], |l, r| l.eq_ignore_ascii_case(&r))
285 /// .parse(&b"AbC"[..]);
286 /// assert_eq!(result, Ok((&b"abc"[..], &b""[..])));
287 /// # }
288 /// ```
289 ///
290 /// [`RangeStream`]: super::super::stream::RangeStream
291 /// [`range`]: super::range::range
292 pub fn bytes_cmp['a, 'b, C, Input](s: &'static [u8], cmp: C)(Input) -> &'a [u8]
293 where [
294 C: FnMut(u8, u8) -> bool,
295 Input: Stream<Token = u8, Range = &'b [u8]>,
296 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
297 ]
298 {
299 let s = *s;
300 tokens_cmp(s.iter().cloned(), cmp)
301 .map(move |_| s)
302 .expected(error::Range(s))
303 }
304 }
305
306 macro_rules! take_until {
307 (
308 $(#[$attr:meta])*
309 $type_name: ident, $func_name: ident, $memchr: ident, $($param: ident),+
310 ) => {
311 parser!{
312 #[derive(Clone)]
313 pub struct $type_name;
314 type PartialState = usize;
315 $(#[$attr])*
316 pub fn $func_name[Input]($($param : u8),*)(Input) -> Input::Range
317 where [
318 Input: RangeStream,
319 Input::Range: AsRef<[u8]> + crate::stream::Range,
320 ]
321 {
322 take_fn(move |haystack: Input::Range| {
323 let haystack = haystack.as_ref();
324 match ::memchr::$memchr( $(*$param),+ , haystack) {
325 Some(i) => TakeRange::Found(i),
326 None => TakeRange::NotFound(haystack.len()),
327 }
328 })
329 }
330 }
331 }
332 }
333
334 take_until! {
335 /// Zero-copy parser which reads a range of 0 or more tokens until `a` is found.
336 ///
337 /// If `a` is not found, the parser will return an error.
338 ///
339 /// ```
340 /// # extern crate combine;
341 /// # use combine::parser::byte::take_until_byte;
342 /// # use combine::*;
343 /// # fn main() {
344 /// let mut parser = take_until_byte(b'\r');
345 /// let result = parser.parse("To: user@example.com\r\n");
346 /// assert_eq!(result, Ok(("To: user@example.com", "\r\n")));
347 /// let result = parser.parse("Hello, world\n");
348 /// assert!(result.is_err());
349 /// # }
350 /// ```
351 TakeUntilByte, take_until_byte, memchr, a
352 }
353 take_until! {
354 /// Zero-copy parser which reads a range of 0 or more tokens until `a` or `b` is found.
355 ///
356 /// If `a` or `b` is not found, the parser will return an error.
357 ///
358 /// ```
359 /// # extern crate combine;
360 /// # use combine::parser::byte::take_until_byte2;
361 /// # use combine::*;
362 /// # fn main() {
363 /// let mut parser = take_until_byte2(b'\r', b'\n');
364 /// let result = parser.parse("To: user@example.com\r\n");
365 /// assert_eq!(result, Ok(("To: user@example.com", "\r\n")));
366 /// let result = parser.parse("Hello, world\n");
367 /// assert_eq!(result, Ok(("Hello, world", "\n")));
368 /// # }
369 /// ```
370 TakeUntilByte2, take_until_byte2, memchr2, a, b
371 }
372 take_until! {
373 /// Zero-copy parser which reads a range of 0 or more tokens until `a`, 'b' or `c` is found.
374 ///
375 /// If `a`, 'b' or `c` is not found, the parser will return an error.
376 ///
377 /// ```
378 /// # extern crate combine;
379 /// # use combine::parser::byte::take_until_byte3;
380 /// # use combine::*;
381 /// # fn main() {
382 /// let mut parser = take_until_byte3(b'\r', b'\n', b' ');
383 /// let result = parser.parse("To: user@example.com\r\n");
384 /// assert_eq!(result, Ok(("To:", " user@example.com\r\n")));
385 /// let result = parser.parse("Helloworld");
386 /// assert!(result.is_err());
387 /// # }
388 /// ```
389 TakeUntilByte3, take_until_byte3, memchr3, a, b, c
390 }
391
392 parser! {
393 type PartialState = usize;
394 /// Zero-copy parser which reads a range of 0 or more tokens until `needle` is found.
395 ///
396 /// If `a`, 'b' or `c` is not found, the parser will return an error.
397 ///
398 /// Optimized variant of [`take_until_range`](../range/fn.take_until_range.html)
399 ///
400 /// ```
401 /// use combine::*;
402 /// use combine::parser::byte::take_until_bytes;
403 /// assert_eq!(
404 /// take_until_bytes(&b"\r\n"[..]).easy_parse(&b"abc\r\n"[..]).map(|(x, _)| x),
405 /// Ok((&b"abc"[..]))
406 /// );
407 /// // Also works on strings as long as `needle` is UTF-8
408 /// assert_eq!(
409 /// take_until_bytes("\r\n".as_bytes()).easy_parse("abc\r\n").map(|(x, _)| x),
410 /// Ok(("abc"))
411 /// );
412 /// ```
413 pub fn take_until_bytes['a, Input](needle: &'a [u8])(Input) -> Input::Range
414 where [
415 Input: RangeStream,
416 Input::Range: AsRef<[u8]> + crate::stream::Range,
417 ]
418 {
419 take_fn(move |haystack: Input::Range| {
420 let haystack = haystack.as_ref();
421 match memslice(needle, haystack) {
422 Some(i) => TakeRange::Found(i),
423 None => TakeRange::NotFound(haystack.len().saturating_sub(needle.len() - 1)),
424 }
425 })
426 }
427
428 }
429
memslice(needle: &[u8], haystack: &[u8]) -> Option<usize>430 fn memslice(needle: &[u8], haystack: &[u8]) -> Option<usize> {
431 let (&prefix, suffix) = match needle.split_first() {
432 Some(x) => x,
433 None => return Some(0),
434 };
435 for i in memchr::memchr_iter(prefix, haystack) {
436 if haystack[i + 1..].starts_with(suffix) {
437 return Some(i);
438 }
439 }
440 None
441 }
442
443 /// Parsers for decoding numbers in big-endian or little-endian order.
444 pub mod num {
445
446 use crate::{error::ResultExt, lib::mem::size_of, parser::function::parser, stream::uncons};
447
448 use super::*;
449
450 macro_rules! integer_parser {
451 (
452 $(#[$attr:meta])*
453 pub $type_name: ident,
454 $output_type: ident, $be_name: ident, $le_name: ident, $read_name: ident
455 ) => {
456 $(#[$attr])*
457 pub fn $be_name<'a, Input>() -> impl Parser<Input, Output = $output_type, PartialState = ()>
458 where
459 Input: Stream<Token = u8>,
460 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
461 {
462 parser(|input: &mut Input| {
463 let checkpoint = input.checkpoint();
464 let result = (|input: &mut Input| {
465 let mut buffer = [0u8; size_of::<$output_type>()];
466 for elem in &mut buffer[..] {
467 *elem = ctry!(uncons(input)).0;
468 }
469 CommitOk($output_type::from_be_bytes(buffer))
470 })(input);
471 if result.is_err() {
472 input.reset(checkpoint).committed().into_result()?;
473 }
474 result.into_result()
475 })
476 }
477
478 $(#[$attr])*
479 pub fn $le_name<'a, Input>() -> impl Parser<Input, Output = $output_type, PartialState = ()>
480 where
481 Input: Stream<Token = u8>,
482 Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
483 {
484 parser(|input: &mut Input| {
485 let checkpoint = input.checkpoint();
486 let result = (|input: &mut Input| {
487 let mut buffer = [0u8; size_of::<$output_type>()];
488 for elem in &mut buffer[..] {
489 *elem = ctry!(uncons(input)).0;
490 }
491 CommitOk($output_type::from_le_bytes(buffer))
492 })(input);
493 if result.is_err() {
494 input.reset(checkpoint).committed().into_result()?;
495 }
496 result.into_result()
497 })
498 }
499 }
500 }
501
502 integer_parser!(
503 /// Reads a u16 out of the byte stream with the specified endianess
504 ///
505 /// ```
506 /// use combine::Parser;
507 /// use combine::parser::byte::num::le_u16;
508 ///
509 /// assert_eq!(le_u16().parse(&b"\x01\0"[..]), Ok((1, &b""[..])));
510 /// assert!(le_u16().parse(&b"\0"[..]).is_err());
511 /// ```
512 pub U16, u16, be_u16, le_u16, read_u16
513 );
514 integer_parser!(
515 /// Reads a u32 out of the byte stream with the specified endianess
516 ///
517 /// ```
518 /// use combine::Parser;
519 /// use combine::parser::byte::num::le_u32;
520 ///
521 /// assert_eq!(le_u32().parse(&b"\x01\0\0\0"[..]), Ok((1, &b""[..])));
522 /// assert!(le_u32().parse(&b"\x01\0\0"[..]).is_err());
523 /// ```
524 pub U32, u32, be_u32, le_u32, read_u32
525 );
526 integer_parser!(
527 /// Reads a u64 out of the byte stream with the specified endianess
528 ///
529 /// ```
530 /// use combine::Parser;
531 /// use combine::parser::byte::num::le_u64;
532 ///
533 /// assert_eq!(le_u64().parse(&b"\x01\0\0\0\0\0\0\0"[..]), Ok((1, &b""[..])));
534 /// assert!(le_u64().parse(&b"\x01\0\0\0\0\0\0"[..]).is_err());
535 /// ```
536 pub U64, u64, be_u64, le_u64, read_u64
537 );
538
539 integer_parser!(
540 /// Reads a i16 out of the byte stream with the specified endianess
541 ///
542 /// ```
543 /// use combine::Parser;
544 /// use combine::parser::byte::num::le_i16;
545 ///
546 /// assert_eq!(le_i16().parse(&b"\x01\0"[..]), Ok((1, &b""[..])));
547 /// assert!(le_i16().parse(&b"\x01"[..]).is_err());
548 /// ```
549 pub I16, i16, be_i16, le_i16, read_i16
550 );
551
552 integer_parser!(
553 /// Reads a i32 out of the byte stream with the specified endianess
554 ///
555 /// ```
556 /// use combine::Parser;
557 /// use combine::parser::byte::num::le_i32;
558 ///
559 /// assert_eq!(le_i32().parse(&b"\x01\0\0\0"[..]), Ok((1, &b""[..])));
560 /// assert!(le_i32().parse(&b"\x01\0\0"[..]).is_err());
561 /// ```
562 pub I32, i32, be_i32, le_i32, read_i32
563 );
564 integer_parser!(
565 /// Reads a i64 out of the byte stream with the specified endianess
566 ///
567 /// ```
568 /// use combine::Parser;
569 /// use combine::parser::byte::num::le_i64;
570 ///
571 /// assert_eq!(le_i64().parse(&b"\x01\0\0\0\0\0\0\0"[..]), Ok((1, &b""[..])));
572 /// assert!(le_i64().parse(&b"\x01\0\0\0\0\0\0"[..]).is_err());
573 /// ```
574 pub I64, i64, be_i64, le_i64, read_i64
575 );
576
577 integer_parser!(
578 /// Reads a i32 out of the byte stream with the specified endianess
579 ///
580 /// ```
581 /// use combine::Parser;
582 /// use combine::parser::byte::num::le_f32;
583 ///
584 /// let buf = 123.45f32.to_le_bytes();
585 /// assert_eq!(le_f32().parse(&buf[..]), Ok((123.45, &b""[..])));
586 /// assert!(le_f32().parse(&b"\x01\0\0"[..]).is_err());
587 /// ```
588 pub F32, f32, be_f32, le_f32, read_f32
589 );
590 integer_parser!(
591 /// Reads a i64 out of the byte stream with the specified endianess
592 ///
593 /// ```
594 /// use combine::Parser;
595 /// use combine::parser::byte::num::le_f64;
596 ///
597 /// let buf = 123.45f64.to_le_bytes();
598 /// assert_eq!(le_f64().parse(&buf[..]), Ok((123.45, &b""[..])));
599 /// assert!(le_f64().parse(&b"\x01\0\0\0\0\0\0"[..]).is_err());
600 /// ```
601 pub F64, f64, be_f64, le_f64, read_f64
602 );
603
604 #[cfg(all(feature = "std", test))]
605 mod tests {
606
607 use crate::stream::{buffered, position, IteratorStream};
608
609 use super::*;
610
611 #[test]
no_rangestream()612 fn no_rangestream() {
613 let buf = 123.45f64.to_le_bytes();
614 assert_eq!(
615 le_f64()
616 .parse(buffered::Stream::new(
617 position::Stream::new(IteratorStream::new(buf.iter().cloned())),
618 1
619 ))
620 .map(|(t, _)| t),
621 Ok(123.45)
622 );
623 assert_eq!(
624 le_f64()
625 .parse(buffered::Stream::new(
626 position::Stream::new(IteratorStream::new(buf.iter().cloned())),
627 1
628 ))
629 .map(|(t, _)| t),
630 Ok(123.45)
631 );
632 let buf = 123.45f64.to_be_bytes();
633 assert_eq!(
634 be_f64()
635 .parse(buffered::Stream::new(
636 position::Stream::new(IteratorStream::new(buf.iter().cloned())),
637 1
638 ))
639 .map(|(t, _)| t),
640 Ok(123.45)
641 );
642 }
643 }
644 }
645
646 #[cfg(all(feature = "std", test))]
647 mod tests {
648
649 use crate::stream::{buffered, position, read};
650
651 use super::*;
652
653 #[test]
memslice_basic()654 fn memslice_basic() {
655 let haystack = b"abc123";
656 assert_eq!(memslice(b"", haystack), Some(0));
657 assert_eq!(memslice(b"a", haystack), Some(0));
658 assert_eq!(memslice(b"ab", haystack), Some(0));
659 assert_eq!(memslice(b"c12", haystack), Some(2));
660
661 let haystack2 = b"abcab2";
662 assert_eq!(memslice(b"abc", haystack2), Some(0));
663 assert_eq!(memslice(b"ab2", haystack2), Some(3));
664
665 let haystack3 = b"aaabaaaa";
666 assert_eq!(memslice(b"aaaa", haystack3), Some(4));
667 }
668
669 #[test]
bytes_read_stream()670 fn bytes_read_stream() {
671 assert!(bytes(b"abc")
672 .parse(buffered::Stream::new(
673 position::Stream::new(read::Stream::new("abc".as_bytes())),
674 1
675 ))
676 .is_ok());
677 }
678 }
679