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}