Serde: Add struct-level annotation for renaming fields

Created on 21 Aug 2015  路  9Comments  路  Source: serde-rs/serde

Serde supports field level renaming with:

struct Foo {
  #[serde(rename="baz")]
  bar: usize
}

But this can be inconvenient to use if you have a lot of fields you need to rename, such as going from rust's "snake-case" style into "camel-case". It would be nice to have struct level renaming support for this:

#[serde(rename_camel_case)]
#[derive(Serialize, Deserialize)]
struct CamelCase {
  foo_bar_baz: usize
}

#[serde(rename_underscore_to_hypens)]
#[derive(Serialize, Deserialize)]
struct Hyphens {
  foo_bar_baz: usize
}

Would get serialized to fooBarBaz, and foo-bar-baz.

derive enhancement

Most helpful comment

@46bit mentioned possibly being interested in working on this.

Possibly the easiest implementation would be right above this line, traverse the "body" and apply all of the renames in place. So if we have the item attrs asking for camelCase, we would change all of the names of the fields (except those that already have a rename) to be camelCase.

Alternatively you could take a reference to this guy or just its bulk rename field, and pass it through these1 two2 calls so the field names get set correctly right away rather than having to update them later. Try whichever one seems easier to you.

In terms of the actual attributes, I don't like @erickt's serde(rename_camel_case) and serde(rename_underscore_to_hypens), would prefer to use a string so the names can look evocative like what the reader would see if these were individual rename attributes. Something like:

#[serde(rename_all = "snake_case")]
#[serde(rename_all = "kebab-case")]
#[serde(rename_all = "SNAKE_CASE")]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "PascalCase")]

Bonus points for not even looking at the word, just the casing.

#[serde(rename_all = "easterEggCase")]

All 9 comments

This was implemented a while ago.

does this feature still exist? I can't seem to find it in the docs.

@williamho figuring out how to do this was surprisingly tricky, as the syntax apparently changed a few times, and it really doesn't seem to be documented anywhere. This is what worked for me:

#[derive(Debug, Deserialize)]
pub struct UploadResponse {
    fid: String,
    #[serde(rename="fileUrl")]
    file_url: String
}

@scottpleb your specific use case is documented here: https://serde.rs/attr-rename.html

All the attributes are documented here: https://serde.rs/attributes.html

I don't think this was ever implemented.

@46bit mentioned possibly being interested in working on this.

Possibly the easiest implementation would be right above this line, traverse the "body" and apply all of the renames in place. So if we have the item attrs asking for camelCase, we would change all of the names of the fields (except those that already have a rename) to be camelCase.

Alternatively you could take a reference to this guy or just its bulk rename field, and pass it through these1 two2 calls so the field names get set correctly right away rather than having to update them later. Try whichever one seems easier to you.

In terms of the actual attributes, I don't like @erickt's serde(rename_camel_case) and serde(rename_underscore_to_hypens), would prefer to use a string so the names can look evocative like what the reader would see if these were individual rename attributes. Something like:

#[serde(rename_all = "snake_case")]
#[serde(rename_all = "kebab-case")]
#[serde(rename_all = "SNAKE_CASE")]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "PascalCase")]

Bonus points for not even looking at the word, just the casing.

#[serde(rename_all = "easterEggCase")]

Awesome. I like rename_all and agree exactly on the code demos you've put. But I'd like to allow users to use their own renaming function, similar to with #[serde(default = "fn")].

The obvious signature would be a mapping from field name to output name, fn(&str) -> &str. We could also provide the other field names in the container with fn(&str, [&str]) -> &str, but I don't see a usecase.

After doing some implementation, I don't know if renaming by function is possible without wider changes. default works because when the code being analysed is run that function will be available. That's not the case when renaming inside the codegen.

There exists the Inflector crate to perform inflection. That adds a dependency and relies on std::ascii. Would that be acceptable? Otherwise I can reimplement.

Implemented in #788.

Was this page helpful?
0 / 5 - 0 ratings