Midiserde: When mini isn't enough and serde is too much
⚓ Rust 📅 2026-03-03 👤 surdeus 👁️ 1Hello guys,
I maintain as a hobby a Rust library for the VMware vCenter vi-json API - vim-rs. I built it with the help serde, tokio, reqwest etc.. It works great and solved some non-trivial challenges. The build time and size of the executables were not best. So I moved vim_rs to use miniserde. My release build sped up substantially and size imploded.
vim_rs project has a lot of quirks in handling JSON from complex inheritance through custom data formats. I had to extend miniserde to do the job.
Few weeks ago I thought it may be useful if I share the research and experimentation in a re-usable crate. A set of more powerful miniserde macros and couple utility functions that I hope people find useful.
Behold midiserde - when mini is not enough and serde is too much.
The features added thus far include:
#[derive(Debug, Deserialize, Serialize)]
struct Record {
// Rename; also part of miniserde
#[mini(rename = "displayName")]
name: String,
// Default::default
#[mini(default)]
score: u32,
// Default with function
#[mini(default = "default_tag")]
tag: String,
// custom serialisation with out of the box base64,..
#[mini(with = "midiserde::with::base64")]
avatar: Vec<u8>,
// rfc-3339 dates and time-delta too
#[mini(with = "midiserde::with::rfc3339")]
created: chrono::DateTime<chrono::Utc>,
// Skip in both serialisation and deserialization
#[mini(skip)]
cached: u64,
#[mini(skip_serializing)]
secret: String,
#[mini(skip_deserializing)]
version: u32,
// Conditional skip
#[mini(skip_serializing_if = "Option::is_none")]
nickname: Option<String>,
// Flatten for structs
#[mini(flatten)]
geo: Geo,
// Flatten for maps
#[mini(flatten)]
extra: HashMap<String, miniserde::json::Value>,
}
#[derive(Debug, PartialEq, Deserialize, Serialize)]
struct Geo {
lat: f64,
lon: f64,
}
fn default_tag() -> String {
"untagged".into()
}
It may come handy at least as design ideas if not code to a project like vim-rs that exposes vast JSON APIs and wrestles with prolonged compilation or huge executables. Another use case may be projects aiming at very small executables like web assembly.
The crate solves mundane problems with functions absent from miniserde to keep its design clean and performance top notch. Of course these utilities come at a little bit higher cost like the "flatten" attribute will make extra dynamic call to the flattened type.
I thought sharing some of the journey in an article could be interesting to technical readers:
Building #[flatten] for a trait-object serialisation framework: a Rust ownership puzzle
Lastly all sorts of feedback on the project, functionality, quality of code, bugs and feature ideas are more than welcome. You may want to use the Midiserde Codeberg Repo
1 post - 1 participant
🏷️ Rust_feed