Lost in generic inference and lifetimes with Nom, and it's only a 6-statement function!

There are also implementations for nom::error::Error, nom::error::VerboseError and (). You can try replacing (&str, nom::error::ErrorKind) with any of these and they will all work, so the compiler needs help in figuring out which one you want. (It would also need such a hint even if there was only one implementation, because it wouldn't be nice if adding a second implementation broke code relying on there only being one.)

I don't know if nom has some more convenient way of selecting the concrete error type, but one option is to annotate the variable instead of the function

let parse: Result<_, nom::Err<(_, _)>> = tuple(( // ...

The 'static error is a bit unhelpful as is often the case, in this case it's trying to tell you that instead of a temporary str borrow, you should use a permanent 'static one, meaning changing the function signature to

fn parse_password_line(i: &'static str) -> Result<(u64, u64, char, &str), io::Error> {

which, as you've correctly guessed, would probably result in unsolveable errors elsewhere.

The reason it tries suggesting this is a bit convoluted, but to simplify it a bit, std::io::Error::new wants something that can be converted into a trait object that does not hold any temporary borrows. nom's errors contain the unparsed input data, which means that this conversion cannot be done when the input data is temporarily borrowed from elsewhere (i: &str). The naive fix is to simply make the borrow permanent (i: &'static str).

Using to_string like you have is fine, I think, but if you want to keep the nom::Err, it offers a function nom::Err::map_input, which we can use to turn the problematic temporarily borrowed input into an owned String.

        Err(e) => Err(io::Error::new(
            io::ErrorKind::InvalidData,
            e.map_input(|e| e.to_string()),
        )),

APIs that use lots of generics like nom's are a bit hard to wrap your head around and I don't have great advice for that, unfortunately. One good trick is to type annotate something wrong to get a compiler error telling you what it actually is. Examples are often valuable too, here you can see that they've made the parsing function parse_string generic over the error type, and it is then called with the error type annotated.

2 Likes