macro_rules! with_suffix {
($module:ident $suffix:expr) => { ... };
($vis:vis $module:ident $suffix:expr) => { ... };
}
Expand description
Serialize with an added suffix on every field name and deserialize by trimming away the suffix.
You can set the visibility of the generated module by suffixing the module name with a module visibility.
with_suffix!(pub(crate) suffix_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_suffix
wrapper.
More details can be found in this issue.
ยงExample
Factorio Prototype tables like to use suffixes to group related fields. In simplified form, their JSON representation may resemble the following:
{
"frames": 4,
"spritesheet": "normal",
"frames_frozen": 1,
"spritesheet_frozen": "frozen",
"frames_visualization": 2,
"spritesheet_visualization": "vis",
}
In Rust, we would ideally like to model this data as a couple of SpriteData
structs, rather than repeating the fields of SpriteData
for each suffix.
struct Graphics {
normal: SpriteData,
frozen: SpriteData,
visualization: SpriteData,
}
struct SpriteData {
frames: u64,
spritesheet: String,
}
This with_suffix!
macro produces an adapter that adds a suffix onto field
names during serialization and trims away the suffix during deserialization.
An implementation for the mentioned situation would use with_suffix!
like this:
use serde::{Deserialize, Serialize};
use serde_with::with_suffix;
#[derive(Serialize, Deserialize)]
struct Graphics {
#[serde(flatten)]
normal: SpriteData,
#[serde(flatten, with = "suffix_frozen")]
frozen: SpriteData,
#[serde(flatten, with = "suffix_visualization")]
visualization: SpriteData,
}
#[derive(Serialize, Deserialize)]
struct SpriteData {
frames: u64,
spritesheet: String,
}
with_suffix!(suffix_frozen "_frozen");
// You can also set the visibility of the generated suffix module, the default is private.
with_suffix!(pub suffix_visualization "_visualization");
fn main() {
let g = Graphics {
normal: SpriteData {
frames: 4,
spritesheet: "normal".to_owned(),
},
frozen: SpriteData {
frames: 1,
spritesheet: "frozen".to_owned(),
},
visualization: SpriteData {
frames: 2,
spritesheet: "vis".to_owned(),
},
};
let j = serde_json::to_string_pretty(&g).unwrap();
println!("{}", j);
}