TL; DR How do you convert None
into anyhow::Error
?
I have a file that contains a few values. Each line line contains (separated by whitespace)
- a usize index
- a f32 f
- an i64 d
I am using anyhow to make it easy to yield errors. I would like to put everything in a HashMap, indexed by the index
. The following code works:
pub struct MyData {
pub f: f32,
pub d: i64,
}
let file = BufReader::new(File::open(&path)?);
let mut line_number = 0;
while let Some(Ok(line)) = lines.next() {
line_number += 1;
let err_msg = || format!("invalid file format [{}:{}]: {}", &path.display(), line_number, &line);
let mut token = line.split_whitespace();
let id = token.next().with_context(err_msg)?.parse().with_context(err_msg)?;
let f = token.next().with_context(err_msg)?.parse().with_context(err_msg)?;
let d = token.next().with_context(err_msg)?.parse().with_context(err_msg)?;
edges.insert(id, MyData {f, d});
}
As you can see, the code to parse the line is repetitive. Since the type of the parsed value isn't the same each time, I cannot create a lambda (Rust doesn't will use the same return type for each call), so I tried to write a function:
fn parse<'a, T, U>(token: &mut 'a T) -> Result<U>
where T: std::iter::Iterator<Item = &'a str>
{
Ok(token
.next()?
.parse()?)
}
let id = parse(&mut token).with_context(err_msg)?;
let f = parse(&mut token).with_context(err_msg)?;
let d = parse(&mut token).with_context(err_msg)?;
But I get the following error
4 || 100 | .next()?
5 || | ^ the trait `std::error::Error` is not implemented for `std::option::NoneError`
6 || |
It I remove all error handling, and just unwrap()
things, it should works, but I would like to nicely report error to my caller. If I understand correctly the issue, I cannot use the try operator to yield an error if the iterator returns None
when next()
is called.
--
Note: if it's possible to automatically parse the line is a much simpler way, it would be even better. I don't think that Serde can be used here, but if I'm wrong, please correct me.