nom8/bits/mod.rs
1//! Bit level parsers
2//!
3
4pub mod complete;
5pub mod streaming;
6#[cfg(test)]
7mod tests;
8
9use crate::error::{ErrorKind, ParseError};
10use crate::input::{ErrorConvert, InputIsStreaming, InputIter, InputLength, Slice, ToUsize};
11use crate::lib::std::ops::{AddAssign, RangeFrom, Shl, Shr};
12use 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/// ```
41pub fn bits<I, O, E1, E2, P>(mut parser: P) -> impl FnMut(I) -> IResult<I, O, E2>
42where
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/// ```
86pub fn bytes<I, O, E1, E2, P>(mut parser: P) -> impl FnMut((I, usize)) -> IResult<(I, usize), O, E2>
87where
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)]
138pub 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>
141where
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)]
158pub 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>
162where
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}