Не удается найти правильные аргументы типа при использовании анализаторов битов в nom 5.1.2

#rust #nom

#Ржавчина #nom

Вопрос:

Мне не удается найти правильный синтаксис для выполнения битового синтаксического анализа в nom 5.

Я пытаюсь это:

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

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

И получение этого от компилятора:

 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<(amp;[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)?;
  

Я пробовал разные отвратительные вещи, подобные этой:

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

… пытаюсь следовать тому, что я вижу в исходном коде nom, но это приводит к различным ошибкам:

 error[E0277]: the size for values of type `dyn nom::error::ParseError<(amp;[u8], usize)>` cannot be known at compilation time
   --> src/fitparsers.rs:662:34
    |
662 | ...om::bits::bits(nom::bits::complete::tag::<amp;[u8], (amp;[u8], u8), usize, dyn nom::error::ParseError<(amp;[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<(amp;[u8], usize)>`
  

Что я делаю не так?

Ответ №1:

Это известная проблема. Следующей аннотации было бы достаточно:

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

Однако, пожалуйста, обратите внимание, что здесь вы, вероятно, допускаете другую ошибку. Да, bits комбинатор переключается nom в режим bits, но только на время работы внутреннего анализатора. При выходе он удаляет оставшуюся часть байта, если он неполный. Таким образом, обычный способ работы с bits заключается в выполнении

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

или что-то эквивалентное этому. Внутренний анализатор не обязательно должен быть таким tuple , но он должен быть анализатором битового уровня, который потребляет кратное 8 битам, в противном случае некоторые биты будут отброшены при выходе из bits контекста.