David Farr
David Farr

Reputation: 143

How can I use a success combinator in conjunction with a map combinator in nom?

I am writing a nom parser combinator that consumes bytes and returns an Option<&[u8]>. The parser combinator should follow the following rules:

  1. Read a single signed, big endian 16 bit integer (s)
  2. If s is -1, return None
  3. If s is not -1, read s bits and return Some

Here is my parser combinator:

fn parse(i: &[u8]) -> nom::IResult<&[u8], Option<&[u8]>> {
    nom::combinator::flat_map(be_i16, |s: i16| {
        match s {
            -1 => nom::combinator::success(None),
            _ => nom::combinator::map(take(s as u16), Some)
        }
    })(i)
}

However I am seeing the following error:

error[E0308]: `match` arms have incompatible types
  --> src/main.rs:15:18
   |
13 | /         match s {
14 | |             -1 => nom::combinator::success(None),
   | |                   ------------------------------ this is found to be of type `impl Fn<(_,)>`
15 | |             _ => nom::combinator::map(take(s as u16), Some)
   | |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found a different opaque type
16 | |         }
   | |_________- `match` arms have incompatible types
   |
  ::: /Users/dfarr/.cargo/registry/src/github.com-1ecc6299db9ec823/nom-6.0.1/src/combinator/mod.rs:74:64
   |
74 |   pub fn map<I, O1, O2, E, F, G>(mut first: F, mut second: G) -> impl FnMut(I) -> IResult<I, O2, E>
   |                                                                  ---------------------------------- the found opaque type
   |
   = note:     expected type `impl Fn<(_,)>`
           found opaque type `impl FnMut<(_,)>`
   = note: distinct uses of `impl Trait` result in different opaque types

I can see that nom::combinator::success does indeed have a return type of impl Fn(I) -> ..., and nom::combinator::map returns impl FnMut(I) -> .... Is there a more idiomatic way of using nom where these combinators can be used together in this manner?

Upvotes: 4

Views: 488

Answers (1)

George
George

Reputation: 2821

This may do the trick (it compiles). Here, nom::combinator::map applies the transform to the successful result value and re-wraps it in the Ok variant. Incidentally, there is also a nom::Parser<T>::map which seems to implement the Map iterator.

use nom::combinator::map;
use nom::number::complete::be_i16;

fn parse(i: &[u8]) -> nom::IResult<&[u8], Option<i16>> {
    let f = |s: i16| if s == -1 { None } else { Some(s) };
    map(be_i16, f)(i)
}

Upvotes: 1

Related Questions