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
Flatten an array of partial objects into struct #2069
Labels
Comments
Here a I believe little better implementation: use serde::{Deserialize, Deserializer};
use serde_json::json;
#[derive(Debug, Deserialize, PartialEq, Eq)]
struct Account {
id: usize,
}
#[derive(Debug, Deserialize, PartialEq, Eq)]
struct Session {
id: String,
}
#[derive(Debug, PartialEq, Eq)]
struct Response {
accounts: Vec<Account>,
session: Session,
}
impl<'de> Deserialize<'de> for Response {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::{Error, SeqAccess, Visitor};
#[derive(Deserialize)]
enum Item {
Account(Account),
Session(Session),
}
struct ResponseVisitor;
impl<'de> Visitor<'de> for ResponseVisitor {
type Value = Response;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("Response array structure")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut accounts = Vec::with_capacity(seq.size_hint().unwrap_or(0));
while let Some(item) = seq.next_element()? {
match item {
Item::Account(account) => accounts.push(account),
Item::Session(session) => {
while let Some(item) = seq.next_element()? {
match item {
Item::Account(account) => accounts.push(account),
Item::Session(_session) => {
return Err(Error::duplicate_field("Session"))
}
}
}
return Ok(Response { accounts, session });
}
}
}
Err(Error::missing_field("Session"))
}
}
deserializer.deserialize_seq(ResponseVisitor)
}
}
#[test]
fn test() {
let value = json!([
{
"Account": {
"id": 0,
}
},
{
"Account": {
"id": 1,
}
},
{
"Session": {
"id": "hello!"
}
},
]);
let response: Response = serde_json::from_value(value).unwrap();
assert_eq!(
response,
Response {
accounts: vec![Account { id: 0 }, Account { id: 1 },],
session: Session {
id: "hello!".to_string()
}
}
);
} |
If you're still looking for guidance on this, please take this question to one of the resources listed in https://github.com/serde-rs/serde/tree/v1.0.135#getting-help. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello there! First of all, thanks for the amazing project! :)
I have been digging through Serde's documentation on how to handle a specific case, but haven't been able to create a generic version so far. I'd greatly appreciate it if someone could give me some pointers on how to solve this deserialisation issue generically.
The problem
I'm trying to work with an API which formats its JSON responses as such:
Now, the issue is that some objects are guaranteed to only appear once (
Session
), while others are guaranteed to be a list (Account
). With those guarantees in mind, I would like to deserialise the response into the following structs:Handwritten
Deserialize
I've managed to write a handwritten
Deserialize
implementation (Playground, Gist). However, my question to you is whether there is room for improvement. Specifically:Field
andTemporary
?Wrapper<Response>
struct or adeserialize_with
function?Sources used
Thank you!
The text was updated successfully, but these errors were encountered: