#proc-macro #macro-derive #endian #procedural #writer #u16 #endian-writer

macro no-std endian-writer-derive

Procedural Macros for endian-writer crate

1 unstable release

0.1.0 Oct 27, 2024

#1299 in Procedural macros

Download history 36/week @ 2024-10-21 106/week @ 2024-10-28 23/week @ 2024-11-04

165 downloads per month

Custom license

12KB
129 lines

endian-writer-derive

Crates.io Docs.rs CI

About

Procedural Macros for endian-writer crate (version 2.X.X).

This is a procedural macro for automatically deriving EndianWritableAt, EndianReadableAt, and HasSize traits for structs whose members already implement the above traits.

Example

The following piece of Rust code.

use endian_writer_derive::EndianWritable;
#[derive(EndianWritable)]
#[repr(C)]
struct MyStruct {
    a: u32,
    b: u16,
    c: u8,
}

Expands to:

use endian_writer::*;
#[repr(C)]
struct Simple {
    a: u32,
    b: u16,
    c: u8,
}
impl HasSize for Simple {
    const SIZE: usize = <u32 as HasSize>::SIZE + <u16 as HasSize>::SIZE + <u8 as HasSize>::SIZE;
}
impl EndianWritableAt for Simple {
    unsafe fn write_at<W: EndianWriter>(&self, writer: &mut W, offset: isize) {
        let a = self.a;
        writer.write_at(&a, offset);
        let b = self.b;
        writer.write_at(&b, offset + <u32 as HasSize>::SIZE as isize);
        let c = self.c;
        writer.write_at(
            &c,
            offset + <u32 as HasSize>::SIZE as isize + <u16 as HasSize>::SIZE as isize,
        );
    }
}
impl EndianReadableAt for Simple {
    unsafe fn read_at<R: EndianReader>(reader: &mut R, offset: isize) -> Self {
        let a = <u32 as EndianReadableAt>::read_at(reader, offset);
        let b =
            <u16 as EndianReadableAt>::read_at(reader, offset + <u32 as HasSize>::SIZE as isize);
        let c = <u8 as EndianReadableAt>::read_at(
            reader,
            offset + <u32 as HasSize>::SIZE as isize + <u16 as HasSize>::SIZE as isize,
        );
        Self { a, b, c }
    }
}

This code is equivalent to what a human would write, in terms of functionality, at no overhead.

Code Generation Behaviour

Fields are written to the output in the order they are declared in the source code.

Consider the following struct

#[derive(EndianWritable)]
struct WeirdOrder {
    c: u8,
    b: u16,
    a: u32,
}

The struct will be written in the order of u8, u16 and lastly u32. On the other hand, Rust may rearrange the fields as u32, u16 and lastly u8.

In other words, the derive macro treats the code as if the struct is #[repr(C, packed(1))]. If padding is desired, the user must manually create it in the struct.

Development

For information on how to work with this codebase, see README-DEV.MD.

License

Licensed under MIT.

Learn more about Reloaded's general choice of licensing for projects..

Dependencies

~0.4–0.8MB
~19K SLoC