Byteable

Derive Macro Byteable 

Source
#[derive(Byteable)]
{
    // Attributes available to this derive:
    #[byteable]
}
Expand description

Derives a delegate pattern for Byteable by generating a raw struct with endianness markers.

This macro creates a companion *Raw struct with #[repr(C, packed)] that handles the actual byte conversion, while keeping your original struct clean and easy to work with. Fields can be annotated with #[byteable(little_endian)] or #[byteable(big_endian)] to specify endianness.

§Generated Code

For each struct, this macro generates:

  1. A *Raw struct with #[repr(C, packed)] and endianness wrappers
  2. From<OriginalStruct> for OriginalStructRaw implementation
  3. From<OriginalStructRaw> for OriginalStruct implementation
  4. A Byteable implementation via impl_byteable_via! macro

§Attributes

  • #[byteable(little_endian)] - Wraps the field in LittleEndian<T>
  • #[byteable(big_endian)] - Wraps the field in BigEndian<T>
  • #[byteable(transparent)] - Uses the field’s raw representation type directly (for nested Byteable types implementing ByteableRaw)
  • No attribute - Keeps the field type as-is

§Requirements

  • The struct must have named fields (not a tuple struct)
  • Fields with endianness attributes must be numeric types that implement EndianConvert
  • Fields with transparent attribute must implement Byteable
  • The struct should derive Clone and Copy for convenience

§Examples

§Basic usage

use byteable::Byteable;

#[derive(Clone, Copy, Byteable)]
struct Packet {
    id: u8,
    #[byteable(little_endian)]
    length: u16,
    #[byteable(big_endian)]
    checksum: u32,
    data: [u8; 4],
}

let packet = Packet {
    id: 42,
    length: 1024,
    checksum: 0x12345678,
    data: [1, 2, 3, 4],
};

// Byteable is automatically implemented
let bytes = packet.to_byte_array();
let restored = Packet::from_byte_array(bytes);

§Generated code

The above example generates approximately:

#[derive(Clone, Copy, Debug, UnsafeByteableTransmute)]
#[repr(C, packed)]
struct PacketRaw {
    id: u8,
    length: LittleEndian<u16>,
    checksum: BigEndian<u32>,
    data: [u8; 4],
}

impl From<Packet> for PacketRaw {
    fn from(value: Packet) -> Self {
        Self {
            id: value.id,
            length: value.length.into(),
            checksum: value.checksum.into(),
            data: value.data,
        }
    }
}

impl From<PacketRaw> for Packet {
    fn from(value: PacketRaw) -> Self {
        Self {
            id: value.id,
            length: value.length.get(),
            checksum: value.checksum.get(),
            data: value.data,
        }
    }
}

impl_byteable_via!(Packet => PacketRaw);