serde
serde copied to clipboard
Apply rename_all to enum member "fields"
When using enums with struct-like members it would be useful if rename_all on the enclosing enum could apply to the members, too. For example:
#[serde(untagged, rename_all = "camelCase" )]
pub enum Value {
Null { null_value: () },
String { string_value: String },
Boolean { boolean_value: bool },
}
could do
Value::String("foo".to_string())
=>
{ "stringValue": "foo" }
------^-----
|
This here is what I want
Currently the annotation has to be placed on the fields in addition:
#[serde(untagged)]
pub enum Value {
Null {
#[serde(rename = "nullValue")]
null_value: ()
},
String {
#[serde(rename = "stringValue")]
string_value: String
},
/* etc. */
}
(If you're wondering what is going on with this type, it's Google Datastore).
Seems reasonable. Do you have a suggestion for how this should work? Simplify changing the meaning of rename_all would be a breaking change.
Side note: representing the datastore value the following way may be more convenient. This avoids restating the type twice in Rust code -- Value::Boolean(true) instead of Value::Boolean { boolean_value: true }.
#[derive(Serialize, Deserialize)]
enum Value {
#[serde(rename = "nullValue", with = "null")]
Null,
#[serde(rename = "stringValue")]
String(String),
#[serde(rename = "booleanValue")]
Boolean(bool),
}
// Serialize the unit variant `Value::Null` as `{"nullValue":null}` rather
// than the default `"nullValue"`.
mod null {
use serde::{Serialize, Serializer, Deserialize, Deserializer};
pub fn serialize<S>(serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
().serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
where D: Deserializer<'de>
{
<()>::deserialize(deserializer)
}
}
Thanks for a quick reply! I'm really enjoying serde btw, easily the most pleasant serialisation lib I've worked with so far :-)
Do you have a suggestion for how this should work? Simplify changing the meaning of rename_all would be a breaking change.
Agreed, maybe it's sensible to have a separate rename_fields for this that would both apply to struct and enum-member fields?
Side note: representing the datastore value the following way may be more convenient
The problem is that the enum is "key-tagged", i.e. it's adjacent to other keys inside of a different struct and the key that contains the Value determines its type.
I haven't found a better way than the current untagged solution, but I also really need to stop thinking about this for today and find a nearby bed! ;-)
Maybe instead of rename_all we should have had distinct rename_fields and rename_variants attributes, so that you can write both to get the desired effect.
It may be confusing to add those now and not have rename_all mean rename both fields and variants.
I would be willing to consider a pull request that adds a serde(rename_all_fields = "...") attribute for enums that applies a rename rule to every field of every variant.
@dtolnay Any update on this?