macro_rules! with_prefix {
    ($module:ident $prefix:expr) => { ... };
    ($vis:vis $module:ident $prefix:expr) => { ... };
}
Expand description

Serialize with an added prefix on every field name and deserialize by trimming away the prefix.

You can set the visibility of the generated module by prefixing the module name with a module visibility. with_prefix!(pub(crate) prefix_foo "foo_"); creates a module with pub(crate) visibility. The visibility is optional and by default pub(self), i.e., private visibility is assumed.

Note: Use of this macro is incompatible with applying the deny_unknown_fields attribute on the container. While deserializing, it will always warn about unknown fields, even though they are processed by the with_prefix wrapper. More details can be found in this issue.

Example

The Challonge REST API likes to use prefixes to group related fields. In simplified form, their JSON may resemble the following:

{
  "player1_name": "name1",
  "player1_votes": 1,
  "player2_name": "name2",
  "player2_votes": 2
}

In Rust, we would ideally like to model this data as a pair of Player structs, rather than repeating the fields of Player for each prefix.

struct Match {
    player1: Player,
    player2: Player,
}

struct Player {
    name: String,
    votes: u64,
}

This with_prefix! macro produces an adapter that adds a prefix onto field names during serialization and trims away the prefix during deserialization. An implementation of the Challonge API would use with_prefix! like this:

use serde::{Deserialize, Serialize};
use serde_with::with_prefix;

#[derive(Serialize, Deserialize)]
struct Match {
    #[serde(flatten, with = "prefix_player1")]
    player1: Player,
    #[serde(flatten, with = "prefix_player2")]
    player2: Player,
}

#[derive(Serialize, Deserialize)]
struct Player {
    name: String,
    votes: u64,
}

with_prefix!(prefix_player1 "player1_");
// You can also set the visibility of the generated prefix module, the default is private.
with_prefix!(pub prefix_player2 "player2_");

fn main() {
    let m = Match {
        player1: Player {
            name: "name1".to_owned(),
            votes: 1,
        },
        player2: Player {
            name: "name2".to_owned(),
            votes: 2,
        },
    };

    let j = serde_json::to_string_pretty(&m).unwrap();
    println!("{}", j);
}