byteable 0.2.0

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

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

byteable is a Rust crate providing traits and utilities for seamless conversion between data structures and byte arrays, handling both synchronous and asynchronous I/O operations, and managing endianness.

Features

  • Byteable Trait: The core trait for types that can be converted to and from a byte array.
  • ReadByteable & WriteByteable Traits: Extension traits for std::io::Read and std::io::Write, enabling convenient reading and writing of Byteable types.
  • AsyncReadByteable & AsyncWriteByteable Traits (with tokio feature): Asynchronous counterparts to ReadByteable and WriteByteable, designed for use with tokio's async I/O.
  • Endianable Trait & Wrappers: Provides methods for converting primitive types between different endianness (little-endian and big-endian), along with BigEndian<T> and LittleEndian<T> wrapper types.
  • #[derive(Byteable)] (with derive feature): A procedural macro that automatically implements the Byteable trait for structs, significantly simplifying boilerplate.

Installation

Add byteable to your Cargo.toml:

[dependencies]
byteable = "0.1" # Or specify the latest version

To enable the derive macro and tokio integration, you can specify features:

[dependencies]
byteable = { version = "0.1", features = ["derive", "tokio"] }

Usage

Basic Byteable Conversion

Implement the Byteable trait manually or use the #[derive(Byteable)] macro (with the derive feature enabled):

use byteable::{Byteable, ReadByteable, WriteByteable, LittleEndian};
use std::io::Cursor;

#[derive(Byteable, Debug, PartialEq, Copy, Clone)]
#[byteable(transparent)] // For single-field structs
struct MyCustomId(u32);

fn main() -> std::io::Result<()> {
    let id = MyCustomId(12345);
    let mut buffer = Vec::new();

    // Write to buffer
    buffer.write_one(id)?;

    // Read from buffer
    let mut reader = &buffer[..];
    let read_id: MyCustomId = reader.read_one()?;

    println!("Original ID: {:?}, Read ID: {:?}", id, read_id);
    assert_eq!(id, read_id);
    Ok(())
}

Endianness Conversion

use byteable::{BigEndian, LittleEndian};

fn main() {
    let value: u32 = 0x01020304;

    // Convert to Big Endian
    let be_value = BigEndian::new(value);
    println!("Value in Big Endian: {:?}", be_value); // Will show 0x01020304


    // Convert to Little Endian
    let le_value = LittleEndian::new(value);
    println!("Value in Little Endian: {:?}", le_value); // Will show 0x04030201
}

Asynchronous I/O (with tokio feature)

#[cfg(feature = "tokio")]
#[tokio::main]
async fn main() -> std::io::Result<()> {
    use byteable::{Byteable, AsyncReadByteable, AsyncWriteByteable};
    use tokio::io::Cursor;

    #[derive(Byteable, Debug, PartialEq, Copy, Clone)]
    struct SensorData {
        temperature: f32,
        humidity: u16,
    }

    let data = SensorData {
        temperature: 25.5,
        humidity: 60,
    };
    let mut buffer = Cursor::new(Vec::new());

    // Write asynchronously
    buffer.write_one(data).await?;

    // Reset cursor and read asynchronously
    buffer.set_position(0);
    let read_data: SensorData = buffer.read_one().await?;

    println!("Original Data: {:?}, Read Data: {:?}", data, read_data);
    assert_eq!(data, read_data);
    Ok(())
}

Contributing

Feel free to open issues or submit pull requests.

License

This project is licensed under MIT.