I have this Rust program using nom 4.2.2. (I have taken the liberty of expanding the nom parser function.)
extern crate failure;
extern crate nom;
use failure::Error;
use std::fs::File;
use std::io::Read;
fn nom_parser(i: &[u8]) -> ::nom::IResult<&[u8], String, u32> {
{ ::nom::lib::std::result::Result::Ok((i, ("foo".to_owned()))) }
}
fn my_parser(buf: &[u8]) -> Result<(&[u8], String), Error> {
Ok((buf, "foo".to_owned()))
}
fn main() -> Result<(), Error> {
let handler = |mut entries: String| { entries.clear() };
loop {
let mut buf = Vec::new();
File::open("/etc/hosts")?.read_to_end(&mut buf)?;
let res = nom_parser(&buf)?.1;
// let res = my_parser(&buf)?.1;
handler(res);
}
}
Compiling this program with rustc 1.33.0 (2aa4c46cf 2019-02-28)
yields the following issue:
error[E0597]: `buf` does not live long enough
--> nom-parsing/src/main.rs:21:26
|
21 | let res = nom_parser(&buf)?.1;
| -----------^^^^-
| | |
| | borrowed value does not live long enough
| argument requires that `buf` is borrowed for `'static`
...
24 | }
| - `buf` dropped here while still borrowed
Switching to the commented out version of the parser compiles just fine. How are my_parser
and nom_parser
different? Who is borrowing buf? How should I change the program to placate the borrow checker?
let res = nom_parser(&buf)?.1;
^ here
You are using the ?
operator to propagate the error out of main
. The IResult<&[u8], String, u32>
= Result<(&[u8], String), nom::Err<&[u8], u32>>
. So in case of error the &buf
is returned as part of it, so it must stay alive even after main
function exits, but it won't because buf
is local variable inside main
.
In your case the nom_parser
never returns error, but the validation only cares about the types and function signatures.
To fix it, you should process the error somehow before propagating it up. For example:
let res = nom_parser(&buf).map_err(|_| failure::format_err!("Parsing failed!"))?.1;
Note that Err
in the IResult
is not always hard error. It could be nom::Err::Incomplete
, meaning that the parsing may succeed if more data is supplied, or nom::Err::Error
meaning that the input was not matched by the parser (so perhaps another parser in alt!
could succeed), or nom::Err::Failure
, meaning that something went really wrong during parsing. Depending on the situation, you may consider them all as failure, or handle them differently.