diff options
Diffstat (limited to 'third_party/rust/nom/src/bits')
-rw-r--r-- | third_party/rust/nom/src/bits/complete.rs | 150 | ||||
-rw-r--r-- | third_party/rust/nom/src/bits/mod.rs | 179 | ||||
-rw-r--r-- | third_party/rust/nom/src/bits/streaming.rs | 129 |
3 files changed, 458 insertions, 0 deletions
diff --git a/third_party/rust/nom/src/bits/complete.rs b/third_party/rust/nom/src/bits/complete.rs new file mode 100644 index 0000000000..b46bc7a279 --- /dev/null +++ b/third_party/rust/nom/src/bits/complete.rs @@ -0,0 +1,150 @@ +//! 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<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::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<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))) + } + }) + } +} + +#[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)) + ); + } +} diff --git a/third_party/rust/nom/src/bits/mod.rs b/third_party/rust/nom/src/bits/mod.rs new file mode 100644 index 0000000000..235b7973e1 --- /dev/null +++ b/third_party/rust/nom/src/bits/mod.rs @@ -0,0 +1,179 @@ +//! Bit level parsers +//! + +pub mod complete; +pub mod streaming; + +use crate::error::{ErrorKind, ParseError}; +use crate::internal::{Err, IResult, Needed}; +use crate::lib::std::ops::RangeFrom; +use crate::traits::{ErrorConvert, Slice}; + +/// Converts a byte-level input to a bit-level input, for consumption by a parser that uses bits. +/// +/// Afterwards, the input is converted back to a byte-level parser, with any remaining bits thrown +/// away. +/// +/// # Example +/// ``` +/// use nom::bits::{bits, streaming::take}; +/// use nom::error::Error; +/// use nom::sequence::tuple; +/// use nom::IResult; +/// +/// fn parse(input: &[u8]) -> IResult<&[u8], (u8, u8)> { +/// bits::<_, _, Error<(&[u8], usize)>, _, _>(tuple((take(4usize), take(8usize))))(input) +/// } +/// +/// let input = &[0x12, 0x34, 0xff, 0xff]; +/// +/// let output = parse(input).expect("We take 1.5 bytes and the input is longer than 2 bytes"); +/// +/// // The first byte is consumed, the second byte is partially consumed and dropped. +/// let remaining = output.0; +/// assert_eq!(remaining, [0xff, 0xff]); +/// +/// let parsed = output.1; +/// assert_eq!(parsed.0, 0x01); +/// assert_eq!(parsed.1, 0x23); +/// ``` +pub fn bits<I, O, E1, E2, P>(mut parser: P) -> impl FnMut(I) -> IResult<I, O, E2> +where + E1: ParseError<(I, usize)> + ErrorConvert<E2>, + E2: ParseError<I>, + I: Slice<RangeFrom<usize>>, + P: FnMut((I, usize)) -> IResult<(I, usize), O, E1>, +{ + move |input: I| match parser((input, 0)) { + Ok(((rest, offset), result)) => { + // If the next byte has been partially read, it will be sliced away as well. + // The parser functions might already slice away all fully read bytes. + // That's why `offset / 8` isn't necessarily needed at all times. + let remaining_bytes_index = offset / 8 + if offset % 8 == 0 { 0 } else { 1 }; + Ok((rest.slice(remaining_bytes_index..), result)) + } + Err(Err::Incomplete(n)) => Err(Err::Incomplete(n.map(|u| u.get() / 8 + 1))), + Err(Err::Error(e)) => Err(Err::Error(e.convert())), + Err(Err::Failure(e)) => Err(Err::Failure(e.convert())), + } +} + +/// Counterpart to `bits`, `bytes` transforms its bit stream input into a byte slice for the underlying +/// parser, allowing byte-slice parsers to work on bit streams. +/// +/// A partial byte remaining in the input will be ignored and the given parser will start parsing +/// at the next full byte. +/// +/// ``` +/// use nom::bits::{bits, bytes, streaming::take}; +/// use nom::combinator::rest; +/// use nom::error::Error; +/// use nom::sequence::tuple; +/// use nom::IResult; +/// +/// fn parse(input: &[u8]) -> IResult<&[u8], (u8, u8, &[u8])> { +/// bits::<_, _, Error<(&[u8], usize)>, _, _>(tuple(( +/// take(4usize), +/// take(8usize), +/// bytes::<_, _, Error<&[u8]>, _, _>(rest) +/// )))(input) +/// } +/// +/// let input = &[0x12, 0x34, 0xff, 0xff]; +/// +/// assert_eq!(parse( input ), Ok(( &[][..], (0x01, 0x23, &[0xff, 0xff][..]) ))); +/// ``` +pub fn bytes<I, O, E1, E2, P>(mut parser: P) -> impl FnMut((I, usize)) -> IResult<(I, usize), O, E2> +where + E1: ParseError<I> + ErrorConvert<E2>, + E2: ParseError<(I, usize)>, + I: Slice<RangeFrom<usize>> + Clone, + P: FnMut(I) -> IResult<I, O, E1>, +{ + move |(input, offset): (I, usize)| { + let inner = if offset % 8 != 0 { + input.slice((1 + offset / 8)..) + } else { + input.slice((offset / 8)..) + }; + let i = (input, offset); + match parser(inner) { + Ok((rest, res)) => Ok(((rest, 0), res)), + Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)), + Err(Err::Incomplete(Needed::Size(sz))) => Err(match sz.get().checked_mul(8) { + Some(v) => Err::Incomplete(Needed::new(v)), + None => Err::Failure(E2::from_error_kind(i, ErrorKind::TooLarge)), + }), + Err(Err::Error(e)) => Err(Err::Error(e.convert())), + Err(Err::Failure(e)) => Err(Err::Failure(e.convert())), + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::bits::streaming::take; + use crate::error::Error; + use crate::sequence::tuple; + + #[test] + /// Take the `bits` function and assert that remaining bytes are correctly returned, if the + /// previous bytes are fully consumed + fn test_complete_byte_consumption_bits() { + let input = &[0x12, 0x34, 0x56, 0x78]; + + // Take 3 bit slices with sizes [4, 8, 4]. + let result: IResult<&[u8], (u8, u8, u8)> = + bits::<_, _, Error<(&[u8], usize)>, _, _>(tuple((take(4usize), take(8usize), take(4usize))))( + input, + ); + + let output = result.expect("We take 2 bytes and the input is longer than 2 bytes"); + + let remaining = output.0; + assert_eq!(remaining, [0x56, 0x78]); + + let parsed = output.1; + assert_eq!(parsed.0, 0x01); + assert_eq!(parsed.1, 0x23); + assert_eq!(parsed.2, 0x04); + } + + #[test] + /// Take the `bits` function and assert that remaining bytes are correctly returned, if the + /// previous bytes are NOT fully consumed. Partially consumed bytes are supposed to be dropped. + /// I.e. if we consume 1.5 bytes of 4 bytes, 2 bytes will be returned, bits 13-16 will be + /// dropped. + fn test_partial_byte_consumption_bits() { + let input = &[0x12, 0x34, 0x56, 0x78]; + + // Take bit slices with sizes [4, 8]. + let result: IResult<&[u8], (u8, u8)> = + bits::<_, _, Error<(&[u8], usize)>, _, _>(tuple((take(4usize), take(8usize))))(input); + + let output = result.expect("We take 1.5 bytes and the input is longer than 2 bytes"); + + let remaining = output.0; + assert_eq!(remaining, [0x56, 0x78]); + + let parsed = output.1; + assert_eq!(parsed.0, 0x01); + assert_eq!(parsed.1, 0x23); + } + + #[test] + #[cfg(feature = "std")] + /// Ensure that in Incomplete error is thrown, if too few bytes are passed for a given parser. + fn test_incomplete_bits() { + let input = &[0x12]; + + // Take bit slices with sizes [4, 8]. + let result: IResult<&[u8], (u8, u8)> = + bits::<_, _, Error<(&[u8], usize)>, _, _>(tuple((take(4usize), take(8usize))))(input); + + assert!(result.is_err()); + let error = result.err().unwrap(); + assert_eq!("Parsing requires 2 bytes/chars", error.to_string()); + } +} 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..e8adc1c0d4 --- /dev/null +++ b/third_party/rust/nom/src/bits/streaming.rs @@ -0,0 +1,129 @@ +//! 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))) + } + }) + } +} + +#[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 + })) + ); + } +} |