I'm trying to include error_chain in a simple lib using Serde 1.0 for deserialization.
I added the serde_json Error type as a "foreign_link" like this:
error_chain! {
foreign_links {
IoError(io::Error);
JsonError(serde_json::error::Error);
}
}
I'm getting the following error though:
error[E0277]: the trait bound `error::Error: serde::Deserialize<'_>` is not satisfied
-->
|
59 | try!(serde_json::from_str(&buffer))
| ^^^^^^^^^^^^^^^^^^^^ the trait `serde::Deserialize<'_>` is not implemented for `error::Error`
|
= note: required because of the requirements on the impl of `serde::Deserialize<'_>` for `std::result::Result<serde_json::Value, error::Error>`
= note: required by `serde_json::from_str`
The problem is not error_chain specific, I've also tried to create a boilerplate Result and Error definition manually, and got the same error. Then I've added the derive(Deserialize) to the Error enum type, like the following:
#[derive(Deserialize)]
pub enum Error {
IoError(io::Error),
JsonError(serde_json::error::Error),
}
But my other linked Error types (io:Error in this example) are not implementing Deserialize of course, so it's also not viable.
What would be the ideal solution here? Is there an example for chaining / wrapping Serde Errors in libs somewhere?
Could you share the function that is calling from_str?
Minimal reproduction example code:
Cargo.toml
[package]
name = "test_lib"
version = "0.1.0"
authors = ["Juhasz Sandor <[email protected]>"]
[dependencies]
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
error-chain = "0.10.0"
src/lib.rs
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate error_chain;
mod error {
use std;
use serde_json;
error_chain!{
foreign_links {
IoError(std::io::Error);
JsonError(serde_json::error::Error);
}
}
}
use std::fs::File;
use std::io::Read;
#[derive(Deserialize)]
struct Data {
something: String
}
pub fn read_and_deserialize(file: File) -> error::Result<Data> {
let mut contents = String::new();
try!(file.read_to_string(&mut contents));
try!(serde_json::from_str(&contents))
}
Build result:
Compiling test_lib v0.1.0 (file:///D:/endticket/wash/test_lib)
error[E0277]: the trait bound `error::Error: serde::Deserialize<'_>` is not satisfied
--> src\lib.rs:31:10
|
31 | try!(serde_json::from_str(&contents))
| ^^^^^^^^^^^^^^^^^^^^ the trait `serde::Deserialize<'_>` is not implemented for `error::Error`
|
= note: required because of the requirements on the impl of `serde::Deserialize<'_>` for `std::result::Result<Data, error::Error>`
= note: required by `serde_json::from_str`
More minimal:
struct Error;
trait Deserialize {}
impl Deserialize for String {}
impl<T: Deserialize, E: Deserialize> Deserialize for Result<T, E> {}
fn read_and_deserialize() -> Result<String, Error> {
try!(from_str())
}
fn from_str<T: Deserialize>() -> Result<T, Error> {
unimplemented!()
}
Can you tell what is happening?
That's very interesting, so this problem is neither serde, nor error_chain dependant? The example code is not really valid though, because it doesn't really need the try! at all. Because the Error types are the same, it works fine without it. So here's a better example:
use std::convert;
struct Error;
struct OtherError;
impl convert::From<OtherError> for Error {
fn from(e: OtherError) -> Error {
Error
}
}
trait Deserialize {}
impl Deserialize for String {}
impl<T: Deserialize, E: Deserialize> Deserialize for Result<T, E> {}
fn read_and_deserialize() -> Result<String, Error> {
try!(from_str())
}
fn from_str<T: Deserialize>() -> Result<T, OtherError> {
unimplemented!()
}
So why does Result have to implement Deserialize at all? I tried to remove the implementation, and it's still not compiling, so I assume it does need it somehow (maybe Result itself is demanding it?). So as it seems, Result does have to implement Deserialize, but why E has to implement it as well? The from_str function only specifies the trait bound on the T type, not on the Error or the Result type.
I managed to compile it with the following code:
use std::convert;
struct Error;
struct OtherError;
impl convert::From<OtherError> for Error {
fn from(e: OtherError) -> Error {
Error
}
}
trait Deserialize {}
impl Deserialize for String {}
impl<T: Deserialize, E> Deserialize for Result<T, E> {}
fn read_and_deserialize() -> Result<String, Error> {
try!(from_str())
}
fn from_str<T: Deserialize>() -> Result<T, OtherError> {
unimplemented!()
}
So maybe error_chain is generating wrong code for the Result type? Anyway, Serde is definitely not the culprit here, so feel free to close this.
Thanks
Well look at the first piece of code in your most recent comment.
from_str() returns Result<??, OtherError> for some type ?? that needs to be inferred.try! macro takes input of type Result<A, B> and gives output of type A.try!(from_str!()) is the same ?? that still needs to be inferred.read_and_deserialize() returns type Result<String, Error>.read_and_deserialize() returns the value try!(from_str!()).try!(from_str!()) is equal to Result<String, Error>.?? is inferred to be Result<String, Error>.from_str is invoked with T equal to Result<String, Error>.from_str requires T: Deserialize.Result<String, Error>: Deserialize.Result<A, B> if and only if A: Deserialize and B: Deserialize.String: Deserialize and Error: Deserialize.Thanks for the detailed explanation. I've realized I have a problem with the inferred types and the return type. I've solved this by putting the last try! macro in an Ok(). It wasn't really readable, so I've put the result of the last try! into a variable and return the Ok(variable) in the next line to make it more explicit.
Here is the final code for reference to others, it works fine:
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate error_chain;
mod error {
use std;
use serde_json;
error_chain!{
foreign_links {
IoError(std::io::Error);
JsonError(serde_json::error::Error);
}
}
}
use std::fs::File;
use std::io::Read;
#[derive(Deserialize)]
pub struct Data {
something: String,
}
pub fn read_and_deserialize(file: &mut File) -> error::Result<Data> {
let mut contents = String::new();
try!(file.read_to_string(&mut contents));
let res = try!(serde_json::from_str(&contents));
Ok(res)
}
Most helpful comment
Well look at the first piece of code in your most recent comment.
from_str()returnsResult<??, OtherError>for some type??that needs to be inferred.try!macro takes input of typeResult<A, B>and gives output of typeA.try!(from_str!())is the same??that still needs to be inferred.read_and_deserialize()returns typeResult<String, Error>.read_and_deserialize()returns the valuetry!(from_str!()).try!(from_str!())is equal toResult<String, Error>.??is inferred to beResult<String, Error>.from_stris invoked withTequal toResult<String, Error>.from_strrequiresT: Deserialize.Result<String, Error>: Deserialize.Result<A, B>if and only ifA: DeserializeandB: Deserialize.String: DeserializeandError: Deserialize.