Make my own error for serde_json Deserialize

Viewed 1321

I'm trying to deserialize a JSON file with a pre-existing format into my own, in Rust, using serde_json.

I'd like to do this by implementing a deserializer for the class.

My problem is that the JSON file could be malformed in such a way that raw_json_result could still decode just fine, but the resulting data structure would be itself malformed. In this case, I want to return an error.

What's the mechanism for forming a valid error object here? I'm thinking I want an Err(something_valid) line -- I just don't know how to make the something_valid.

impl<'de> Deserialize<'de> for MyClass {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        let raw_json_result = MyAliasedClassFromJson::deserialize(deserializer)?;
        MyClass::from_cal_json::<D>(cal_json)
    }
}
1 Answers

Assuming you have some MyError type, which implements Debug, Display, and Error. Then if you try to return Err(MyError::SomethingBadHappened) then the most straightforward way to get it working is to simply add .map_err(D::Error::custom).

Err(MyError::SomethingBadHappened).map_err(D::Error::custom)

Here's a short example:

use std::error;
use std::fmt;

// serde = "1.0"
use serde::de::Error;
use serde::{Deserialize, Deserializer};

#[derive(Debug)]
enum MyError {
    YouAreNotBob,
    // ...
}

impl error::Error for MyError {}

impl fmt::Display for MyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use MyError::*;
        match self {
            YouAreNotBob => write!(f, "YouAreNotBob"),
            // ...
        }
    }
}

pub fn deserialize_bob<'de, D>(deserializer: D) -> Result<String, D::Error>
where
    D: Deserializer<'de>,
{
    let string = String::deserialize(deserializer)?;

    if string == "bob" {
        Ok(string)
    } else {
        Err(MyError::YouAreNotBob).map_err(D::Error::custom)
    }
}
Related