I have a JSON API that returns an object that looks like this:
{
"PrivatePort": 2222,
"PublicPort": 3333,
"Type": "tcp"
}
To capture this, I have an enum and a struct:
#[derive(Eq, PartialEq, Deserialize, Serialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum PortType {
Sctp,
Tcp,
Udp,
}
#[derive(Deserialize, Serialize, Debug)]
#[serde(rename_all = "PascalCase")]
pub struct PortMapping {
pub private_port: u16,
pub public_port: u16,
#[serde(rename = "Type")]
pub port_type: PortType,
}
Right now, this API only supports the three protocols listed in PortType
, but let's assume that support for DCCP
is added in the future. I do not want clients of the API to start failing simply because of an unknown string in a configuration option they might not be looking at.
To address this, I've added an Unknown
variant with a String
to represent the value:
#[derive(Eq, PartialEq, Deserialize, Serialize, Debug)]
#[serde(rename_all = "snake_case")]
pub enum PortType {
Sctp,
Tcp,
Udp,
Unknown(String),
}
The goal here is to end up with the slightly-inconvenient PortType::Unknown("dccp")
value when an unknown value is passed in. Of course, this does not do what I would like out-of-box -- passing the unknown "dccp"
value will result in:
Error("unknown variant `dccp`, expected one of `sctp`, `tcp`, `udp`, `unknown`", line: 1, column: 55)
Is there a Serde configuration for doing what I want or should I resort to manually writing Deserialize
and Serialize
implementations for PortType
?
Serde is a framework for serializing and deserializing Rust data structures efficiently and generically. The Serde ecosystem consists of data structures that know how to serialize and deserialize themselves along with data formats that know how to serialize and deserialize other things.
The Hive JSON SerDe is commonly used to process JSON data like events. These events are represented as single-line strings of JSON-encoded text separated by a new line. The Hive JSON SerDe does not allow duplicate keys in map or struct key names.
Rustc has to serialize and deserialize various data during compilation. Specifically: "Crate metadata", mainly query outputs, are serialized in a binary format into rlib and rmeta files that are output when compiling a library crate, these are then deserialized by crates that depend on that library.
Try use serde-enum-str
#[derive(serde_enum_str::Deserialize_enum_str, serde_enum_str::Serialize_enum_str)]
#[serde(rename_all = "snake_case")]
pub enum PortType {
Sctp,
Tcp,
Udp,
#[serde(other)]
Unknown(String),
}
There's an issue for this, though it's been open for 3 years with no full resolution so far. Serde #912.
What seems to be currently implemented (though undocumented) at the time of this post is #[serde(other)]
. It can only be applied to unit enum fields, which limits its usefulness:
#[derive(Deserialize, PartialEq)]
#[serde(tag = "tag")]
enum Target {
A(()),
B(()),
#[serde(other)]
Others
}
fn main() {
assert_eq!(Target::Others, from_str::<Target>(r#"{ "tag": "blablah" }"#).unwrap());
}
Other than that, the only other method as of this writing is writing your own Deserialize
implementation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With