#enums #attributes #parser #macro #proc-macro #serialization

macro enum_parse

Procedural macro generating boilerplate code for parsing enum variants

1 unstable release

0.1.0 Oct 2, 2023

#2869 in Rust patterns

22 downloads per month

MIT license

21KB
319 lines

enum_parse

Provides the enum_parse procedural macro that generates boilerplate code for parsing enum variants.

#[enum_parse(derive(SomehowParsable, Debug),
             repr(C, packed),
             attr(parse_input = &[u8], parse_fn = somehow_parse))]
pub enum Payload {
    #[attr(ID = 0x2b)]
    Hello { a: u8, b: u64, c: u64, d: u8 },
    #[attr(ID = 0x42)]
    Goodbye { a: u8, e: u8 },
    #[attr(ID = _)]
    Unknown,
}

pub fn parse_packet(data: &[u8]) -> Option<Payload> {
    let id: usize = data[0] as usize;
    // parse method is generated by the macro
    Payload::parse(&data[1..], id)
}

(SomehowParsable is an imaginary derive that implements a trait) This is evaluated to the following code:

pub enum Payload {
    Hello(Hello),
    Goodbye(Goodbye),
    Unknown,
}

impl Payload {
    pub fn parse(data: &[u8], id: usize) -> Option<Self> {
        match id {
            Hello::ID => Hello::read_from(data).map(|s| Self::Hello(s)),
            Goodbye::ID => Goodbye::read_from(data).map(|s| Self::Goodbye(s)),
            _ => Some(Self::Unknown),
        }
    }
}

#[derive(SomehowParsable, Debug, Default)]
#[repr(C, packed)]
pub struct Hello {
    pub a: u8,
    pub b: u64,
    pub c: u64,
    pub d: u8,
}
impl Hello {
    pub const ID: usize = 0x2b;
}

#[derive(SomehowParsable, Debug, Default)]
#[repr(C, packed)]
pub struct Goodbye {
    pub a: u8,
    pub e: u8,
}
impl Goodbye {
    pub const ID: usize = 0x42;
}

#[derive(SomehowParsable, Debug, Default)]
#[repr(C, packed)]
pub struct Unknown {}

pub fn parse_packet(data: &[u8]) -> Option<Payload> {
    let id: usize = data[0] as usize;
    Payload::parse(&data[1..], id)
}

There's a lot of duplicated code in the expanded code - each struct needs to be attributed, put in the enum, and given a match case in parse() method. That's why using a proc macro instead can be useful.

Dependencies

~0.4–0.8MB
~20K SLoC