//! Bit level parsers //! use crate::error::{ErrorKind, ParseError}; use crate::internal::{Err, IResult}; use crate::lib::std::ops::{AddAssign, Div, RangeFrom, Shl, Shr}; use crate::traits::{InputIter, InputLength, Slice, ToUsize}; /// Generates a parser taking `count` bits /// /// # Example /// ```rust /// # use nom::bits::complete::take; /// # use nom::IResult; /// # use nom::error::{Error, ErrorKind}; /// // Input is a tuple of (input: I, bit_offset: usize) /// fn parser(input: (&[u8], usize), count: usize)-> IResult<(&[u8], usize), u8> { /// take(count)(input) /// } /// /// // Consumes 0 bits, returns 0 /// assert_eq!(parser(([0b00010010].as_ref(), 0), 0), Ok((([0b00010010].as_ref(), 0), 0))); /// /// // Consumes 4 bits, returns their values and increase offset to 4 /// assert_eq!(parser(([0b00010010].as_ref(), 0), 4), Ok((([0b00010010].as_ref(), 4), 0b00000001))); /// /// // Consumes 4 bits, offset is 4, returns their values and increase offset to 0 of next byte /// assert_eq!(parser(([0b00010010].as_ref(), 4), 4), Ok((([].as_ref(), 0), 0b00000010))); /// /// // Tries to consume 12 bits but only 8 are available /// assert_eq!(parser(([0b00010010].as_ref(), 0), 12), Err(nom::Err::Error(Error{input: ([0b00010010].as_ref(), 0), code: ErrorKind::Eof }))); /// ``` pub fn take>( count: C, ) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E> where I: Slice> + InputIter + InputLength, C: ToUsize, O: From + AddAssign + Shl + Shr, { 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::Error(E::from_error_kind( (input, bit_offset), ErrorKind::Eof, ))) } 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>( pattern: O, count: C, ) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E> where I: Slice> + InputIter + InputLength + Clone, C: ToUsize, O: From + AddAssign + Shl + Shr + 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))) } }) } } #[cfg(test)] mod test { use super::*; #[test] fn test_take_0() { let input = [0b00010010].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_take_eof() { let input = [0b00010010].as_ref(); let result: crate::IResult<(&[u8], usize), usize> = take(1usize)((input, 8)); assert_eq!( result, Err(crate::Err::Error(crate::error::Error { input: (input, 8), code: ErrorKind::Eof })) ) } #[test] fn test_take_span_over_multiple_bytes() { let input = [0b00010010, 0b00110100, 0b11111111, 0b11111111].as_ref(); let result: crate::IResult<(&[u8], usize), usize> = take(24usize)((input, 4)); assert_eq!( result, Ok((([0b11111111].as_ref(), 4), 0b1000110100111111111111)) ); } }