byteable 0.21.0

A Rust crate for convenient serialization and deserialization of byte-oriented data.
Documentation

Byteable

Crates.io Documentation License: MIT

A Rust crate for zero-overhead, zero-copy serialization and deserialization of byte-oriented data.

byteable provides traits and utilities for seamless conversion between data structures and byte arrays, with full support for both synchronous and asynchronous I/O operations, and comprehensive endianness handling.

Features

  • Byte Conversion Traits: Modular trait system for byte array conversion:
    • AssociatedByteArray: Associates a type with its byte array representation
    • IntoByteArray: Converts values into byte arrays
    • FromByteArray: Constructs values from byte arrays
    • TryIntoByteArray & TryFromByteArray: Fallible conversion variants
  • ReadByteable & WriteByteable: Extension traits for std::io::Read and std::io::Write
  • AsyncReadByteable & AsyncWriteByteable: Async I/O support with tokio (optional)
  • Endianness Support: BigEndian<T> and LittleEndian<T> wrappers for explicit byte order
  • #[derive(Byteable)]: Procedural macro for automatic trait implementation with endianness support (optional)
  • Extensive Documentation: Every function, trait, and type is thoroughly documented with examples
  • Inline Comments: All implementations include detailed explanatory comments
  • Zero Overhead: Compiles down to simple memory operations with no runtime cost

Why byteable?

  • Binary Protocols: Perfect for implementing network protocols (TCP, UDP, custom formats)
  • File I/O: Read/write binary file formats with ease
  • Cross-Platform: Consistent behavior across different architectures with endianness control
  • Type-Safe: Rust's type system ensures correctness at compile time
  • No Dependencies: Core functionality has zero dependencies (tokio is optional)

Installation

Add byteable to your Cargo.toml:

[dependencies]
byteable = "0.19"  # Or latest version

Optional Features

[dependencies]
byteable = { version = "0.19", features = ["derive", "tokio"] }
  • derive (default): Enables the #[derive(Byteable)] procedural macro
  • tokio: Enables async I/O traits for use with tokio

Quick Start

Basic File I/O Example

use byteable::{Byteable, LittleEndian, ReadByteable, WriteByteable};
use std::fs::File;

#[derive(Byteable, Debug, PartialEq)]
struct Packet {
    id: u8,
    #[byteable(little_endian)]
    length: u16,
    data: [u8; 4],
}

fn main() -> std::io::Result<()> {
    // Create a packet
    let packet = Packet {
        id: 42,
        length: 1024.into(),
        data: [0xDE, 0xAD, 0xBE, 0xEF],
    };

    // Write packet to a file
    let mut file = File::create("packet.bin")?;
    file.write_byteable(packet)?;
    println!("Packet written to file");

    // Read packet back from file
    let mut file = File::open("packet.bin")?;
    let restored: Packet = file.read_byteable()?;

    assert_eq!(packet, restored);
    println!("Packet successfully read back: {:?}", restored);

    Ok(())
}

Network Protocol Example

use byteable::Byteable;

#[derive(Byteable, Debug, Clone, Copy)]
struct TcpHeader {
    #[byteable(big_endian)]
    source_port: u16,      // Network byte order (big-endian)
    #[byteable(big_endian)]
    dest_port: u16,
    #[byteable(big_endian)]
    sequence_num: u32,
    #[byteable(big_endian)]
    ack_num: u32,
}

let header = TcpHeader {
    source_port: 80,
    dest_port: 8080,
    sequence_num: 12345,
    ack_num: 67890,
};

// Convert to bytes for transmission
let bytes = header.into_byte_array();

Async I/O with Tokio

use byteable::{AsyncReadByteable, AsyncWriteByteable, Byteable};
use tokio::net::TcpStream;

#[derive(Byteable, Debug, Clone, Copy)]
struct Message {
    msg_type: u8,
    payload: [u8; 64],
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut stream = TcpStream::connect("127.0.0.1:8080").await?;

    let msg = Message {
        msg_type: 1,
        payload: [0; 64],
    };

    // Async write
    stream.write_byteable(msg).await?;

    // Async read
    let response: Message = stream.read_byteable().await?;

    Ok(())
}

Usage Patterns

Working with Different Endianness

use byteable::Byteable;

#[derive(Byteable, Clone, Copy)]
struct MixedEndianData {
    // Network protocols often use big-endian
    #[byteable(big_endian)]
    network_value: u32,

    // File formats often use little-endian
    #[byteable(little_endian)]
    file_value: u32,

    // Native endianness (matches system)
    native_value: u32,
}

Reading Multiple Values

use byteable::ReadByteable;
use std::io::Cursor;

let data = vec![/* bytes */];
let mut reader = Cursor::new(data);

let header: u32 = reader.read_byteable()?;
let length: u16 = reader.read_byteable()?;
let checksum: u32 = reader.read_byteable()?;

Safety Considerations

The #[derive(Byteable)] macro uses unsafe code (core::mem::transmute) internally. When using it, you must ensure:

Safe to Use With:

  • Primitive numeric types (u8, i32, f64, etc.)
  • BigEndian<T> and LittleEndian<T> wrappers
  • Arrays of safe types
  • Structs with #[repr(C, packed)] or #[repr(transparent)]

Never Use With:

  • bool, char, or enums (have invalid bit patterns)
  • String, Vec, or any heap-allocated types
  • References or pointers (&T, Box<T>, *const T)
  • Types with Drop implementations
  • NonZero* types or types with invariants

Requirements:

  1. Explicit memory layout: Always use #[repr(C, packed)] or similar
  2. All byte patterns valid: Every possible byte combination must be valid for your type
  3. No padding with undefined values: Use packed to avoid alignment padding
  4. No drop glue: Types must be Copy and have no cleanup logic

Documentation

The crate includes extensive documentation:

  • API Documentation: Every trait, type, and function is documented with examples
  • Inline Comments: All implementations include explanatory comments
  • Safety Guidelines: Clear warnings about unsafe usage
  • Examples: Multiple real-world usage examples in the examples/ directory

Generate and view the documentation locally:

cargo doc --open --no-deps

See Also

License

This project is licensed under the MIT License - see the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Acknowledgments

Built with ❤️ for the Rust community.