Coverage Report

Created: 2025-11-16 06:34

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