Skip to main content

Byteable

Derive Macro Byteable 

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

Derives byte conversion and I/O traits for structs and enums.

This is the main derive macro for the byteable crate. It automatically generates appropriate trait implementations based on the annotated type.

§Struct Modes

§Fixed-size structs (default)

For ordinary structs without #[byteable(io_only)], this macro generates a *Raw helper struct with #[repr(C, packed)] and implements IntoByteArray / FromByteArray via transmute. This provides zero-copy conversion but requires all fields to be fixed-size.

Fields can be annotated with #[byteable(little_endian)] or #[byteable(big_endian)] to control byte order.

Supports:

  • Named structs
  • Tuple structs
  • Unit structs

§Dynamic-size structs with #[byteable(io_only)]

For structs containing Vec<T>, String, Option<T>, or other dynamically-sized types, annotate with #[byteable(io_only)]. This generates Readable / Writable implementations that perform sequential field I/O, allowing arbitrary field types.

Supports:

  • Named structs
  • Tuple structs
  • Unit structs

§Enum Modes

§C-like enums (unit variants only)

Enums with only unit variants and explicit discriminants implement IntoByteArray / TryFromByteArray via transmute. Supports:

  • Explicit #[repr(u8)], #[repr(u16)], etc.
  • Auto-repr inference (when #[repr] is omitted)
  • Auto-discriminant assignment (when discriminants are omitted)
  • Type-level endianness: #[byteable(big_endian)] / #[byteable(little_endian)]

§Enums with variant fields

Enums where any variant has fields implement Readable / Writable via stream-based I/O. Discriminant is written first (respecting endianness), then the variant’s fields in order. Supports:

  • Mix of unit, named-field, and tuple-field variants
  • Auto-repr and auto-discriminant assignment
  • Per-field endianness annotations

§Attributes

§Struct/Enum-level

  • #[byteable(io_only)] - Generate Readable/Writable via field I/O instead of transmute
  • #[byteable(little_endian)] - Set type-level endianness (enums only)
  • #[byteable(big_endian)] - Set type-level endianness (enums only)

§Field-level

  • #[byteable(little_endian)] - Wrap field in LittleEndian<T>
  • #[byteable(big_endian)] - Wrap field in BigEndian<T>
  • #[byteable(transparent)] - Use field’s raw type (transmute path only)
  • #[byteable(try_transparent)] - Use field’s raw type with fallible conversion (transmute path only)

§Examples

§Fixed-size struct with endianness

use byteable::Byteable;

#[derive(Clone, Copy, Byteable, Debug, PartialEq)]
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],
};
let bytes = packet.into_byte_array();
let restored = Packet::from_byte_array(bytes);

§Dynamic-size struct with io_only

use byteable::Byteable;

#[derive(Byteable, Debug, PartialEq)]
#[byteable(io_only)]
struct Message {
    tag: u8,
    payload: Vec<u8>,
    label: String,
}
// io_only structs implement Readable/Writable (not IntoByteArray)

§C-like enum

use byteable::Byteable;

#[derive(Byteable, Debug, Clone, Copy, PartialEq)]
#[repr(u8)]
enum Status {
    Idle = 0,
    Running = 1,
    Done = 2,
}
let status = Status::Running;
let bytes = status.into_byte_array();

§Enum with variant fields

use byteable::Byteable;

#[derive(Byteable, Debug, PartialEq)]
#[repr(u8)]
enum Message {
    Ping = 0,
    Pong { id: u8 } = 1,
    Data { len: u8, value: [u8; 4] } = 2,
}
// Enums with fields implement Readable/Writable (not IntoByteArray)