Custom derives are awesome!

As part of an experiment at work I had a go at rewriting some code for communicating with a microcontroller in Rust. Thanks to custom derives, I was able to replace a couple thousand lines of code (including one gnarly 1000+ line switch statement!) with 20-something trivial struct declarations and a custom derive which weighed in at less than a hundred lines.

I know a lot of people have put lots of hard work into the macro system and thanks to all of you!

I can't really share the code, but the general idea is I would create a couple important traits in the root crate:

pub trait Message{
    fn encode<W: Write>(&self, writer: W) -> Result<(), Error>;
    fn description(&self) -> &'static str;
}

pub trait MessageField {
    fn encode_field<W: Write>(&self, writer: W) -> Result<(), Error>;
}

Then write out a couple structs like so,

#[derive(Debug, Copy, Clone, PartialEq, Message)]
#[msg(mnemonic = "RLXX", description = "Run the bootloader")]
pub struct RunBootloader;

#[derive(Debug, Copy, Clone, PartialEq, Message)]
#[msg(mnemonic = "PPXX", description = "Default program pause for op")]
pub struct ProgramPause {
    pub duration: Option<usize>,
    pub next_operation: usize,
}

Which then expands to something like this:

impl Message for RunBootloader {
    fn encode<W: Write>(&self, writer: W) -> Result<(), Error> {
        write!(writer, "RLXX")?;
        Ok(())
    }
    fn description(&self) -> &'static str {
        "Run the bootloader"
    }
}
impl Message for ProgramPause {
    fn encode<W: Write>(&self, writer: W) -> Result<(), Error> {
        write!(writer, "PPXX")?;
        if let Some(value) = self.duration {
            value.encode_field(&mut writer)?;
        }
        self.next_operation.encode_field(&mut writer)?;
        Ok(())
    }
    fn description(&self) -> &'static str {
        "Default program pause for op"
    }
}

As an afterthough, does anyone know if there are any resources for implementing your own custom derives? I got pretty far by just skimming the syn and quote docs as well as structopt_derive's source code, but it'd be nice if there were something akin to The Little Book of Rust Macros ("The Little Book of Macros 2.0"?).

8 Likes

That's awesome!

Regarding docs, no, there's nothing yet. I was going to wait until Macros 2.0 before trying to put the whole thing together.

2 Likes

I've been super impressed with the abomonation_derive implementation Nika put together using synstructure. It's (to my reading) super short and clear. Maybe that (synstructure) would help for learning about implementing more?

1 Like