Closed dtolnay closed 7 years ago
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use std::fmt;
use serde::de::{self, value, Deserialize, Deserializer, Visitor, SeqAccess};
#[derive(Deserialize, Debug)]
struct Cetra {
#[serde(deserialize_with = "string_or_vec")]
v: Vec<String>,
}
fn string_or_vec<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where D: Deserializer<'de>
{
struct StringOrVec;
impl<'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, s: &str) -> Result<Self::Value, E>
where E: de::Error
{
Ok(vec![s.to_owned()])
}
fn visit_seq<S>(self, seq: S) -> Result<Self::Value, S::Error>
where S: SeqAccess<'de>
{
Deserialize::deserialize(value::SeqAccessDeserializer::new(seq))
}
}
deserializer.deserialize_any(StringOrVec)
}
fn main() {
let j = "{\"v\":\"s\"}";
println!("{:?}", serde_json::from_str::<Cetra>(j).unwrap());
let j = "{\"v\":[\"a\",\"b\"]}";
println!("{:?}", serde_json::from_str::<Cetra>(j).unwrap());
}
I want to ask if it is possible to implement a generic version of type_or_vec
?
@dtolnay Do you know any way to generically do this? I tried by doing a variant of what you described, but instead of calling visit_seq on a seq type and calling visit_map on a map type, it just calls visit_seq on both a seq and a map type (unreachable! never gets hit).
fn string_or_seq_string<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where D: Deserializer<'de>, T: Deserialize<'de> + std::fmt::Debug
{
log!("in the deserialization function");
struct StringOrVec<T>(PhantomData<Vec<T>>);
impl<'de, T: Deserialize<'de> + std::fmt::Debug> de::Visitor<'de> for StringOrVec<T> {
type Value = Vec<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_fmt(format_args!("{} or list thereof", std::any::type_name::<T>()))
}
fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error>
where S: de::SeqAccess<'de>
{
log!("Seq type {:?}", std::any::type_name::<S>());
let retval = Deserialize::deserialize(de::value::SeqAccessDeserializer::new(visitor));
log!("Internal result {:?}", retval);
retval
}
fn visit_map<S>(self, visitor: S) -> Result<Self::Value, S::Error>
where S: de::MapAccess<'de>,
{
unreachable!();
}
}
let retval = deserializer .deserialize_any(StringOrVec(PhantomData));
log!("Result is {:?}", retval);
log!("out of the deserialization function");
retval
}
From IRC: