My first ever proc-macro: `#[pack_bools]` that collects all bool fields into a single numeric field

51 points CMDJojo

I recently released my first ever proc-macro called pack\_bools. It was a nice mix of frustration and joy as i had to navigate around syn, proc-macro2, quote and all the other tools. Some problems I encountered was that while syn was awesome for parsing the TokenStream, there was really no easy way to instantiate the AST structures from it, and I was kind of lost in how I was supposed to quote structures I had destructured. Also, it was quite hard to debug, I often got error messages like unexpected ,, but even with cargo expand it was sometimes invisible. But, I managed at last, and I am proud of the final product. Feedback highly appreciated!

As a quick decription, the macro turns structs looking like this:

use pack_bools::pack_bools;

#[pack_bools]
#[derive(Debug, Clone)]
struct Config<'a> {
    output_name: &'a str,
    verbose: bool,
    pub use_colors: bool,
    original_file: &'a std::path::Path,
    legacy_mode: bool
}

into structs looking like this:

#[derive(Debug, Clone)]
struct Config<'a> {
    output_name: &'a str,
    original_file: &'a std::path::Path,
    packed_bools: u8
}

impl<'a> Config<'a> {
    /* getters and setters for the fields,
    with the same visibility as the fields */
}

I also added lots of configuration options, inspired by serde, so you could do #[pack_bools(newtype)] to use the newtype pattern for the packed bool field, and much more. I looked around at crates.io a bit before making this, but didn't quite find anything just like this; I found some macros that generated bitfield-structs, and some macros that could expand a u8 field into multiple boolean fields with getters and setters, but I like the "clean" interface this crate provides.

As said, feedback greatly appreciated!