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

De/serialize struct as an array of values #637

Closed
dtolnay opened this issue Dec 7, 2016 · 7 comments
Closed

De/serialize struct as an array of values #637

dtolnay opened this issue Dec 7, 2016 · 7 comments

Comments

@dtolnay
Copy link
Member

dtolnay commented Dec 7, 2016

From IRC:

<mimbo> Hi all. How to I de/serialize a struct as an array of values?
<mimbo> i.e. struct T { s: String, i: i32, b: bool } should be used from ["str", 123, true]

Here is one approach.

extern crate serde;
extern crate serde_json;
use serde::{Serialize, Serializer, Deserialize, Deserializer};

#[derive(Debug)]
struct T {
    s: String,
    i: i32,
    b: bool,
}

impl Serialize for T {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
        where S: Serializer
    {
        (&self.s, self.i, self.b).serialize(serializer)
    }
}

impl Deserialize for T {
    fn deserialize<D>(deserializer: &mut D) -> Result<T, D::Error>
        where D: Deserializer
    {
        Deserialize::deserialize(deserializer)
            .map(|(s, i, b)| T { s: s, i: i, b: b })
    }
}

fn main() {
    let t = T { s: "str".to_owned(), i: 123, b: true };
    let j = serde_json::to_string(&t).unwrap();
    println!("{}", j);

    let t2: T = serde_json::from_str(&j).unwrap();
    println!("{:?}", t2);
}
@dtolnay dtolnay added the support label Dec 7, 2016
@dtolnay
Copy link
Member Author

dtolnay commented Dec 7, 2016

I have not seen this use case before but if it turns out to be pretty common, we could make it nicer with some sort of attribute.

#[derive(Serialize, Deserialize, Debug)]
#[serde(as_tuple)]
struct T {
    s: String,
    i: i32,
    b: bool,
}

On the other hand if is common in mimbo's code but uncommon elsewhere, you could write a macro_rules! macro to generate Serialize and Deserialize implementations like this for a particular struct.

@dtolnay
Copy link
Member Author

dtolnay commented Dec 7, 2016

Use cases:

<sfackler> i have done this before to shrink e.g. {"time": 1000, "value": 10.5} to [1000, 10.5]

<mimbo> the use case is to compact data

I think it would be reasonable for us to support this in #[derive(Serialize)].

@RReverser
Copy link

I have similar use-case, but with enum as a target - items in the source I'm pulling data from are encoded as ["TagN", value1, value2, ...] which I want to decode into an MyEnum::TagN(value1, value2, ...). My understanding is that it's not currently achievable with just "internally tagged" enum representation because it expects a string key into a map?

@jean-airoldie
Copy link

Here is a macro based on @dtolnay solution tested on serde = "1.0.80".

@dtolnay
Copy link
Member Author

dtolnay commented Jan 6, 2019

I am closing this issue because I would prefer to see this use case supported by a derive macro in a separate crate. Something like:

#[derive(Serialize_tuple, Deserialize_tuple)]
struct T {
    s: String,
    i: i32,
    b: bool,
}

which emits the appropriate Serialize and Deserialize impls. In this case:

impl Serialize for T {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        #[derive(Serialize)]
        #[serde(rename = "T")]
        struct Helper<'a>(&'a String, &'a i32, &'a bool);

        let helper = Helper(&self.s, &self.i, &self.b);
        helper.serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for T {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        #[derive(Deserialize)]
        #[serde(rename = "T")]
        struct Helper(String, i32, bool);

        let helper = Helper::deserialize(deserializer)?;
        Ok(T {
            s: helper.0,
            i: helper.1,
            b: helper.2,
        })
    }
}

@dtolnay dtolnay closed this as completed Jan 6, 2019
@dtolnay
Copy link
Member Author

dtolnay commented Jan 22, 2019

Posted a request for implementation: dtolnay/request-for-implementation#3.

@theduke
Copy link

theduke commented Jun 29, 2019

Just for reference, there is a crate for this now: https://crates.io/crates/serde_tuple

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

4 participants