From @alexreg in IRC:
is it possible to write a deserialize_with function that deserializes a comma-separates list of values of type T?
All the type parameters make this a bit nasty because we need V: FromIterator<T>, T: FromStr<Err = E>, E: Display. But the method bodies themselves are brief and sensible.
This belongs in a helper library. cc #553
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate serde_json;
use std::fmt::{self, Display};
use std::iter::FromIterator;
use std::marker::PhantomData as Phantom;
use std::str::FromStr;
use serde::de::{self, Deserializer, Visitor};
#[derive(Deserialize, Debug)]
struct S {
#[serde(deserialize_with = "comma_separated")]
f: Vec<i32>,
}
fn comma_separated<'de, V, T, D>(deserializer: D) -> Result<V, D::Error>
where
V: FromIterator<T>,
T: FromStr,
T::Err: Display,
D: Deserializer<'de>,
{
struct CommaSeparated<V, T>(Phantom<V>, Phantom<T>);
impl<'de, V, T> Visitor<'de> for CommaSeparated<V, T>
where
V: FromIterator<T>,
T: FromStr,
T::Err: Display,
{
type Value = V;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("string containing comma-separated elements")
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
let iter = s.split(",").map(FromStr::from_str);
Result::from_iter(iter).map_err(de::Error::custom)
}
}
let visitor = CommaSeparated(Phantom, Phantom);
deserializer.deserialize_str(visitor)
}
fn main() -> Result<(), serde_json::Error> {
let j = r#"{"f":"1,2,3"}"#;
let s: S = serde_json::from_str(j)?;
println!("{:?}", s);
Ok(())
}
Most helpful comment
All the type parameters make this a bit nasty because we need
V: FromIterator<T>,T: FromStr<Err = E>,E: Display. But the method bodies themselves are brief and sensible.This belongs in a helper library. cc #553