Serde: Deserialize comma-separated list

Created on 13 Oct 2016  路  1Comment  路  Source: serde-rs/serde

From @alexreg in IRC:

is it possible to write a deserialize_with function that deserializes a comma-separates list of values of type T?

support

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

#[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(())
}

>All comments

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(())
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

sackery picture sackery  路  3Comments

vityafx picture vityafx  路  3Comments

dtolnay picture dtolnay  路  4Comments

kleimkuhler picture kleimkuhler  路  3Comments

dtolnay picture dtolnay  路  3Comments