I'm trying to use the snafu crate for error handling, but keep getting errors that my error enum struct is missing the 'source' and that IntoError
is not implemented for Error
:
//main.rs
use snafu::{ResultExt, Snafu};
#[derive(Debug, Snafu)]
#[snafu(visibility = "pub(crate)")]
pub enum Error{
#[snafu(display("Could not load gallery JSON: {}: {}", json_path, source))]
LoadGallery {
source: std::io::Error,
json_path: String,
},
}
//gallery.rs
use snafu::{ResultExt};
use crate::Error::{LoadGallery};
pub struct Gallery{
name: String,
}
impl Gallery{
pub fn from_json(json_path: String)->Result<()>{
let configuration = std::fs::read_to_string(&json_path).context(LoadGallery { json_path })?;
Ok(())
}
}
This code results in:
let configuration = std::fs::read_to_string(&json_path).context(LoadGallery { json_path })?;
| ^^^^^^^^^^^ missing `source`
let configuration = std::fs::read_to_string(&json_path).context(LoadGallery { json_path })?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoError<_>` is not implemented for `Error`
Based on this example from the docs, I don't see what I'm doing wrong:
use snafu::{ResultExt, Snafu};
use std::{fs, io, path::PathBuf};
#[derive(Debug, Snafu)]
enum Error {
#[snafu(display("Unable to read configuration from {}: {}", path.display(), source))]
ReadConfiguration { source: io::Error, path: PathBuf },
#[snafu(display("Unable to write result to {}: {}", path.display(), source))]
WriteResult { source: io::Error, path: PathBuf },
}
type Result<T, E = Error> = std::result::Result<T, E>;
fn process_data() -> Result<()> {
let path = "config.toml";
let configuration = fs::read_to_string(path).context(ReadConfiguration { path })?;
let path = unpack_config(&configuration);
fs::write(&path, b"My complex calculation").context(WriteResult { path })?;
Ok(())
}
fn unpack_config(data: &str) -> &str {
"/some/path/that/does/not/exist"
}
It's because when you're constructing LoadGallery
, you're attempting to construct Error::LoadGallery
. You then get a compile error saying "missing source
", because the Error::LoadGallery
variant has a source
field. Fixing it is straight forward, you just need to change which LoadGallery
you import.
// Not this one:
// use crate::Error::LoadGallery;
// This one:
use crate::LoadGallery;
Why? Because snafu
generates a struct
for each of Error
's variants. So there's a struct LoadGallery
being generated. This struct doesn't contain the source
field, which is why you can construct it without source
and pass it to context()
, because it's not actually Error::LoadGallery
.
Your from_json()
also needs to return Result<(), Error>
instead of Result<()>
(you don't have the type alias, like in the example.)
use crate::{Error, LoadGallery};
use snafu::ResultExt;
pub struct Gallery {
name: String,
}
impl Gallery {
pub fn from_json(json_path: String) -> Result<(), Error> {
let configuration =
std::fs::read_to_string(&json_path).context(LoadGallery { json_path })?;
Ok(())
}
}
If you're curious you can use cargo expand
to inspect what macros expand to. You first need to install it by doing cargo install expand
. Then you can execute cargo expand
in any project.