summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nom/src/bits/streaming.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/nom/src/bits/streaming.rs')
-rw-r--r--third_party/rust/nom/src/bits/streaming.rs170
1 files changed, 170 insertions, 0 deletions
diff --git a/third_party/rust/nom/src/bits/streaming.rs b/third_party/rust/nom/src/bits/streaming.rs
new file mode 100644
index 0000000000..a7c8d0a67b
--- /dev/null
+++ b/third_party/rust/nom/src/bits/streaming.rs
@@ -0,0 +1,170 @@
+//! Bit level parsers
+//!
+
+use crate::error::{ErrorKind, ParseError};
+use crate::internal::{Err, IResult, Needed};
+use crate::lib::std::ops::{AddAssign, Div, RangeFrom, Shl, Shr};
+use crate::traits::{InputIter, InputLength, Slice, ToUsize};
+
+/// Generates a parser taking `count` bits
+pub fn take<I, O, C, E: ParseError<(I, usize)>>(
+ count: C,
+) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E>
+where
+ I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
+ C: ToUsize,
+ O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O>,
+{
+ let count = count.to_usize();
+ move |(input, bit_offset): (I, usize)| {
+ if count == 0 {
+ Ok(((input, bit_offset), 0u8.into()))
+ } else {
+ let cnt = (count + bit_offset).div(8);
+ if input.input_len() * 8 < count + bit_offset {
+ Err(Err::Incomplete(Needed::new(count as usize)))
+ } else {
+ let mut acc: O = 0_u8.into();
+ let mut offset: usize = bit_offset;
+ let mut remaining: usize = count;
+ let mut end_offset: usize = 0;
+
+ for byte in input.iter_elements().take(cnt + 1) {
+ if remaining == 0 {
+ break;
+ }
+ let val: O = if offset == 0 {
+ byte.into()
+ } else {
+ ((byte << offset) as u8 >> offset).into()
+ };
+
+ if remaining < 8 - offset {
+ acc += val >> (8 - offset - remaining);
+ end_offset = remaining + offset;
+ break;
+ } else {
+ acc += val << (remaining - (8 - offset));
+ remaining -= 8 - offset;
+ offset = 0;
+ }
+ }
+ Ok(((input.slice(cnt..), end_offset), acc))
+ }
+ }
+ }
+}
+
+/// Generates a parser taking `count` bits and comparing them to `pattern`
+pub fn tag<I, O, C, E: ParseError<(I, usize)>>(
+ pattern: O,
+ count: C,
+) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E>
+where
+ I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength + Clone,
+ C: ToUsize,
+ O: From<u8> + AddAssign + Shl<usize, Output = O> + Shr<usize, Output = O> + PartialEq,
+{
+ let count = count.to_usize();
+ move |input: (I, usize)| {
+ let inp = input.clone();
+
+ take(count)(input).and_then(|(i, o)| {
+ if pattern == o {
+ Ok((i, o))
+ } else {
+ Err(Err::Error(error_position!(inp, ErrorKind::TagBits)))
+ }
+ })
+ }
+}
+
+/// Parses one specific bit as a bool.
+///
+/// # Example
+/// ```rust
+/// # use nom::bits::complete::bool;
+/// # use nom::IResult;
+/// # use nom::error::{Error, ErrorKind};
+///
+/// fn parse(input: (&[u8], usize)) -> IResult<(&[u8], usize), bool> {
+/// bool(input)
+/// }
+///
+/// assert_eq!(parse(([0b10000000].as_ref(), 0)), Ok((([0b10000000].as_ref(), 1), true)));
+/// assert_eq!(parse(([0b10000000].as_ref(), 1)), Ok((([0b10000000].as_ref(), 2), false)));
+/// ```
+pub fn bool<I, E: ParseError<(I, usize)>>(input: (I, usize)) -> IResult<(I, usize), bool, E>
+where
+ I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
+{
+ let (res, bit): (_, u32) = take(1usize)(input)?;
+ Ok((res, bit != 0))
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_take_0() {
+ let input = [].as_ref();
+ let count = 0usize;
+ assert_eq!(count, 0usize);
+ let offset = 0usize;
+
+ let result: crate::IResult<(&[u8], usize), usize> = take(count)((input, offset));
+
+ assert_eq!(result, Ok(((input, offset), 0)));
+ }
+
+ #[test]
+ fn test_tag_ok() {
+ let input = [0b00011111].as_ref();
+ let offset = 0usize;
+ let bits_to_take = 4usize;
+ let value_to_tag = 0b0001;
+
+ let result: crate::IResult<(&[u8], usize), usize> =
+ tag(value_to_tag, bits_to_take)((input, offset));
+
+ assert_eq!(result, Ok(((input, bits_to_take), value_to_tag)));
+ }
+
+ #[test]
+ fn test_tag_err() {
+ let input = [0b00011111].as_ref();
+ let offset = 0usize;
+ let bits_to_take = 4usize;
+ let value_to_tag = 0b1111;
+
+ let result: crate::IResult<(&[u8], usize), usize> =
+ tag(value_to_tag, bits_to_take)((input, offset));
+
+ assert_eq!(
+ result,
+ Err(crate::Err::Error(crate::error::Error {
+ input: (input, offset),
+ code: ErrorKind::TagBits
+ }))
+ );
+ }
+
+ #[test]
+ fn test_bool_0() {
+ let input = [0b10000000].as_ref();
+
+ let result: crate::IResult<(&[u8], usize), bool> = bool((input, 0));
+
+ assert_eq!(result, Ok(((input, 1), true)));
+ }
+
+ #[test]
+ fn test_bool_eof() {
+ let input = [0b10000000].as_ref();
+
+ let result: crate::IResult<(&[u8], usize), bool> = bool((input, 8));
+
+ assert_eq!(result, Err(crate::Err::Incomplete(Needed::new(1))));
+ }
+}