Skip to content
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
Closed

Deserialize comma-separated list #581

dtolnay opened this issue Oct 13, 2016 · 1 comment
Labels

Comments

@dtolnay
Copy link
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
Copy link
Member Author

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 as completed Oct 13, 2016
jonasbb added a commit to jonasbb/serde_with that referenced this issue May 28, 2018
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
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
Labels
Development

No branches or pull requests

1 participant