]> git.proxmox.com Git - rustc.git/blob - vendor/nom8/src/bits/mod.rs
New upstream version 1.70.0+dfsg2
[rustc.git] / vendor / nom8 / src / bits / mod.rs
1 //! Bit level parsers
2 //!
3
4 pub mod complete;
5 pub mod streaming;
6 #[cfg(test)]
7 mod tests;
8
9 use crate::error::{ErrorKind, ParseError};
10 use crate::input::{ErrorConvert, InputIsStreaming, InputIter, InputLength, Slice, ToUsize};
11 use crate::lib::std::ops::{AddAssign, RangeFrom, Shl, Shr};
12 use crate::{Err, IResult, Needed, Parser};
13
14 /// Converts a byte-level input to a bit-level input, for consumption by a parser that uses bits.
15 ///
16 /// Afterwards, the input is converted back to a byte-level parser, with any remaining bits thrown
17 /// away.
18 ///
19 /// # Example
20 /// ```
21 /// use nom8::bits::{bits, take};
22 /// use nom8::error::Error;
23 /// use nom8::IResult;
24 ///
25 /// fn parse(input: &[u8]) -> IResult<&[u8], (u8, u8)> {
26 /// bits::<_, _, Error<(&[u8], usize)>, _, _>((take(4usize), take(8usize)))(input)
27 /// }
28 ///
29 /// let input = &[0x12, 0x34, 0xff, 0xff];
30 ///
31 /// let output = parse(input).expect("We take 1.5 bytes and the input is longer than 2 bytes");
32 ///
33 /// // The first byte is consumed, the second byte is partially consumed and dropped.
34 /// let remaining = output.0;
35 /// assert_eq!(remaining, [0xff, 0xff]);
36 ///
37 /// let parsed = output.1;
38 /// assert_eq!(parsed.0, 0x01);
39 /// assert_eq!(parsed.1, 0x23);
40 /// ```
41 pub fn bits<I, O, E1, E2, P>(mut parser: P) -> impl FnMut(I) -> IResult<I, O, E2>
42 where
43 E1: ParseError<(I, usize)> + ErrorConvert<E2>,
44 E2: ParseError<I>,
45 I: Slice<RangeFrom<usize>>,
46 P: Parser<(I, usize), O, E1>,
47 {
48 move |input: I| match parser.parse((input, 0)) {
49 Ok(((rest, offset), result)) => {
50 // If the next byte has been partially read, it will be sliced away as well.
51 // The parser functions might already slice away all fully read bytes.
52 // That's why `offset / 8` isn't necessarily needed at all times.
53 let remaining_bytes_index = offset / 8 + if offset % 8 == 0 { 0 } else { 1 };
54 Ok((rest.slice(remaining_bytes_index..), result))
55 }
56 Err(Err::Incomplete(n)) => Err(Err::Incomplete(n.map(|u| u.get() / 8 + 1))),
57 Err(Err::Error(e)) => Err(Err::Error(e.convert())),
58 Err(Err::Failure(e)) => Err(Err::Failure(e.convert())),
59 }
60 }
61
62 /// Counterpart to `bits`, `bytes` transforms its bit stream input into a byte slice for the underlying
63 /// parser, allowing byte-slice parsers to work on bit streams.
64 ///
65 /// A partial byte remaining in the input will be ignored and the given parser will start parsing
66 /// at the next full byte.
67 ///
68 /// ```
69 /// use nom8::bits::{bits, bytes, take};
70 /// use nom8::combinator::rest;
71 /// use nom8::error::Error;
72 /// use nom8::IResult;
73 ///
74 /// fn parse(input: &[u8]) -> IResult<&[u8], (u8, u8, &[u8])> {
75 /// bits::<_, _, Error<(&[u8], usize)>, _, _>((
76 /// take(4usize),
77 /// take(8usize),
78 /// bytes::<_, _, Error<&[u8]>, _, _>(rest)
79 /// ))(input)
80 /// }
81 ///
82 /// let input = &[0x12, 0x34, 0xff, 0xff];
83 ///
84 /// assert_eq!(parse( input ), Ok(( &[][..], (0x01, 0x23, &[0xff, 0xff][..]) )));
85 /// ```
86 pub fn bytes<I, O, E1, E2, P>(mut parser: P) -> impl FnMut((I, usize)) -> IResult<(I, usize), O, E2>
87 where
88 E1: ParseError<I> + ErrorConvert<E2>,
89 E2: ParseError<(I, usize)>,
90 I: Slice<RangeFrom<usize>> + Clone,
91 P: Parser<I, O, E1>,
92 {
93 move |(input, offset): (I, usize)| {
94 let inner = if offset % 8 != 0 {
95 input.slice((1 + offset / 8)..)
96 } else {
97 input.slice((offset / 8)..)
98 };
99 let i = (input, offset);
100 match parser.parse(inner) {
101 Ok((rest, res)) => Ok(((rest, 0), res)),
102 Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)),
103 Err(Err::Incomplete(Needed::Size(sz))) => Err(match sz.get().checked_mul(8) {
104 Some(v) => Err::Incomplete(Needed::new(v)),
105 None => Err::Failure(E2::from_error_kind(i, ErrorKind::TooLarge)),
106 }),
107 Err(Err::Error(e)) => Err(Err::Error(e.convert())),
108 Err(Err::Failure(e)) => Err(Err::Failure(e.convert())),
109 }
110 }
111 }
112
113 /// Generates a parser taking `count` bits
114 ///
115 /// # Example
116 /// ```rust
117 /// # use nom8::bits::take;
118 /// # use nom8::IResult;
119 /// # use nom8::error::{Error, ErrorKind};
120 /// // Input is a tuple of (input: I, bit_offset: usize)
121 /// fn parser(input: (&[u8], usize), count: usize)-> IResult<(&[u8], usize), u8> {
122 /// take(count)(input)
123 /// }
124 ///
125 /// // Consumes 0 bits, returns 0
126 /// assert_eq!(parser(([0b00010010].as_ref(), 0), 0), Ok((([0b00010010].as_ref(), 0), 0)));
127 ///
128 /// // Consumes 4 bits, returns their values and increase offset to 4
129 /// assert_eq!(parser(([0b00010010].as_ref(), 0), 4), Ok((([0b00010010].as_ref(), 4), 0b00000001)));
130 ///
131 /// // Consumes 4 bits, offset is 4, returns their values and increase offset to 0 of next byte
132 /// assert_eq!(parser(([0b00010010].as_ref(), 4), 4), Ok((([].as_ref(), 0), 0b00000010)));
133 ///
134 /// // Tries to consume 12 bits but only 8 are available
135 /// assert_eq!(parser(([0b00010010].as_ref(), 0), 12), Err(nom8::Err::Error(Error{input: ([0b00010010].as_ref(), 0), code: ErrorKind::Eof })));
136 /// ```
137 #[inline(always)]
138 pub fn take<I, O, C, E: ParseError<(I, usize)>, const STREAMING: bool>(
139 count: C,
140 ) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E>
141 where
142 I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength + InputIsStreaming<STREAMING>,
143 C: ToUsize,
144 O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O>,
145 {
146 let count = count.to_usize();
147 move |input: (I, usize)| {
148 if STREAMING {
149 streaming::take_internal(input, count)
150 } else {
151 complete::take_internal(input, count)
152 }
153 }
154 }
155
156 /// Generates a parser taking `count` bits and comparing them to `pattern`
157 #[inline(always)]
158 pub fn tag<I, O, C, E: ParseError<(I, usize)>, const STREAMING: bool>(
159 pattern: O,
160 count: C,
161 ) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E>
162 where
163 I: Slice<RangeFrom<usize>>
164 + InputIter<Item = u8>
165 + InputLength
166 + InputIsStreaming<STREAMING>
167 + Clone,
168 C: ToUsize,
169 O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O> + PartialEq,
170 {
171 let count = count.to_usize();
172 move |input: (I, usize)| {
173 if STREAMING {
174 streaming::tag_internal(input, &pattern, count)
175 } else {
176 complete::tag_internal(input, &pattern, count)
177 }
178 }
179 }