serde-hex
serde-hex copied to clipboard
Deserialization of mixed types
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
}
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),
}
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.
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.