byten

Crates.iobyten
lib.rsbyten
version0.0.13
created_at2025-10-30 20:57:49.955248+00
updated_at2025-11-09 16:57:42.779516+00
descriptionA binary codec library for efficient encoding and decoding of data structures
homepagehttps://github.com/m-ali-akbay/byten
repositoryhttps://github.com/m-ali-akbay/byten
max_upload_size
id1908960
size114,055
M. Ali AKBAY (m-ali-akbay)

documentation

https://docs.rs/byten

README

byten

Crates.io Documentation License

A binary codec library for efficient encoding and decoding of Rust data structures.

⚠️ Early Development: This library is in active development and the API may change.

Features

  • 🚀 Derive macros for automatic codec implementation (Encode, Decode, Measure)
  • 🔢 Primitive types with custom byte ordering (BE/LE) and variable-length encoding
  • 📦 Collections support: Vec, arrays, slices with configurable length prefixes
  • 🔤 String handling: UTF-8 strings, C strings (CStr), and byte slices
  • 💾 Zero-copy decoding with borrowed data ('encoded lifetime)
  • 🎯 Type-safe enums with discriminant encoding
  • 🔧 Flexible attribute-based customization with inline codec syntax
  • 🎨 Nested structures including boxed types for recursive data

Quick Start

Add to your Cargo.toml:

[dependencies]
byten = "0.0"

Basic Usage

use byten::{DefaultCodec, DecodeOwned, Encode, Measure, EncodeToVec as _};

#[derive(Debug, DefaultCodec, Encode, Measure, DecodeOwned, PartialEq)]
struct Person {
    #[byten($be)]
    id: u32,
    age: u8,
    #[byten($bytes[u8] $utf8 $own)]
    name: String,
}

fn main() {
    let person = Person {
        id: 12345,
        age: 30,
        name: "Alice".to_string(),
    };

    // Encode to Vec
    let encoded = person.encode_to_vec().unwrap();
    
    // Decode from slice
    let mut offset = 0;
    let decoded = Person::decode(&encoded, &mut offset).unwrap();
    assert_eq!(person, decoded);
}

Advanced Examples

Zero-Copy Borrowed Data

use byten::{DefaultCodec, Decode, Encode, Measure, EncodeToVec as _};
use std::ffi::CStr;

#[derive(Debug, DefaultCodec, Encode, Decode, Measure)]
pub struct Person<'encoded> {
    pub first_name: &'encoded CStr,
    pub last_name: &'encoded CStr,
    
    #[byten($bytes[u16 $be] $utf8)]
    pub address: &'encoded str,
    
    #[byten($bytes[u32 $uvarbe])]
    pub avatar_image: &'encoded [u8],
    
    #[byten(.. $utf8)]
    pub extra_data: &'encoded str,
}

Enums with Discriminants

use byten::{DefaultCodec, DecodeOwned, Encode, Measure};

#[derive(Debug, DefaultCodec, DecodeOwned, Encode, Measure, PartialEq)]
#[repr(u16)]
#[byten($le)]
enum Color {
    Red = 1,
    Green = 2,
    Blue = 3,
    Grayscale(#[byten($be)] u16) = 4,
    RGBa {
        red: u8,
        green: u8,
        blue: u8,
        #[byten($be)]
        alpha: u16,
    } = 5,
    Gradient(Box<Color>, Box<Color>) = 6,
}

Recursive Structures

use byten::{DefaultCodec, DecodeOwned, Encode, Measure};
use std::ffi::CString;

#[derive(Debug, DefaultCodec, Encode, Measure, DecodeOwned)]
pub struct Directory {
    #[byten(CStr $own)]
    pub name: CString,
    #[byten(Entry box for[u16 $be])]
    pub entries: Vec<Box<Entry>>,
}

#[derive(Debug, DefaultCodec, Encode, Measure, DecodeOwned)]
pub struct File {
    #[byten(CStr $own)]
    pub name: CString,
    #[byten($bytes[u16 $be] $own)]
    pub content: Vec<u8>,
    #[byten(u32 $be ?)]
    pub assigned_application_id: Option<u32>,
}

#[derive(Debug, DefaultCodec, Encode, Measure, DecodeOwned)]
#[repr(u8)]
pub enum Entry {
    File(File) = 1,
    Directory(Directory) = 2,
}

Inline Codec Syntax

use byten::{byten, Decoder, EncoderToVec as _};

fn main() {
    // Define codec inline without derive macros
    let codec = byten!( $bytes[u32 $be] $utf8 );

    let original_str = "Hello, Byten!";
    let encoded = codec.encode_to_vec(original_str).unwrap();
    let decoded_str = codec.decode(&encoded, &mut 0).unwrap();
}

Attribute Syntax

The #[byten(...)] attribute supports a flexible syntax for customizing encoding:

  • Endianness: $be (big-endian), $le (little-endian)
  • Variable-length: $uvarbe (variable-length unsigned, big-endian)
  • Collections: T for[Length], T []
  • Bytes: $bytes[Length] for raw byte slices
  • Strings: $utf8 for UTF-8 strings, CStr for C strings
  • Ownership: $own to decode into owned data (e.g., String, Vec)
  • Optional: ? for Option<T> types with presence byte
  • Boxing: box for Box<T> types
  • Phantom: = expr for constant values with zero bytes
  • Remaining: .. to consume rest of input
  • Tuples: (a, b, ...N) as built-in codecs for N sized tuples
  • Custom: { expr } for custom codec expressions

Features Flags

  • std (default): Enable standard library support. Disable for no_std environments with default-features = false
  • alloc (default via std): Enable types that require allocation (Vec, Box, String). Can be used in no_std with an allocator.
  • anyhow (default): Integration with the anyhow error handling crate (requires std)
  • derive (default): Enable derive macros for self-coded traits. Works in all modes (core-only, alloc, std).

Using in no_std Environments

Without an allocator (core only)

For embedded systems without an allocator, use only core types:

[dependencies]
byten = { version = "0.0", default-features = false }

This provides support for:

  • Primitive types (u8, i8, bool, etc.)
  • Arrays and slices
  • Borrowed data (&str, &[u8], &CStr)
  • Endian conversion
  • Fixed-size types

With derive macros:

[dependencies]
byten = { version = "0.0", default-features = false, features = ["derive"] }

Note: When using derive macros in core-only mode, avoid using Vec, Box, String, or other allocation-dependent types in your structs.

With an allocator (core + alloc)

For no_std environments with an allocator:

[dependencies]
byten = { version = "0.0", default-features = false, features = ["alloc"] }

This adds support for:

  • Vec<T> collections
  • Box<T> heap allocation
  • Owned strings (String)
  • Variable-length encoding (UVarBECodec)

With derive macros (recommended for most use cases):

[dependencies]
byten = { version = "0.0", default-features = false, features = ["alloc", "derive"] }

Note: The derive feature works in all modes (core-only, alloc, and std). The generated code will only use features that are enabled.

Examples

The byten/examples directory contains several complete examples:

  • array.rs: Encoding arrays with variable-length integers
  • borrowed.rs: Zero-copy decoding with borrowed data and lifetimes
  • archive.rs: Recursive structures (file system directory tree)
  • icmp.rs: Network packet encoding (ICMP header)
  • nostd.rs: Simple FS structures for no_std environments
  • inline.rs: Using the inline byten!() macro for ad-hoc codecs

Run examples with:

cargo run --example borrowed

License

Licensed under either of:

at your option.

Contributing

Contributions are welcome! Please read our Contributing Guidelines for details on how to submit pull requests, report issues, and contribute to the project.

This project adheres to the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.

Commit count: 0

cargo fmt