Instead of defining a field as optional and collect both Nones and Somes like the following:
extern crate serde;
extern crate serde_json;
use serde::Deserialize;
#[derive(Debug, Deserialize, PartialEq)]
struct Bar {
a: u32,
b: Option<u32>,
}
#[derive(Debug, Deserialize, PartialEq)]
struct Foo {
vec: Vec<Bar>,
}
fn main() {
let data = r#"{ "vec": [ { "a": 1 }, { "a": 2, "b": 3 } ] }"#;
assert_eq!(
serde_json::from_str::<Foo>(data).unwrap(),
Foo {
vec: vec![Bar { a: 1, b: None }, Bar { a: 2, b: Some(3) }]
}
);
}
It would be nice to only collect fully defined elements so the Bar struct could be defined as struct Bar { a: u32, b: u32 } and serde_json::from_str would simply return Foo { vec: [ Bar { a: 2, b: 3 } ] }.
How to achieve such behavior? Here is my unsuccessful attempt to create a custom Deserialize implementation that tries to tackle this.
extern crate serde;
extern crate serde_json;
use core::fmt;
use serde::{
de::{SeqAccess, Visitor},
Deserialize, Deserializer,
};
#[derive(Debug, Deserialize)]
struct Bar {
a: i32,
b: i32,
c: i32,
}
#[derive(Debug)]
struct VecOpt(Vec<Bar>);
impl<'de> Deserialize<'de> for VecOpt {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ArrayVecVisitor;
impl<'de> Visitor<'de> for ArrayVecVisitor {
type Value = VecOpt;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "VecOpt")
}
fn visit_seq<SA>(self, mut seq: SA) -> Result<Self::Value, SA::Error>
where
SA: SeqAccess<'de>,
{
let mut values = Vec::new();
loop {
match seq.next_element::<Bar>() {
Ok(Some(x)) => values.push(x),
Ok(None) => break,
// If error, the input reader won't move to the next element of the sequence and the following `seq.next_element` will
// simply try to read contents of the current element. In this case, `"c": 5 }, ... `
Err(_) => {}
}
}
Ok(VecOpt(values))
}
}
deserializer.deserialize_seq(ArrayVecVisitor)
}
}
#[derive(Debug, Deserialize)]
struct Foo {
vec: VecOpt,
}
fn main() {
let data = r#"{ "vec": [ { "a": 1 "b": 2, "c": 3 }, { "b": 4, "c": 5 }, { "a": 6 "b": 7, "c": 8 } ] }"#;
dbg!(serde_json::from_str::<Foo>(data).unwrap());
}
Your code worked for the most part but invalid JSON literal in the main, which missed couple commas, tripped it over. The problem is that the Err(_) branch swallowed all errors indiscriminately; it should have only silenced missing field error:
fn visit_seq<SA>(self, mut seq: SA) -> Result<Self::Value, SA::Error>
where
SA: SeqAccess<'de>,
{
let mut values = Vec::new();
loop {
match seq.next_element::<Bar>() {
Ok(Some(x)) => values.push(x),
Ok(None) => break,
Err(e) => {
if !e.to_string().starts_with("missing field") {
return Err(e);
}
}
}
}
Ok(VecOpt(values))
}
TBH I really don't like this solution although it worked. Option is a perfect fit here for modelling the potentially missing fields.
Related
I have JSON objects with the following format:
{
"name": "foo",
"value": 1234,
"upper_bound": 5000,
"lower_bound": 1000
}
I'd like to use serde to work with these objects, with a struct like
struct MyObject {
name: String,
value: i32,
bound: Range<i32>,
}
Without any modifications, serializing one of these structs yields
{
"name": "foo",
"value": 1234,
"bound": {
"start": 1000,
"end": 5000
}
}
I can apply #[serde(flatten)] to get closer, yielding
{
"name": "foo",
"value": 1234,
"start": 1000,
"end": 5000
}
But adding #[serde(rename...)] doesn't seem to change anything, no matter what kind of arguments I try giving to the rename. Is it possible to flatten the range, and rename the args?
You can use serde attribute with and just use a intermediate structure letting the real implementation to serde:
use core::ops::Range;
use serde::{Deserialize, Serialize};
use serde_json::Error;
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
struct Foo {
name: String,
value: i32,
#[serde(with = "range_aux", flatten)]
bound: Range<i32>,
}
mod range_aux {
use core::ops::Range;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Serialize, Deserialize)]
struct RangeAux {
upper_bound: i32,
lower_bound: i32,
}
pub fn serialize<S>(range: &Range<i32>, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
RangeAux::serialize(
&RangeAux {
upper_bound: range.end,
lower_bound: range.start,
},
ser,
)
}
pub fn deserialize<'de, D>(d: D) -> Result<Range<i32>, D::Error>
where
D: Deserializer<'de>,
{
let range_aux: RangeAux = RangeAux::deserialize(d)?;
Ok(Range {
start: range_aux.lower_bound,
end: range_aux.upper_bound,
})
}
}
fn main() -> Result<(), Error> {
let data = r#"{"name":"foo","value":1234,"upper_bound":5000,"lower_bound":1000}"#;
let foo: Foo = serde_json::from_str(data)?;
assert_eq!(
foo,
Foo {
name: "foo".to_string(),
value: 1234,
bound: 1000..5000
}
);
let output = serde_json::to_string(&foo)?;
assert_eq!(data, output);
Ok(())
}
That very close to remote pattern but this doesn't work with generic see serde#1844.
A possible generic version:
use core::ops::Range;
use serde::{Deserialize, Serialize};
use serde_json::Error;
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
struct Foo {
name: String,
value: i32,
#[serde(with = "range_aux", flatten)]
bound: Range<i32>,
}
mod range_aux {
use core::ops::Range;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub fn serialize<S, Idx: Serialize>(range: &Range<Idx>, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// could require Idx to be Copy or Clone instead of borrowing Idx
#[derive(Serialize)]
struct RangeAux<'a, Idx> {
upper_bound: &'a Idx,
lower_bound: &'a Idx,
}
RangeAux::serialize(
&RangeAux {
upper_bound: &range.end,
lower_bound: &range.start,
},
ser,
)
}
pub fn deserialize<'de, D, Idx: Deserialize<'de>>(d: D) -> Result<Range<Idx>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct RangeAux<Idx> {
upper_bound: Idx,
lower_bound: Idx,
}
let range_aux: RangeAux<Idx> = RangeAux::deserialize(d)?;
Ok(Range {
start: range_aux.lower_bound,
end: range_aux.upper_bound,
})
}
}
fn main() -> Result<(), Error> {
let data = r#"{"name":"foo","value":1234,"upper_bound":5000,"lower_bound":1000}"#;
let foo: Foo = serde_json::from_str(data)?;
assert_eq!(
foo,
Foo {
name: "foo".to_string(),
value: 1234,
bound: 1000..5000
}
);
let output = serde_json::to_string(&foo)?;
assert_eq!(data, output);
Ok(())
}
Not necessarily more concise than a custom serializer, but certainly a good bit more trivial is a solution with [serde(from and into)]. (I feel like I'm posting this on every serde question. :/)
You define an auxiliary, serializable struct that has the JSON structure you want:
#[derive(Deserialize, Serialize, Clone)]
struct AuxMyObject {
name: String,
value: i32,
upper_bound: i32,
lower_bound: i32,
}
Then you explain to rust how your auxiliary struct relates to the original struct. It's a bit tedious (but easy), there may be some macro crates that help lessen the typing load:
impl From<MyObject> for AuxMyObject {
fn from(from: MyObject) -> Self {
Self {
name: from.name,
value: from.value,
lower_bound: from.bound.start,
upper_bound: from.bound.end,
}
}
}
impl From<AuxMyObject> for MyObject {
fn from(from: AuxMyObject) -> Self {
Self {
name: from.name,
value: from.value,
bound: Range {
start: from.lower_bound,
end: from.upper_bound,
},
}
}
}
Lastly, you tell serde to replace your main struct with the auxiliary struct when serializing:
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(from = "AuxMyObject", into = "AuxMyObject")]
struct MyObject { … }
Playground
Serde ignores unknown named fields when deserializing into regular structs. How can I similarly ignore extra items when deserializing into tuple structs (e.g. from a heterogeneous JSON array)?
For example, this code ignores the extra "c" field just fine:
#[derive(Serialize, Deserialize, Debug)]
pub struct MyStruct { a: String, b: i32 }
fn test_deserialize() -> MyStruct {
::serde_json::from_str::<MyStruct>(r#"
{
"a": "foo",
"b": 123,
"c": "ignore me"
}
"#).unwrap()
}
// => MyStruct { a: "foo", b: 123 }
By contrast, this fails on the extra item in the tuple:
#[derive(Serialize, Deserialize, Debug)]
pub struct MyTuple(String, i32);
fn test_deserialize_tuple() -> MyTuple {
::serde_json::from_str::<MyTuple>(r#"
[
"foo",
123,
"ignore me"
]
"#).unwrap()
}
// => Error("trailing characters", line: 5, column: 13)
I'd like to allow extra items for forward compatibility in my data format. What's the easiest way to get Serde to ignore extra tuple items when deserializing?
You can implement a custom Visitor which ignores rest of the sequence. Be aware that the whole sequence must be consumed. This is an important part (try to remove it and you'll get same error):
// This is very important!
while let Some(IgnoredAny) = seq.next_element()? {
// Ignore rest
}
Here's a working example:
use std::fmt;
use serde::de::{self, Deserialize, Deserializer, IgnoredAny, SeqAccess, Visitor};
use serde::Serialize;
#[derive(Serialize, Debug)]
pub struct MyTuple(String, i32);
impl<'de> Deserialize<'de> for MyTuple {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct MyTupleVisitor;
impl<'de> Visitor<'de> for MyTupleVisitor {
type Value = MyTuple;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("struct MyTuple")
}
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let s = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
let n = seq
.next_element()?
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
// This is very important!
while let Some(IgnoredAny) = seq.next_element()? {
// Ignore rest
}
Ok(MyTuple(s, n))
}
}
deserializer.deserialize_seq(MyTupleVisitor)
}
}
fn main() {
let two_elements = r#"["foo", 123]"#;
let three_elements = r#"["foo", 123, "bar"]"#;
let tuple: MyTuple = serde_json::from_str(two_elements).unwrap();
assert_eq!(tuple.0, "foo");
assert_eq!(tuple.1, 123);
let tuple: MyTuple = serde_json::from_str(three_elements).unwrap();
assert_eq!(tuple.0, "foo");
assert_eq!(tuple.1, 123);
}
For JSON, I'd combine RawValue and a custom deserialization:
use serde::{Deserialize, Deserializer};
#[derive(Debug)]
struct MyTuple(String, i32);
#[derive(Deserialize, Debug)]
struct MyTupleFutureCompat<'a>(
String,
i32,
#[serde(default, borrow)] Option<&'a serde_json::value::RawValue>,
);
impl<'de> Deserialize<'de> for MyTuple {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let t: MyTupleFutureCompat = Deserialize::deserialize(deserializer)?;
Ok(MyTuple(t.0, t.1))
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let json = r#"[
"foo",
123,
"ignore me"
]"#;
let d: MyTuple = serde_json::from_str(json)?;
println!("{:?}", d);
Ok(())
}
See also:
How to transform fields during deserialization using Serde?
Is there a way to deserialize arbitrary JSON using Serde without creating fine-grained objects?
Why can Serde not derive Deserialize for a struct containing only a &Path?
This question already has an answer here:
How can I deserialize JSON with a top-level array using Serde?
(1 answer)
Closed 4 years ago.
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]]
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);
}
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);
}
I have a group of different messages that come in as JSON and can be distinguished based on a single field, but then each variant has a different collection of secondary fields:
#[derive(Debug, Serialize, Deserialize)]
struct MessageOne {
///op will always be "one"
op: String,
x: f64,
y: f64,
}
#[derive(Debug, Serialize, Deserialize)]
struct MessageTwo {
///op will always be "two"
op: String,
a: f64,
b: i64,
}
The different message types are routed to different processing functions (e.g. process_message_one, process_message_two, etc). Is there an elegant or idiomatic way to automatically select the correct message sub-type? Currently I've defined a generic message:
#[derive(Debug, Serialize, Deserialize)]
struct MessageGeneric {
op: String,
}
then parse the incoming JSON into the MessageGeneric, read the op field and then deserialize again, matching on op to select the correct message type. Full example:
#![allow(unused)]
extern crate serde; // 1.0.78
extern crate serde_json; // 1.0.27
#[macro_use]
extern crate serde_derive;
use std::collections::HashMap;
#[derive(Debug, Serialize, Deserialize)]
struct MessageGeneric {
op: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct MessageOne {
///op will always be "one"
op: String,
x: f64,
y: f64,
}
#[derive(Debug, Serialize, Deserialize)]
struct MessageTwo {
///op will always be "two"
op: String,
a: f64,
b: f64,
}
fn process_message_one(m: &MessageOne) {
println!("Processing a MessageOne: {:?}", m);
}
fn process_message_two(m: &MessageTwo) {
println!("Processing a MessageTwo: {:?}", m);
}
fn main() {
let data = r#"{
"op": "one",
"x": 1.0,
"y": 2.0
}"#;
let z: MessageGeneric = serde_json::from_str(data).unwrap();
match z.op.as_ref() {
"one" => {
let zp: MessageOne = serde_json::from_str(data).unwrap();
process_message_one(&zp);
},
"two" => {
let zp: MessageTwo = serde_json::from_str(data).unwrap();
process_message_two(&zp);
},
_ => println!("Unknown Message Type")
}
}
I've seen Serde's enum representations but it was unclear to me if/how that would be applied in this case. The messages coming in are defined by an external API, so I can't control their content beyond knowing what the variants are.
There is no point to keep "one" or "two" in your structure MessageOne and MessageTwo: if you have constructed this structure you already know if it is message one or message two.
extern crate serde; // 1.0.78
extern crate serde_json; // 1.0.27
#[macro_use]
extern crate serde_derive;
#[derive(Serialize, Deserialize, Debug)]
#[serde(tag = "op")]
enum Message {
#[serde(rename = "one")]
One { x: f64, y: f64 },
#[serde(rename = "two")]
Two { a: f64, b: f64 },
}
fn process_message(message: &Message) {
println!("Processing a : {:?}", message);
}
use serde_json::Error;
fn main() -> Result<(), Error> {
let data = r#"{
"op": "one",
"x": 1.0,
"y": 2.0
}"#;
let message: Message = serde_json::from_str(data)?;
process_message(&message);
let data = r#"{
"op": "two",
"a": 1.0,
"b": 2.0
}"#;
let message: Message = serde_json::from_str(data)?;
process_message(&message);
let data = r#"{
"op": "42",
"i": 1.0,
"j": 2.0
}"#;
let message: Message = serde_json::from_str(data)?;
process_message(&message);
Ok(())
}
Standard Output
Processing a : One { x: 1.0, y: 2.0 }
Processing a : Two { a: 1.0, b: 2.0 }
Standard Error
Error: Error("unknown variant `42`, expected `one` or `two`", line: 2, column: 18)
I'm writing a crate that interfaces with a JSON web API. One endpoint usually returns responses of the form { "key": ["value1", "value2"] }, but sometimes there's only one value for the key, and the endpoint returns { "key": "value" } instead of { "key": ["value"] }
I wanted to write something generic for this that I could use with #[serde(deserialize_with)] like so:
#[derive(Deserialize)]
struct SomeStruct {
#[serde(deserialize_with = "deserialize_string_or_seq_string")]
field1: Vec<SomeStringNewType>,
#[serde(deserialize_with = "deserialize_string_or_seq_string")]
field2: Vec<SomeTypeWithCustomDeserializeFromStr>,
}
#[derive(Deserialize)]
struct SomeStringNewType(String);
struct SomeTypeWithCustomDeserializeFromStr(String);
impl ::serde::de::Deserialize for SomeTypeWithCustomDeserializeFromStr {
// Some custom implementation here
}
How can I write a deserialize_string_or_seq_string to be able to do this?
In case you want to deserialize a single string or a list of strings into the more general Vec<String> instead of a custom type, the following is a simpler solution for Serde 1.0:
extern crate serde;
#[macro_use] extern crate serde_derive;
extern crate serde_json;
use std::fmt;
use std::marker::PhantomData;
use serde::de;
use serde::de::{Deserialize, Deserializer};
#[derive(Deserialize, Debug, Clone)]
pub struct Parent {
#[serde(deserialize_with = "string_or_seq_string")]
pub strings: Vec<String>,
}
fn main() {
let list_of_strings: Parent = serde_json::from_str(r#"{ "strings": ["value1", "value2"] }"#).unwrap();
println!("list of strings: {:?}", list_of_strings);
// Prints:
// list of strings: Parent { strings: ["value1", "value2"] }
let single_string: Parent = serde_json::from_str(r#"{ "strings": "value" }"#).unwrap();
println!("single string: {:?}", single_string);
// Prints:
// single string: Parent { strings: ["value"] }
}
fn string_or_seq_string<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where D: Deserializer<'de>
{
struct StringOrVec(PhantomData<Vec<String>>);
impl<'de> de::Visitor<'de> for StringOrVec {
type Value = Vec<String>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("string or list of strings")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where E: de::Error
{
Ok(vec![value.to_owned()])
}
fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error>
where S: de::SeqAccess<'de>
{
Deserialize::deserialize(de::value::SeqAccessDeserializer::new(visitor))
}
}
deserializer.deserialize_any(StringOrVec(PhantomData))
}
This solution also works under the 0.9 release of Serde with the following changes:
remove the lifetimes
SeqAccess -> SeqVisitor
SeqAccessDeserializer -> SeqVisitorDeserializer
MapAccess -> MapVisitor
MapAccessDeserializer -> MapVisitorDeserializer
This solution works for Serde 1.0.
The way I found also required me to write a custom deserializer, because I needed one that would call visitor.visit_newtype_struct to try deserializing newtypes, and there don't seem to be any in-built into serde that do so. (I was expecting something like the ValueDeserializer series of types.)
A self-contained example is below. The SomeStruct is deserialized correctly for both inputs, one where the values are JSON arrays of strings, and the other where they're just strings.
#[macro_use]
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
fn main() {
#[derive(Debug, Deserialize)]
struct SomeStringNewType(String);
#[derive(Debug)]
struct SomeTypeWithCustomDeserializeFromStr(String);
impl<'de> ::serde::Deserialize<'de> for SomeTypeWithCustomDeserializeFromStr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: ::serde::Deserializer<'de> {
struct Visitor;
impl<'de> ::serde::de::Visitor<'de> for Visitor {
type Value = SomeTypeWithCustomDeserializeFromStr;
fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "a string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: ::serde::de::Error {
Ok(SomeTypeWithCustomDeserializeFromStr(v.to_string() + " custom"))
}
}
deserializer.deserialize_any(Visitor)
}
}
#[derive(Debug, Deserialize)]
struct SomeStruct {
#[serde(deserialize_with = "deserialize_string_or_seq_string")]
field1: Vec<SomeStringNewType>,
#[serde(deserialize_with = "deserialize_string_or_seq_string")]
field2: Vec<SomeTypeWithCustomDeserializeFromStr>,
}
let x: SomeStruct = ::serde_json::from_str(r#"{ "field1": ["a"], "field2": ["b"] }"#).unwrap();
println!("{:?}", x);
assert_eq!(x.field1[0].0, "a");
assert_eq!(x.field2[0].0, "b custom");
let x: SomeStruct = ::serde_json::from_str(r#"{ "field1": "c", "field2": "d" }"#).unwrap();
println!("{:?}", x);
assert_eq!(x.field1[0].0, "c");
assert_eq!(x.field2[0].0, "d custom");
}
/// Deserializes a string or a sequence of strings into a vector of the target type.
pub fn deserialize_string_or_seq_string<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
where T: ::serde::Deserialize<'de>, D: ::serde::Deserializer<'de> {
struct Visitor<T>(::std::marker::PhantomData<T>);
impl<'de, T> ::serde::de::Visitor<'de> for Visitor<T>
where T: ::serde::Deserialize<'de> {
type Value = Vec<T>;
fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "a string or sequence of strings")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where E: ::serde::de::Error {
let value = {
// Try parsing as a newtype
let deserializer = StringNewTypeStructDeserializer(v, ::std::marker::PhantomData);
::serde::Deserialize::deserialize(deserializer)
}.or_else(|_: E| {
// Try parsing as a str
let deserializer = ::serde::de::IntoDeserializer::into_deserializer(v);
::serde::Deserialize::deserialize(deserializer)
})?;
Ok(vec![value])
}
fn visit_seq<A>(self, visitor: A) -> Result<Self::Value, A::Error>
where A: ::serde::de::SeqAccess<'de> {
::serde::Deserialize::deserialize(::serde::de::value::SeqAccessDeserializer::new(visitor))
}
}
deserializer.deserialize_any(Visitor(::std::marker::PhantomData))
}
// Tries to deserialize the given string as a newtype
struct StringNewTypeStructDeserializer<'a, E>(&'a str, ::std::marker::PhantomData<E>);
impl<'de, 'a, E> ::serde::Deserializer<'de> for StringNewTypeStructDeserializer<'a, E> where E: ::serde::de::Error {
type Error = E;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> where V: ::serde::de::Visitor<'de> {
visitor.visit_newtype_struct(self)
}
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value, Self::Error> where V: ::serde::de::Visitor<'de> {
// Called by newtype visitor
visitor.visit_str(self.0)
}
forward_to_deserialize_any! {
bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str bytes
byte_buf option unit unit_struct newtype_struct seq tuple tuple_struct map
struct enum identifier ignored_any
}
}
I found this pattern to work for me in a similar situation:
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
#[serde(untagged)]
enum ParameterValue {
Primitive(String),
List(Vec<String>),
}
#[derive(Debug, Serialize, Deserialize)]
struct Parameter {
name: String,
value: ParameterValue,
}
example primitive:
let primitive = Parameter {
name: String::from("theKey"),
value: ParameterValue::Primitive(String::from("theValue")),
};
let primitive_serialized = serde_json::to_string(&primitive).unwrap();
println!("{primitive_serialized}");
let primitive_again: Parameter = serde_json::from_str(&primitive_serialized).unwrap();
println!("{primitive_again:?}");
Prints:
{"name":"theKey","value":"theValue"}
Parameter { name: "theKey", value: Primitive("theValue") }
example array:
let list = Parameter {
name: String::from("theKey"),
value: ParameterValue::List(vec![String::from("v1"), String::from("v2")]),
};
let list_serialized = serde_json::to_string(&list).unwrap();
println!("{list_serialized}");
let list_again: Parameter = serde_json::from_str(&list_serialized).unwrap();
println!("{list_again:?}");
Prints:
{"name":"theKey","value":["v1","v2"]}
Parameter { name: "theKey", value: List(["v1", "v2"]) }