-
-
Notifications
You must be signed in to change notification settings - Fork 774
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Catch-all field when deserializing struct #827
Comments
Here is one possible approach. extern crate serde;
extern crate serde_json;
use std::collections::BTreeMap as Map;
use std::fmt;
use serde::de::{self, Deserialize, Deserializer, Visitor, MapVisitor};
use serde_json::Value;
#[derive(Debug)]
struct Vorner {
first: u8,
second: String,
rest: Map<String, Value>,
}
impl Deserialize for Vorner {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer
{
struct VornerVisitor;
impl Visitor for VornerVisitor {
type Value = Vorner;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct Vorner with arbitrary fields")
}
fn visit_map<V>(self, mut visitor: V) -> Result<Vorner, V::Error>
where V: MapVisitor
{
let mut first = None;
let mut second = None;
let mut rest = Map::new();
while let Some(key) = visitor.visit_key::<String>()? {
match key.as_str() {
"first" => {
if first.is_some() {
return Err(de::Error::duplicate_field("first"));
}
first = Some(visitor.visit_value()?);
}
"second" => {
if second.is_some() {
return Err(de::Error::duplicate_field("second"));
}
second = Some(visitor.visit_value()?);
}
_ => {
rest.insert(key, visitor.visit_value()?);
}
}
}
let first = first.ok_or_else(|| de::Error::missing_field("first"))?;
let second = second.ok_or_else(|| de::Error::missing_field("first"))?;
Ok(Vorner {
first: first,
second: second,
rest: rest,
})
}
}
deserializer.deserialize_map(VornerVisitor)
}
}
fn main() {
let j = r#" {"first":0,"second":"vorner","a":"A","b":"B"} "#;
let v: Vorner = serde_json::from_str(j).unwrap();
println!("{:?}", v);
} |
Here is another possible approach that is less code, but I would encourage you to learn the first approach because it is more flexible, gives better error messages, and will be more valuable to you in other situations. extern crate serde;
extern crate serde_json;
use std::collections::BTreeMap as Map;
use serde::de::{self, Deserialize, Deserializer};
use serde_json::Value;
#[derive(Debug)]
struct Vorner {
first: u8,
second: String,
rest: Map<String, Value>,
}
impl Deserialize for Vorner {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer
{
let mut all = Map::deserialize(deserializer)?;
let first = all.remove("first")
.ok_or_else(|| de::Error::missing_field("first"))
.map(Deserialize::deserialize)?
.map_err(de::Error::custom)?;
let second = all.remove("second")
.ok_or_else(|| de::Error::missing_field("second"))
.map(Deserialize::deserialize)?
.map_err(de::Error::custom)?;
Ok(Vorner {
first: first,
second: second,
rest: all,
})
}
}
fn main() {
let j = r#" {"first":0,"second":"ajd","a":"A","b":"B"} "#;
let v: Vorner = serde_json::from_str(j).unwrap();
println!("{:?}", v);
} |
Perhaps serde's |
To anyone finding this issue, instead of the other. Then this is indeed possible using See the other issue for an example: #941 (comment) |
From IRC:
@vorner
The text was updated successfully, but these errors were encountered: