I have the following code that reads the contents of a json file and deserializes the string into a vector of Todo
s:
fn deserialize_todos(filepath: &Path) -> Result<Vec<Todo>, &str> {
let string = match std::fs::read_to_string(filepath) {
Ok(string) => string,
Err(_) => return Err("Could not read file"),
};
match serde_json::from_str::<Vec<Todo>>(&string) {
Ok(todos) => Ok(todos),
Err(_) => Err("Could not parse JSON"),
}
}
I have two issues with this:
- I'm pretty sure there's a way to make the logic more similar to a pipeline, something like the following pseudo-code
fn deserialize_todos(filepath: &Path) -> Result<Vec<Todo>, &str> {
Ok(filepath)
.??(std::fs::read_to_string, "Could not read file")
.??(serde_json::from_str::<Vec<TodoItem>>, "Could not parse JSON")
}
for some ??
method on Result
which I'm not aware of.
- Two things could fail: either the file cannot be read or it cannot be parsed into JSON. I'd like to return the relative errors, i.e.
std::io::Error
ifstd::fs::read_to_string
fails orserde_json::Error
ifserde_json::from_str
fails. Instead I'm returning a string slice because I'm not sure how to express eitherErr(a)
orErr(b)
as the error type of the function. How does Rust deal with multiple possible error types?