Serde deserialize A to deserialize Vec<Vec<Vec<A>>>

#1
  1. I have implemented a custom serde deserialize for TokenLoc here:
use super::*;


use std::fs::File;
use std::io::prelude::*;
use std::fmt;
use serde_json::Value;
use serde::de::{Deserialize, Deserializer, Visitor};
use serde::de::SeqAccess;
use serde::de::MapAccess;

#[derive(Debug)]
pub struct TokenLoc {
    beg: i32,
    end: i32,
}

impl <'de> Deserialize<'de> for TokenLoc {
    fn deserialize<D>(deserializer: D) -> Result<TokenLoc, D::Error> where
        D: Deserializer<'de> {

        struct TokenLocVisitor;

        impl<'de> Visitor<'de> for TokenLocVisitor {
            type Value = TokenLoc;

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

            fn visit_seq<A>(self, mut seq: A) -> Result<TokenLoc, A::Error>
                where A: SeqAccess<'de>,
            {
                let beg = seq.next_element::<i32>()?.unwrap();
                let end = seq.next_element::<i32>()?.unwrap();
                Ok(TokenLoc { beg, end })
            }
        }
        deserializer.deserialize_seq(TokenLocVisitor {})
    }
}
  1. Now, I have a serde_json::Value which I know is an Array(Array(Array(TokenLoc)))

  2. My question is: is there a way to auto deserialize that? Pseudo code would be something like:

let v: Value = ... ;
let ans: Vec<Vec<Vec<TokenLoc>>> = v.???
#2

Use serde_json::from_value:

let v: Value = ... ;
let ans: Vec<Vec<Vec<TokenLoc>>> = serde_json::from_value(v)?;
#3

The following appears to work, but I don’t think it’s the idiomatic solution:

                        let a3: Value = v;
                        let ans: Vec<Vec<Vec<TokenLoc>>> =
                            a3.as_array().unwrap().iter()
                                .map(|a2| a2.as_array().unwrap().iter()
                                    .map(|a1| a1.as_array().unwrap().iter()
                                        .map(|a0|
                                            a0.deserialize_seq(TokenLocVisitor{}).unwrap()
                                        ).collect()
                                    ).collect()
                                ).collect() ;
                        println!("ans: {:?}", ans);
#4

@jethrogb : This code is part of implementing a

impl <'de> Deserialize<'de> for Article {
    fn deserialize<D>(deserializer: D) -> Result<Article, D::Error> where
        D: Deserializer<'de> {

        struct ArticleVisitor;

        impl<'de> Visitor<'de> for ArticleVisitor {

Is it possible to do this via merely serde instead of using serde_json ?

#5

How are you getting a serde_json::Value inside a deserialize implementation?

1 Like
#6

That’s a good point. I am already using serde_json without even noticing it. Can you point out everything I’m doing wrong with this, and how it should be written ? [The code currently “works”, but I am clearly doing something wrong.]

use super::*;


use std::fs::File;
use std::io::prelude::*;
use std::fmt;
use serde_json::Value;
use serde::de::{Deserialize, Deserializer, Visitor};
use serde::de::SeqAccess;
use serde::de::MapAccess;

#[derive(Debug)]
pub struct TokenLoc {
    beg: i32,
    end: i32,
}

struct TokenLocVisitor;
impl<'de> Visitor<'de> for TokenLocVisitor {
    type Value = TokenLoc;

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

    fn visit_seq<A>(self, mut seq: A) -> Result<TokenLoc, A::Error>
        where A: SeqAccess<'de>,
    {
        let beg = seq.next_element::<i32>()?.unwrap();
        let end = seq.next_element::<i32>()?.unwrap();
        Ok(TokenLoc {beg, end } )
    }
}


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


#[derive(Debug)]
pub struct Article {
    charoffset: Vec<Vec<Vec<TokenLoc>>>,
    text: Vec<Vec<String>>
}


impl <'de> Deserialize<'de> for Article {
    fn deserialize<D>(deserializer: D) -> Result<Article, D::Error> where
        D: Deserializer<'de> {

        struct ArticleVisitor;

        impl<'de> Visitor<'de> for ArticleVisitor {
            type Value = Article;

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

            fn visit_map<A>(self, mut access: A) -> Result<Article, A::Error>
                where
                    A: MapAccess<'de>,
            {
                let mut text = Vec::new();
                let mut charoffset = Vec::new();

                while let Some((k,v)) = access.next_entry::<Value, Value>()? {
                    if (k == "text") {
                        let a2: Value = v;
                        text =
                            a2.as_array().unwrap().iter()
                                .map(|a1| a1.as_array().unwrap().iter()
                                    .map( |a| a.as_str().unwrap().to_string()
                                    ).collect()
                                ).collect();
                        // println!("need to process text: {:?} ", v);

                    } else if (k == "charoffset") {
                        let a3: Value = v;
                        charoffset =
                            a3.as_array().unwrap().iter()
                                .map(|a2| a2.as_array().unwrap().iter()
                                    .map(|a1| a1.as_array().unwrap().iter()
                                        .map(|a0|
                                            a0.deserialize_seq(TokenLocVisitor{}).unwrap()
                                        ).collect()
                                    ).collect()
                                ).collect() ;
                        // println!("ans: {:?}", charoffset);
                    }
                }
                Ok(Article { text, charoffset })
            }
        }
        deserializer.deserialize_map(ArticleVisitor {})
    }
}
#7

lol, the .as_array() is also from serde_json

I am no longer sure why my code compiles + runs at all.

#8

Is there a reason you’re implementing Deserialize manually for Article instead of deriving it?

Anyway, if you need the manual implementation, you’re creating the Value here: access.next_entry::<Value, Value>()?. I think what you want instead is to call access.next_key::<String>()?, match on that, and then call access::next_value::<...>() with the appropriate type corresponding to the key you’re looking at.