Last active
September 6, 2018 17:24
-
-
Save gaganjakhotiya/063653aeafb4c80540b7adc314531661 to your computer and use it in GitHub Desktop.
Serde Custom Deserializer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[macro_use] | |
extern crate serde_json; | |
#[macro_use] | |
extern crate serde_derive; | |
extern crate serde; | |
use serde::{ | |
de::{Error, MapAccess, Unexpected, Visitor}, | |
Deserialize, Deserializer, | |
}; | |
use std::fmt; | |
#[derive(Clone, Debug, Serialize)] | |
struct Galaxy { | |
name: Option<String>, | |
total_stars: Option<i32>, | |
} | |
impl<'de> Deserialize<'de> for Galaxy { | |
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | |
where | |
D: Deserializer<'de>, | |
{ | |
struct GalaxyVisitor; | |
impl<'de> Visitor<'de> for GalaxyVisitor { | |
type Value = Galaxy; | |
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { | |
formatter.write_str("valid Galaxy") | |
} | |
fn visit_map<D>(self, mut map: D) -> Result<Self::Value, D::Error> | |
where | |
D: MapAccess<'de>, | |
{ | |
let mut galaxy = Galaxy { | |
name: None, | |
total_stars: None, | |
}; | |
while let Some((key, value)) = map.next_entry::<String, serde_json::Value>()? { | |
match &key[..] { | |
"name" => { | |
galaxy.name = Some( | |
serde_json::from_value::<String>(value.clone()).map_err(|_| { | |
D::Error::invalid_type( | |
Unexpected::Other(format!("{:?}", value).as_ref()), | |
&self, | |
) | |
})?, | |
); | |
Ok(())? | |
} | |
"total_stars" => { | |
galaxy.total_stars = Some(match serde_json::from_value::<i32>( | |
value.clone(), | |
) { | |
Ok(val) => Ok(val), | |
_ => match serde_json::from_value::<String>(value.clone()) { | |
Ok(val) => val.parse::<i32>().map_err(|_| { | |
D::Error::invalid_type(Unexpected::Str(val.as_ref()), &self) | |
}), | |
_ => Err(D::Error::invalid_value( | |
Unexpected::Other(format!("{:?}", value).as_ref()), | |
&self, | |
)), | |
}, | |
}?); | |
Ok(())? | |
} | |
_ => {} | |
} | |
} | |
Ok(galaxy) | |
} | |
} | |
deserializer.deserialize_struct("Galaxy", &["name", "total_stars"], GalaxyVisitor) | |
} | |
} | |
fn main() { | |
println!( | |
"{:?}\n{:?}\n{:?}\n{:?}\n{:?}\n{:?}", | |
serde_json::from_value::<Galaxy>(json!({ "total_stars": "3131231", "name": "Backyard" })), // Ok | |
serde_json::from_value::<Galaxy>(json!({ "total_stars": 989031213, "name": "Rooftop" })), // Ok | |
serde_json::from_value::<Galaxy>(json!({ "name": "Unknown" })), // Ok | |
serde_json::from_value::<Galaxy>(json!({ "total_stars": 0 })), // Ok | |
serde_json::from_value::<Galaxy>(json!({ "total_stars": "aa" })), // Err | |
serde_json::from_value::<Galaxy>(json!({ "name": 231 })), // Err | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment