Deser: Rethinking Rust Serialization
45 points by asb
45 points by asb
I don't believe serde is the end all be all of serialization but it has proven itself as a stable and reliable ecosystem-default for about a decade.
For the shortcomings serde does have (nothing can hit every possible trade-off perfectly), there are plenty of alternatives in the ecosystem albeit with less out-of-the-box library-support. Switching hasn't really been a big issue in my experience when my requirements didn't match serde's trade offs.
So I don't believe serde needs to be "dethroned" and I personally would rather not rely on a library that, based on recent commit history, received hundreds of slop commits for something as fundamental and critical as serialization but to each their own, I guess.
It would be best for serde to be dethroned, mostly to increase bus-factor and reduce reliance on proc-macros, but the only thing that could do that is first-class compile-time reflection.
Compile time reflection would be amazing but it's also quite tricky to make compile time reflection work for serialization without further meta data. Part of this is agreeing on behaviors. It's really more a social problem than a technical one :)
simdjson's latest release seems to have recently implemented json serde using C++ compiletime reflection: https://lemire.me/blog/2026/09/28/simdjson-5-0-is-out/
there are plenty of alternatives in the ecosystem
It would be nice for that to be the case, but unfortunately that hasn't really been the case. At least not at scale. I think a lot of it comes from the Orphan rule that makes it very hard to replace serde, but also because it's just quite tricky to come up with a design that strikes a better balance.
use deser::{Deserialize, Serialize};
use deser_encoding::Hex;
use deser_validate::{Check, NonEmpty, Range};
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
// at least one 256-bit key, each written as hex
#[deser(as = Check<NonEmpty, Vec<Hex>>)]
secret_keys: Vec<[u8; 32]>,
}
I noticed that this example violates "parse, don't validate." Does this library still support newtypes?
Does this library still support newtypes?
Yes, and in fact the code change is quite minimal if you want to have a newtype for the check:
#[derive(Debug, Serialize, Deserialize)]
#[deser(transparent)]
pub struct SecretKeys(
#[deser(as = Check<NonEmpty, Vec<Hex>>)] Vec<[u8; 32]>
);
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
secret_keys: SecretKeys,
}