I'm trying to make a library that serializes things using serde but I'd like better type-safety. Specifically: the format is much more restrictive than serde and I'd like field types incompatible with my format to be rejected at compile-time. I'd also like to have a separate trait/derive macro for this. Is there a good example of this or something similar being done in a crate somewhere? What I'd want is something like this:
// Option, String, and Vec are OK
#[derive(Clone, Debug, MyRestrictedSerialize)]
#[skip_serializing_none]
pub struct ValidType {
pub field: Option<String>,
pub field2: Vec<String>,
// Compile-time error, i64 and bool are not allowed
#[derive(Clone, Debug, MyRestrictedSerialize)]
#[skip_serializing_none]
pub struct InvalidType {
pub field: Option<i64>,
pub field2: Vec<bool>,
pub field3: i64,
I'm almost positive someone has done something like this before but perusing crates.io hasn't led to anything that quite fits what I'm thinking of. I'm considering writing a macro that implements a wrapper trait that is requires Serialize if-and-only-if the type is valid for the intended format but that seems a little icky. Something like this:
trait MyRestrictedSerialize<T: Serialize = Self> {
fn my_serialize(…) -> MyFormat {
…
}
}
First: am I on the right track? Is there another approach I should consider?
Second: Are there any crates solving a similar problem? I can't be the first person implementing a format that can only express a subset of what serde
allows who wants to reject invalid types at compile-time.