serde-hex icon indicating copy to clipboard operation
serde-hex copied to clipboard

Deserialization of mixed types

Open silwol opened this issue 6 years ago • 3 comments

I use a JSON API where in some places either hex numbers or JSON numbers can be used for the same field. I don't know if it fits into this crate's functionality, but it would be if serde-hex could deserialize this type of item.

Example of two valid representations of the same data:

{
  "code": "0x123"
}
{
  "code": 291
}

silwol avatar May 16 '18 07:05 silwol

I'm not opposed to the idea, but it isn't immediately obvious to me what the default behavior of the Serialize half of the impl would be. I'm open to suggestions. In the meantime, untagged enums offer a pretty easy workaround. Ex:

#[derive(Serialize,Deserialize)]
#[serde(untagged)]
enum MaybeHex {
    Hex(#[serde(with = "SerHex::<CompactPfx>")] u64),
    Num(u64),
}

fspmarshall avatar May 30 '19 20:05 fspmarshall

Yes, that's what I do right now, with From implementation for the corresponding integer type, and it works ok-ish for (de-)serializing. However, when using the data structures in the program, it's somewhat inconvenient. I'm not too familiar with implementing attributes, but from my perspective as a user, defining the default serialization variant would be fine.

silwol avatar May 31 '19 19:05 silwol

As the API is currently structured, all configuration values must be communicated as part of the generic type parameter. I'm hesitant to add too many options until there is a more convenient mechanism of supplying the optional configuration values. For your specific case, you should be able to eliminate the inconvenience by extending the untagged enum solution like so:

mod hexish {
    // ...
    pub fn serialize<S>(n: &u64, s: S) -> Result<S::Ok,S::Error> where S: Serializer {
        Serialize::serialize(&MaybeHex::Hex(*n),s)
    }
    pub fn deserialize<'de,D>(d: D) -> Result<u64,D::Error> where D: Deserializer<'de> {
        match Deserialize::deserialize(d)? {
            MaybeHex::Hex(n) => Ok(n),
            MaybeHex::Num(n) => Ok(n),
        }
    }
}
#[derive(Serialize,Deserialize)]
struct MyStruct {
    #[serde(with = "hexish")]
    number: u64,
}

Its definitely a hack, but it does the job.

fspmarshall avatar Jun 01 '19 00:06 fspmarshall