Riven icon indicating copy to clipboard operation
Riven copied to clipboard

How to serialize PlatformRoute, Tier, Division, etc?

Open VRichardJP opened this issue 3 years ago • 2 comments

Some structures like Match derive serde::Serialize and serde::Deserialize for parsing purpose but a few enums don't. Is there a reason?

For example, I would like to create a serializable structure like this:

#[derive(Serialize, Deserialize)]
pub struct config {
    pub version: String,
    pub servers: Vec<PlatformRoute>,
    pub tiers: Vec<Tier>
}

VRichardJP avatar Nov 01 '21 04:11 VRichardJP

To answer, anything that shows up in JSON responses returned by the API derive serde (though I guess only the de is needed), and things like PlatformRoute don't since they don't show up in the JSON.

Tier and Division actually do implement serde manually (not derive) since they're serialized as strings rather than numbers in the JSON.


The easiest way to deal with this in current form would be with a newtype and serde impl, something like this: (untested)

pub struct PlatformRouteSerde(pub PlatformRoute);

impl<'de> serde::de::Deserialize<'de> for PlatformRouteSerde {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::de::Deserializer<'de>
    {
        let num = u8::deserialize(deserializer)?;
        let route = num.parse().map_err(serde::de::Error::custom)?;
        PlatformRouteSerde(route)
    }
}

impl serde::ser::Serialize for PlatformRouteSerde {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::ser::Serializer,
    {
        serializer.serialize_u8(self.0.into())
    }
}

MingweiSamuel avatar Nov 01 '21 16:11 MingweiSamuel

Thanks, I just saw the serde_string macro. Regarding Tier and Division I feel the macro is redundant: #derive(serde::Serialize) does stringify the enum variant by default (while #derive(serde_repr::Serialize_repr) would use the repr value instead). For example:

use serde_repr::{Serialize_repr, Deserialize_repr};
use serde::{Serialize, Deserialize};

#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug)]
#[repr(u8)]
enum SmallPrimeRepr {
    Two = 2,
    Three = 3,
    Five = 5,
    Seven = 7,
}

#[derive(Serialize, Deserialize, PartialEq, Debug)]
#[repr(u8)]
enum SmallPrime {
    Two = 2,
    Three = 3,
    Five = 5,
    Seven = 7,
}

fn main() -> serde_json::Result<()> {
    let j_repr = serde_json::to_string(&SmallPrimeRepr::Seven)?;
    let j = serde_json::to_string(&SmallPrime::Seven)?;
    println!("{} {}", j_repr, j);

    let p_repr: SmallPrimeRepr = serde_json::from_str("2")?;
    let p: SmallPrime = serde_json::from_str("\"Two\"")?;
    println!("{:?} {:?}", p_repr, p);

    Ok(())
}

prints:

7 "Seven"
Two Two

So I think for Tier/Division a simple #derive(serde::Serialize) would do. For PlatformRoute I guess it is not that easy because then there is the issue with serde <-> strum serialization consistency =/

VRichardJP avatar Nov 02 '21 01:11 VRichardJP