Failing to find the right type arguments when using the bits parsers in nom 5.1.2

Viewed 353

I'm failing to find the correct syntax to do bit parsing in nom 5.

I'm trying this:

pub fn parse_normal_record_header(i: &[u8]) -> nom::IResult<&[u8], FitRecordHeader> {

     let (i, _) = nom::bits::bits(nom::bits::complete::tag(0x0, 1_usize))(i)?;
     ...
}

And getting this from the compiler:

error[E0283]: type annotations needed
   --> src/fitparsers.rs:658:18
    |
658 |     let (i, _) = nom::bits::bits(nom::bits::complete::tag(0x0, 1_usize))(i)?;
    |                  ^^^^^^^^^^^^^^^ cannot infer type for type parameter `E1` declared on the function `bits`
    |
   ::: /Users/djk/.cargo/registry/src/github.com-1ecc6299db9ec823/nom-5.1.2/src/bits/mod.rs:37:23
    |
37  | pub fn bits<I, O, E1: ParseError<(I, usize)>+ErrorConvert<E2>, E2: ParseError<I>, P>(parser: P) -> impl Fn(I) -> IResult<I, O, E2>
    |                       ---------------------- required by this bound in `nom::bits`
    |
    = note: cannot satisfy `_: nom::error::ParseError<(&[u8], usize)>`
help: consider specifying the type arguments in the function call
    |
658 |     let (i, _) = nom::bits::bits::<I, O, E1, E2, P>(nom::bits::complete::tag(0x0, 1_usize))(i)?;

I've tried various hideous things like this:

let (i, _) = nom::bits::bits(nom::bits::complete::tag::<&[u8], (&[u8], u8), usize, dyn nom::error::ParseError<(&[u8], usize)>>(0, 1_usize))(i)?;

... attempting to follow what I'm seeing in the nom source, but that's yielding different errors:

error[E0277]: the size for values of type `dyn nom::error::ParseError<(&[u8], usize)>` cannot be known at compilation time
   --> src/fitparsers.rs:662:34
    |
662 | ...om::bits::bits(nom::bits::complete::tag::<&[u8], (&[u8], u8), usize, dyn nom::error::ParseError<(&[u8], usize)>>(0, 1_usize))(i)?;
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
   ::: /Users/djk/.cargo/registry/src/github.com-1ecc6299db9ec823/nom-5.1.2/src/bits/complete.rs:57:21
    |
57  | pub fn tag<I, O, C, E: ParseError<(I, usize)>>(pattern: O, count: C) -> impl Fn((I, usize)) -> IResult<(I, usize), O, E>
    |                     - required by this bound in `nom::complete::tag`
    |
    = help: the trait `std::marker::Sized` is not implemented for `dyn nom::error::ParseError<(&[u8], usize)>`

What am I doing wrong?

1 Answers

This is a known problem. The following annotation would be enough:

nom::bits::complete::tag::<_, _, _, (_, _)>(0x0, 1_usize)

However, please note that you're likely making another mistake here. Yes, the bits combinator switches nom to bits mode, but only for the duration of the inner parser. On exit it drops the remaining part of the byte if it's incomplete. Thus the normal way of working with bits is to do

nom::bits::bits(nom::sequence::tuple::<_, _, (_, _), _>((
    /* a number of bitfields that add up to a whole number of bytes */
)))(i)?

or something equivalent to that. The inner parser does not need to be tuple, but it needs to be a bit-level parser that consumes a multiple of 8 bits, otherwise some bits will be dropped on exiting the bits context.

Related