7

I would like to build a custom deserializer to deserialize an array of arrays of values into a Vec<Child> where I have already written a custom serde deserializer to parse an array of values into a Child.

One idea would be to add a customer deserializer for a Vec<Child> directly but I was wondering whether a more elegant solution would exist.


As an illustration I'm trying to make something like the below but with field array in Parent instead of single.

extern crate serde_json; // 1.0.32
extern crate serde; // 1.0.80
#[macro_use] extern crate serde_derive;

use serde::de::{Deserializer, SeqAccess, Visitor};
use std::fmt;

#[derive(Debug, Deserialize)]
struct Parent {
    #[serde(deserialize_with = "parse_child")]
    single: Child,
    //#[serde(deserialize_with = "parse_child")]
    //array: Vec<Child>,
}

#[derive(Default, Debug, Deserialize)]
struct Child {
    a: u64,
    b: f32,
    c: usize,
}

fn parse_child<'de, D>(deserializer: D) -> Result<Child, D::Error>
where
    D: Deserializer<'de>,
{
    struct ChildParser;
    impl<'de> Visitor<'de> for ChildParser
    {
        type Value = Child;

        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
            formatter.write_str("[u64, f32, usize]")
        }

        fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
            println!("In custom deserializer");
            let mut child = Child { ..Default::default() };

            let tmp = seq.next_element::<u64>()?;
            if let Some(a) = tmp {
                child.a = a;
            };

            let tmp = seq.next_element::<f32>()?;
            if let Some(b) = tmp {
                child.b = b;
            };

            let tmp = seq.next_element::<usize>()?;
            if let Some(c) = tmp {
                child.c = c;
            };

            Ok(child)
        }
    }

    deserializer.deserialize_any(ChildParser{})
}

fn main() {
    let child_data = r#"[49, 11.75, 0]"#;
    let child : Child = serde_json::from_str(child_data).unwrap();
    println!("Child = {:?}", &child);

    let parent_data = r#"{"single": [49, 11.75, 0]}"#;
    let parent : Parent = serde_json::from_str(parent_data).expect("to be able to deserialize it");
    println!("Parent = {:?}", &parent);

}

Link to a playground

Sample input I want to deserialize: [[49, 11.75, 0], [42, 9, 1]]

Boris
  • 991
  • 1
  • 9
  • 15
  • 1
    @Stargateur there you go. Any idea on how I could solve this? – Boris Nov 13 '18 at 14:05
  • That much better but your question is still unclear. We don't know if you want to be able to deserialize `r#"{"single": [49, 11.75, 0]}"#` or `r#"[[49, 11.75, 0], [42, 9, 1]]"#` or both. – Stargateur Nov 13 '18 at 16:27
  • 2
    What trouble you with `let parent: Vec = serde_json::from_str(parent_data).unwrap()` ? – Stargateur Nov 13 '18 at 16:34

2 Answers2

7

I would implement this as:

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

#[derive(Deserialize, Debug)]
#[serde(transparent)]
struct Parent {
    array: Vec<Child>,
}

#[derive(Deserialize, Debug)]
struct Child {
    a: u64,
    b: f32,
    c: usize,
}

fn main() {
    let j = r#" [[49, 11.75, 0], [42, 9, 1]] "#;
    println!("{:#?}", serde_json::from_str::<Parent>(j).unwrap());
}

Or more concisely:

#[macro_use]
extern crate serde_derive;

extern crate serde;
extern crate serde_json;

#[derive(Deserialize, Debug)]
struct Child {
    a: u64,
    b: f32,
    c: usize,
}

fn main() {
    let j = r#" [[49, 11.75, 0], [42, 9, 1]] "#;
    let array: Vec<Child> = serde_json::from_str(j).unwrap();
    println!("{:#?}", array);
}
dtolnay
  • 9,621
  • 5
  • 41
  • 62
  • Thanks a lot @dtolnay that's a super neat way to do it indeed. I didn't know (or understand) serde could deserialize struct from arrays directly – Boris Nov 13 '18 at 19:23
  • I'd suggest adding the `transparent` example to the linked duplicate. – Shepmaster Nov 15 '18 at 15:27
0

I'm not sure if this is what you want but using the doc for deserialize a map:

extern crate serde; // 1.0.80
extern crate serde_json; // 1.0.32

use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
use std::fmt;

#[derive(Debug)]
struct Child {
    a: u64,
    b: f32,
    c: usize,
}

struct ChildVisitor;

impl<'de> Visitor<'de> for ChildVisitor {
    type Value = Child;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("[u64, f32, usize]")
    }

    fn visit_seq<A: SeqAccess<'de>>(self, mut access: A) -> Result<Self::Value, A::Error> {
        let a = access.next_element::<u64>()?.unwrap_or(Default::default());

        let b = access.next_element::<f32>()?.unwrap_or(Default::default());

        let c = access
            .next_element::<usize>()?
            .unwrap_or(Default::default());

        Ok(Child { a, b, c })
    }
}

impl<'de> Deserialize<'de> for Child {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_seq(ChildVisitor {})
    }
}

#[derive(Debug)]
struct Parent {
    childs: Vec<Child>,
}

struct ParentVisitor {}

impl<'de> Visitor<'de> for ParentVisitor {
    type Value = Parent;

    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("[[Child]]")
    }

    fn visit_seq<A: SeqAccess<'de>>(self, mut access: A) -> Result<Self::Value, A::Error> {
        let mut childs = Vec::with_capacity(access.size_hint().unwrap_or(0));

        while let Some(child) = access.next_element::<Child>()? {
            childs.push(child);
        }

        Ok(Parent { childs })
    }
}

impl<'de> Deserialize<'de> for Parent {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        deserializer.deserialize_seq(ParentVisitor {})
    }
}

fn main() {
    let child_data = r#"[49, 11.75, 0]"#;
    let child: Child = serde_json::from_str(child_data).unwrap();
    println!("Child = {:#?}", child);

    let parent_data = r#"[[49, 11.75, 0], [42, 9, 1]]"#;
    let parent: Parent = serde_json::from_str(parent_data).unwrap();
    println!("Parent = {:#?}", parent);
}
Stargateur
  • 24,473
  • 8
  • 65
  • 91
  • Thanks @Stargateur indeed I just needed to implement manually `Deserialize` for `Child` instead of deriving it – Boris Nov 13 '18 at 19:12