nom/bits/
streaming.rs

1//! Bit level parsers
2//!
3
4use crate::error::{ErrorKind, ParseError};
5use crate::internal::{Err, IResult, Needed};
6use crate::lib::std::ops::{AddAssign, Div, Shl, Shr};
7use crate::traits::{Input, ToUsize};
8
9/// Generates a parser taking `count` bits
10pub fn take<I, O, C, E: ParseError<(I, usize)>>(
11  count: C,
12) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E>
13where
14  I: Input<Item = u8>,
15  C: ToUsize,
16  O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O>,
17{
18  let count = count.to_usize();
19  move |(input, bit_offset): (I, usize)| {
20    if count == 0 {
21      Ok(((input, bit_offset), 0u8.into()))
22    } else {
23      let cnt = (count + bit_offset).div(8);
24      if input.input_len() * 8 < count + bit_offset {
25        Err(Err::Incomplete(Needed::new(count)))
26      } else {
27        let mut acc: O = 0_u8.into();
28        let mut offset: usize = bit_offset;
29        let mut remaining: usize = count;
30        let mut end_offset: usize = 0;
31
32        for byte in input.iter_elements().take(cnt + 1) {
33          if remaining == 0 {
34            break;
35          }
36          let val: O = if offset == 0 {
37            byte.into()
38          } else {
39            ((byte << offset) >> offset).into()
40          };
41
42          if remaining < 8 - offset {
43            acc += val >> (8 - offset - remaining);
44            end_offset = remaining + offset;
45            break;
46          } else {
47            acc += val << (remaining - (8 - offset));
48            remaining -= 8 - offset;
49            offset = 0;
50          }
51        }
52        Ok(((input.take_from(cnt), end_offset), acc))
53      }
54    }
55  }
56}
57
58/// Generates a parser taking `count` bits and comparing them to `pattern`
59pub fn tag<I, O, C, E: ParseError<(I, usize)>>(
60  pattern: O,
61  count: C,
62) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E>
63where
64  I: Input<Item = u8> + Clone,
65  C: ToUsize,
66  O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O> + PartialEq,
67{
68  let count = count.to_usize();
69  move |input: (I, usize)| {
70    let inp = input.clone();
71
72    take(count)(input).and_then(|(i, o)| {
73      if pattern == o {
74        Ok((i, o))
75      } else {
76        Err(Err::Error(error_position!(inp, ErrorKind::TagBits)))
77      }
78    })
79  }
80}
81
82/// Parses one specific bit as a bool.
83///
84/// # Example
85/// ```rust
86/// # use nom::bits::complete::bool;
87/// # use nom::IResult;
88/// # use nom::error::{Error, ErrorKind};
89///
90/// fn parse(input: (&[u8], usize)) -> IResult<(&[u8], usize), bool> {
91///     bool(input)
92/// }
93///
94/// assert_eq!(parse(([0b10000000].as_ref(), 0)), Ok((([0b10000000].as_ref(), 1), true)));
95/// assert_eq!(parse(([0b10000000].as_ref(), 1)), Ok((([0b10000000].as_ref(), 2), false)));
96/// ```
97pub fn bool<I, E: ParseError<(I, usize)>>(input: (I, usize)) -> IResult<(I, usize), bool, E>
98where
99  I: Input<Item = u8>,
100{
101  let (res, bit): (_, u32) = take(1usize)(input)?;
102  Ok((res, bit != 0))
103}
104
105#[cfg(test)]
106mod test {
107  use super::*;
108
109  #[test]
110  fn test_take_0() {
111    let input = [].as_ref();
112    let count = 0usize;
113    assert_eq!(count, 0usize);
114    let offset = 0usize;
115
116    let result: crate::IResult<(&[u8], usize), usize> = take(count)((input, offset));
117
118    assert_eq!(result, Ok(((input, offset), 0)));
119  }
120
121  #[test]
122  fn test_tag_ok() {
123    let input = [0b00011111].as_ref();
124    let offset = 0usize;
125    let bits_to_take = 4usize;
126    let value_to_tag = 0b0001;
127
128    let result: crate::IResult<(&[u8], usize), usize> =
129      tag(value_to_tag, bits_to_take)((input, offset));
130
131    assert_eq!(result, Ok(((input, bits_to_take), value_to_tag)));
132  }
133
134  #[test]
135  fn test_tag_err() {
136    let input = [0b00011111].as_ref();
137    let offset = 0usize;
138    let bits_to_take = 4usize;
139    let value_to_tag = 0b1111;
140
141    let result: crate::IResult<(&[u8], usize), usize> =
142      tag(value_to_tag, bits_to_take)((input, offset));
143
144    assert_eq!(
145      result,
146      Err(crate::Err::Error(crate::error::Error {
147        input: (input, offset),
148        code: ErrorKind::TagBits
149      }))
150    );
151  }
152
153  #[test]
154  fn test_bool_0() {
155    let input = [0b10000000].as_ref();
156
157    let result: crate::IResult<(&[u8], usize), bool> = bool((input, 0));
158
159    assert_eq!(result, Ok(((input, 1), true)));
160  }
161
162  #[test]
163  fn test_bool_eof() {
164    let input = [0b10000000].as_ref();
165
166    let result: crate::IResult<(&[u8], usize), bool> = bool((input, 8));
167
168    assert_eq!(result, Err(crate::Err::Incomplete(Needed::new(1))));
169  }
170}