nom8/bits/
complete.rs

1//! Bit level parsers
2//!
3
4#![allow(deprecated)]
5
6use crate::error::{ErrorKind, ParseError};
7use crate::input::{InputIter, InputLength, Slice, ToUsize};
8use crate::lib::std::ops::{AddAssign, Div, RangeFrom, Shl, Shr};
9use crate::{Err, IResult};
10
11/// Generates a parser taking `count` bits
12///
13/// # Example
14/// ```rust
15/// # use nom8::bits::complete::take;
16/// # use nom8::IResult;
17/// # use nom8::error::{Error, ErrorKind};
18/// // Input is a tuple of (input: I, bit_offset: usize)
19/// fn parser(input: (&[u8], usize), count: usize)-> IResult<(&[u8], usize), u8> {
20///  take(count)(input)
21/// }
22///
23/// // Consumes 0 bits, returns 0
24/// assert_eq!(parser(([0b00010010].as_ref(), 0), 0), Ok((([0b00010010].as_ref(), 0), 0)));
25///
26/// // Consumes 4 bits, returns their values and increase offset to 4
27/// assert_eq!(parser(([0b00010010].as_ref(), 0), 4), Ok((([0b00010010].as_ref(), 4), 0b00000001)));
28///
29/// // Consumes 4 bits, offset is 4, returns their values and increase offset to 0 of next byte
30/// assert_eq!(parser(([0b00010010].as_ref(), 4), 4), Ok((([].as_ref(), 0), 0b00000010)));
31///
32/// // Tries to consume 12 bits but only 8 are available
33/// assert_eq!(parser(([0b00010010].as_ref(), 0), 12), Err(nom8::Err::Error(Error{input: ([0b00010010].as_ref(), 0), code: ErrorKind::Eof })));
34/// ```
35///
36/// **WARNING:** Deprecated, replaced with [`nom8::bits::take`][crate::bits::take]
37#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bits::take`")]
38pub fn take<I, O, C, E: ParseError<(I, usize)>>(
39  count: C,
40) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E>
41where
42  I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
43  C: ToUsize,
44  O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O>,
45{
46  let count = count.to_usize();
47  move |input: (I, usize)| take_internal(input, count)
48}
49
50pub(crate) fn take_internal<I, O, E: ParseError<(I, usize)>>(
51  (input, bit_offset): (I, usize),
52  count: usize,
53) -> IResult<(I, usize), O, E>
54where
55  I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
56  O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O>,
57{
58  if count == 0 {
59    Ok(((input, bit_offset), 0u8.into()))
60  } else {
61    let cnt = (count + bit_offset).div(8);
62    if input.input_len() * 8 < count + bit_offset {
63      Err(Err::Error(E::from_error_kind(
64        (input, bit_offset),
65        ErrorKind::Eof,
66      )))
67    } else {
68      let mut acc: O = 0_u8.into();
69      let mut offset: usize = bit_offset;
70      let mut remaining: usize = count;
71      let mut end_offset: usize = 0;
72
73      for byte in input.iter_elements().take(cnt + 1) {
74        if remaining == 0 {
75          break;
76        }
77        let val: O = if offset == 0 {
78          byte.into()
79        } else {
80          ((byte << offset) as u8 >> offset).into()
81        };
82
83        if remaining < 8 - offset {
84          acc += val >> (8 - offset - remaining);
85          end_offset = remaining + offset;
86          break;
87        } else {
88          acc += val << (remaining - (8 - offset));
89          remaining -= 8 - offset;
90          offset = 0;
91        }
92      }
93      Ok(((input.slice(cnt..), end_offset), acc))
94    }
95  }
96}
97
98/// Generates a parser taking `count` bits and comparing them to `pattern`
99///
100/// **WARNING:** Deprecated, replaced with [`nom8::bits::tag`][crate::bits::tag]
101#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bits::tag`")]
102pub fn tag<I, O, C, E: ParseError<(I, usize)>>(
103  pattern: O,
104  count: C,
105) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E>
106where
107  I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength + Clone,
108  C: ToUsize,
109  O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O> + PartialEq,
110{
111  let count = count.to_usize();
112  move |input: (I, usize)| tag_internal(input, &pattern, count)
113}
114
115pub(crate) fn tag_internal<I, O, E: ParseError<(I, usize)>>(
116  input: (I, usize),
117  pattern: &O,
118  count: usize,
119) -> IResult<(I, usize), O, E>
120where
121  I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength + Clone,
122  O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O> + PartialEq,
123{
124  let inp = input.clone();
125
126  take_internal(input, count).and_then(|(i, o)| {
127    if *pattern == o {
128      Ok((i, o))
129    } else {
130      Err(Err::Error(error_position!(inp, ErrorKind::TagBits)))
131    }
132  })
133}
134
135#[cfg(test)]
136mod test {
137  use super::*;
138
139  #[test]
140  fn test_take_0() {
141    let input = [0b00010010].as_ref();
142    let count = 0usize;
143    assert_eq!(count, 0usize);
144    let offset = 0usize;
145
146    let result: crate::IResult<(&[u8], usize), usize> = take(count)((input, offset));
147
148    assert_eq!(result, Ok(((input, offset), 0)));
149  }
150
151  #[test]
152  fn test_take_eof() {
153    let input = [0b00010010].as_ref();
154
155    let result: crate::IResult<(&[u8], usize), usize> = take(1usize)((input, 8));
156
157    assert_eq!(
158      result,
159      Err(crate::Err::Error(crate::error::Error {
160        input: (input, 8),
161        code: ErrorKind::Eof
162      }))
163    )
164  }
165
166  #[test]
167  fn test_take_span_over_multiple_bytes() {
168    let input = [0b00010010, 0b00110100, 0b11111111, 0b11111111].as_ref();
169
170    let result: crate::IResult<(&[u8], usize), usize> = take(24usize)((input, 4));
171
172    assert_eq!(
173      result,
174      Ok((([0b11111111].as_ref(), 4), 0b1000110100111111111111))
175    );
176  }
177}