- 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 {})
}
}
-
Now, I have a serde_json::Value
which I know is an Array(Array(Array(TokenLoc)))
-
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.???
1 Like
Use serde_json::from_value
:
let v: Value = ... ;
let ans: Vec<Vec<Vec<TokenLoc>>> = serde_json::from_value(v)?;
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);
@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 ?
How are you getting a serde_json::Value
inside a deserialize
implementation?
1 Like
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 {})
}
}
lol, the .as_array()
is also from serde_json
I am no longer sure why my code compiles + runs at all.
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.