I'm trying to involve std::error::FromError trait as widely as possible in my projects to take advantage of try! macro. However, I'm a little lost with these errors conversions between different mods.
For example, I have mod (or crate) a, which has some error handling using it's own Error type, and implements errors conversion for io::Error:
mod a {
use std::io;
use std::io::Write;
use std::error::FromError;
#[derive(Debug)]
pub struct Error(pub String);
impl FromError<io::Error> for Error {
fn from_error(err: io::Error) -> Error {
Error(format!("{}", err))
}
}
pub fn func() -> Result<(), Error> {
try!(writeln!(&mut io::stdout(), "Hello, world!"));
Ok(())
}
}
I also have mod b in the same situation, but it implements error conversion for num::ParseIntError:
mod b {
use std::str::FromStr;
use std::error::FromError;
use std::num::ParseIntError;
#[derive(Debug)]
pub struct Error(pub String);
impl FromError<ParseIntError> for Error {
fn from_error(err: ParseIntError) -> Error {
Error(format!("{}", err))
}
}
pub fn func() -> Result<usize, Error> {
Ok(try!(FromStr::from_str("14")))
}
}
Now I'm in my current mod super, which has it's own Error type, and my goal is to write a procedure like this:
#[derive(Debug)]
struct Error(String);
fn func() -> Result<(), Error> {
println!("a::func() -> {:?}", try!(a::func()));
println!("b::func() -> {:?}", try!(b::func()));
Ok(())
}
So I definitely need to implement conversions from a::Error and b::Error for my Error type:
impl FromError<a::Error> for Error {
fn from_error(a::Error(contents): a::Error) -> Error {
Error(contents)
}
}
impl FromError<b::Error> for Error {
fn from_error(b::Error(contents): b::Error) -> Error {
Error(contents)
}
}
Ok, it works up until that time. And now I need to write something like this:
fn another_func() -> Result<(), Error> {
let _ = try!(<usize as std::str::FromStr>::from_str("14"));
Ok(())
}
And here a problem raises, because there is no conversion from num::ParseIntError to Error. So it seems that I have to implement it again. But why should I? There is a conversion implemented already from num::ParseIntError to b::Error, and there is also a conversion from b::Error to Error. So definitely there is a clean way for rust to convert one type to another without my explicit help.
So, I removed my impl FromError<b::Error> block and tried this blanket impl instead:
impl<E> FromError<E> for Error where b::Error: FromError<E> {
fn from_error(err: E) -> Error {
let b::Error(contents) = <b::Error as FromError<E>>::from_error(err);
Error(contents)
}
}
And it's even worked! However, I didn't succeed to repeat this trick with a::Error, because rustc started to complain about conflicting implementations:
experiment.rs:57:1: 62:2 error: conflicting implementations for trait `core::error::FromError` [E0119]
experiment.rs:57 impl<E> FromError<E> for Error where a::Error: FromError<E> {
experiment.rs:58 fn from_error(err: E) -> Error {
experiment.rs:59 let a::Error(contents) = <a::Error as FromError<E>>::from_error(err);
experiment.rs:60 Error(contents)
experiment.rs:61 }
experiment.rs:62 }
experiment.rs:64:1: 69:2 note: note conflicting implementation here
experiment.rs:64 impl<E> FromError<E> for Error where b::Error: FromError<E> {
experiment.rs:65 fn from_error(err: E) -> Error {
experiment.rs:66 let b::Error(contents) = <b::Error as FromError<E>>::from_error(err);
experiment.rs:67 Error(contents)
experiment.rs:68 }
experiment.rs:69 }
I can even understand the origin of problem (one type FromError<E> can be implemented both for a::Error and b::Error), but I can't get how to fix it.
Theoretically, maybe this is a wrong way and there is another solution for my problem? Or I still have to repeat manually all errors conversions in every new module?