Serde transitioning to Macros 1.1

Serde 0.8.10 deprecates the old Serde compiler plugin serde_macros in favor of the Macros 1.1-based implementation serde_derive.

We do not intend to release any further version of serde_macros, not even to fix breakage in future nightly versions. The design of Macros 1.1 is such that we do not expect to see the regular breakage with serde_derive that we used to see with serde_macros, as it depends on a far more limited set of unstable compiler internals.

See https://serde.rs/codegen-nightly.html for steps to set up serde_derive, or https://serde.rs/codegen-hybrid.html for steps to set up a hybrid serde_codegen/serde_derive approach that works on stable.

Old approach

[dependencies]
serde_macros = "0.8"
#![feature(plugin, custom_derive)]
#![plugin(serde_macros)]

New approach

[dependencies]
serde_derive = "0.8"
#![feature(rustc_macro)]

#[macro_use]
extern crate serde_derive;

// everything else is the same
23 Likes

Please let us know here or by filing an issue if you run into any trouble using serde_derive.

Awesome work! I'll have to go and dig back through the implementation again now that it's finished.

Is this the first library to officially support Macros 1.1?

1 Like

Is this the first library to officially support Macros 1.1?

We have actually officially supported it for almost a month, since before the feature even landed in nightly or was supported by Cargo. This is just the point at which we feel confident enough to abandon the old compiler plugin.

The only two other libraries I have seen actively working on Macros 1.1 are num and namedarg. Also @sgrif has said he is going to try to port Diesel over by this Friday.

I'll have to go and dig back through the implementation again now that it's finished.

For others too lazy to dig, here is the entire serde_derive crate below. Really the only interesting part is that serde_codegen now uses syn to parse the input instead of Syntex, which results in compile times for serde_derive similar to serde_macros (i.e. much faster than using serde_codegen directly).

#![feature(rustc_macro, rustc_macro_lib)]
#![cfg(not(test))]

extern crate rustc_macro;
extern crate serde_codegen;

use rustc_macro::TokenStream;

#[rustc_macro_derive(Serialize)]
pub fn derive_serialize(input: TokenStream) -> TokenStream {
    let item = format!("#[derive(Serialize)]\n{}", input);
    match serde_codegen::expand_single_item(&item) {
        Ok(expanded) => expanded.parse().unwrap(),
        Err(msg) => panic!(msg),
    }
}

#[rustc_macro_derive(Deserialize)]
pub fn derive_deserialize(input: TokenStream) -> TokenStream {
    let item = format!("#[derive(Deserialize)]\n{}", input);
    match serde_codegen::expand_single_item(&item) {
        Ok(expanded) => expanded.parse().unwrap(),
        Err(msg) => panic!(msg),
    }
}
2 Likes

Really the only interesting part is that serde_codegen now uses syn to parse the input instead of Syntex, which results in compile times for serde_derive similar to serde_macros (i.e. much faster than using serde_codegen directly).

In fact now that I actually try it, serde_derive compiles significantly faster than serde_macros. On my computer, from scratch including all dependencies it is 20 seconds for serde_macros 0.8.9 and only 12 seconds for serde_derive 0.8.10. The speedup is because syn also replaces our dependency on aster and quasi and quasi_codegen and quasi_macros.

3 Likes