New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserialize comma-separated list #581

Closed
dtolnay opened this Issue Oct 13, 2016 · 1 comment

Comments

1 participant
@dtolnay
Member

dtolnay commented Oct 13, 2016

From @alexreg in IRC:

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

@dtolnay dtolnay added the support label Oct 13, 2016

@dtolnay

This comment has been minimized.

Show comment
Hide comment
@dtolnay

dtolnay Oct 13, 2016

Member

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(())
}
Member

dtolnay commented Oct 13, 2016

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

@dtolnay dtolnay closed this Oct 13, 2016

jonasbb added a commit to jonasbb/serde_with that referenced this issue May 28, 2018

Add support for string-based collections
String based collections use Display and FromStr for de/serialization of
types. Each value is then separated by a seperator, commonly space or
comma.

A similar wish was voiced at
serde-rs/serde#581

The implementation uses something like
serde-rs/serde#1059 to support arbitrary, even
library user defined, separators.

bors bot added a commit to jonasbb/serde_with that referenced this issue May 28, 2018

Merge #4 #5
4: Miscellanious changes r=jonasbb a=jonasbb

* Rename module
* Some improvements to the doc comments
* Ignore the Cargo.lock file

bors r+

5: String collections r=jonasbb a=jonasbb

String based collections use Display and FromStr for de/serialization of
types. Each value is then separated by a seperator, commonly space or
comma.

A similar wish was voiced at
serde-rs/serde#581

The implementation uses something like
serde-rs/serde#1059 to support arbitrary, even
library user defined, separators.

bors r+

Co-authored-by: Jonas Bushart <jonas@bushart.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment