byteable 0.23.0

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

This file provides guidance to AI-Agents when working with code in this repository.

## Project Overview

`byteable` is a Rust crate for zero-overhead, zero-copy serialization/deserialization of byte-oriented data. The crate provides a modular trait system for converting between Rust types and byte arrays, with support for endianness control, sync/async I/O, and procedural macros.

## Build and Development Commands

### Testing

```bash
# Run all tests
cargo test

# Run tests for a specific test file
cargo test --test enum_test
cargo test --test primitive_types_test

# Run tests with tokio feature
cargo test --features tokio

# Run tests without default features (no_std)
cargo test --no-default-features

# Run doctests
cargo test --doc
```

### Building

```bash
# Build the project
cargo build

# Build with all features
cargo build --features all

# Build without std (no_std mode)
cargo build --no-default-features

# Build documentation
cargo doc --open --no-deps
```

### Benchmarks

```bash
# Run benchmarks (uses criterion)
cargo bench
```

### Examples

```bash
# Run examples (requires std feature)
cargo run --example simple_usage
cargo run --example file_io
cargo run --example enum_endianness
cargo run --example cursor_usage
cargo run --example try_io
```

### Publishing

The project is a workspace with two crates:

- Main crate: `byteable` (root directory)
- Proc macro crate: `byteable_derive` (subdirectory)

When bumping versions, update both crates and ensure version compatibility in [Cargo.toml](Cargo.toml).

## Architecture

### Crate Structure

This is a **dual-crate architecture**:

1. **`byteable`** (main crate) - Core traits and implementations
2. **`byteable_derive`** (proc-macro crate) - Procedural macros for deriving traits

### Core Trait System

The crate uses a **modular trait hierarchy** (as of v0.20+):

1. **`AssociatedByteArray`** - Associates a type with its byte array representation
2. **`IntoByteArray`** - Infallible conversion to bytes
3. **`FromByteArray`** - Infallible conversion from bytes
4. **`TryIntoByteArray`** - Fallible conversion to bytes
5. **`TryFromByteArray`** - Fallible conversion from bytes (used for `bool`, `char`, enums)

These traits replaced the previous monolithic `Byteable` trait to provide more flexibility.

### Key Components

#### Endianness System ([src/endian.rs]src/endian.rs)

- **`EndianConvert` trait** - For types supporting endianness conversion
- **`BigEndian<T>` wrapper** - Ensures big-endian byte order
- **`LittleEndian<T>` wrapper** - Ensures little-endian byte order
- These wrappers are `#[repr(transparent)]` for zero-cost abstraction

#### Raw Type Delegation Pattern

The derive macro generates a hidden "raw" struct (e.g., `__byteable_raw_Foo` for `struct Foo`) with:

- `#[repr(C, packed)]` for predictable layout
- Endianness wrappers around fields based on `#[byteable(big_endian)]` or `#[byteable(little_endian)]` attributes
- Direct `transmute`-based `IntoByteArray`/`FromByteArray` implementations

The original struct gets `From` conversions to/from the raw struct, creating a safe API layer.

#### Safety Validation ([src/derive_safety_helpers.rs]src/derive_safety_helpers.rs)

- **`ValidBytecastMarker` trait** - Marks types safe for `transmute`-based conversions
- Automatically implemented for primitive types, endian wrappers, and arrays
- Raw structs require all fields to implement `ValidBytecastMarker`
- This prevents unsafe usage with types like `String`, `Vec`, references, etc.

#### I/O Extension Traits

- **Sync I/O** ([src/io.rs]src/io.rs): `ReadByteable`, `WriteByteable` - Extend `std::io::Read`/`Write`
- **Async I/O** ([src/async_io.rs]src/async_io.rs): `AsyncReadByteable`, `AsyncWriteByteable` - Extend `tokio::io::AsyncRead`/`AsyncWrite`

### Derive Macro Implementation ([byteable_derive/src/lib.rs]byteable_derive/src/lib.rs)

The `#[derive(Byteable)]` macro handles three cases:

1. **Named structs** - Generates raw struct with field-level endianness attributes
2. **Tuple structs** - Similar to named structs but with positional fields
3. **Unit structs** - Direct implementation (zero-sized type, empty byte array)
4. **Enums** - Only C-like enums with explicit discriminants

#### Enum Support

- Requires `#[repr(u8)]`, `#[repr(u16)]`, etc.
- All variants must be unit variants (no fields)
- All variants must have explicit discriminant values
- Implements `TryFromByteArray` (not `FromByteArray`) because invalid discriminants are possible
- Supports type-level endianness: `#[byteable(big_endian)]` or `#[byteable(little_endian)]`

#### Field Attributes

- `#[byteable(little_endian)]` - Wrap field in `LittleEndian<T>`
- `#[byteable(big_endian)]` - Wrap field in `BigEndian<T>`
- `#[byteable(transparent)]` - Use field's raw type (via `HasRawType::Raw`)
- `#[byteable(try_transparent)]` - Use field's raw type with fallible conversion (via `TryHasRawType::Raw`)

When `try_transparent` is used, the struct implements `TryFromByteArray` instead of `FromByteArray`.

### Feature Flags

- `derive` (default) - Enables `#[derive(Byteable)]` and `#[derive(UnsafeByteableTransmute)]`
- `std` (default) - Enables `std` support (I/O traits, error types)
- `tokio` - Enables async I/O traits for tokio
- `all` - Enables all features

### no_std Support

The crate is `no_std` compatible when built with `--no-default-features`. The I/O traits require `std` feature.

## Important Development Guidelines

### Safety Requirements for Byteable Types

**Safe to use:**

- Primitive numeric types (`u8`, `i32`, `f64`, etc.)
- `bool`, `char` (with `TryFromByteArray` validation)
- Arrays of safe types
- `BigEndian<T>`, `LittleEndian<T>` wrappers
- Structs with `#[repr(C, packed)]`
- C-like enums with explicit discriminants (with `TryFromByteArray`)

**Never use:**

- `String`, `Vec`, or heap-allocated types
- References or pointers (`&T`, `Box<T>`, `*const T`)
- Complex enums with fields
- Types with `Drop` implementations
- `NonZero*` types or types with invariants

### When Adding New Features

1. **Primitive type support** - Add implementations in [src/byteable_trait.rs]src/byteable_trait.rs
2. **Endianness changes** - Modify [src/endian.rs]src/endian.rs
3. **Macro changes** - Edit [byteable_derive/src/lib.rs]byteable_derive/src/lib.rs
4. **New I/O traits** - Add to [src/io.rs]src/io.rs or [src/async_io.rs]src/async_io.rs

### Testing Strategy

- **Integration tests** ([tests/]tests/) - Test derive macros, specific features
- **Doctests** - Embedded in rustdoc comments, run with `cargo test --doc`
- **Examples** ([examples/]examples/) - Demonstrate real-world usage patterns
- **Benchmarks** ([benches/]benches/) - Performance validation with criterion

Important test files:

- [tests/enum_test.rs]tests/enum_test.rs - C-like enum derive validation
- [tests/primitive_types_test.rs]tests/primitive_types_test.rs - `bool`, `char` validation
- [tests/try_transparent_test.rs]tests/try_transparent_test.rs - Nested enum/validated types
- [tests/safety_validation_test.rs]tests/safety_validation_test.rs - `ValidBytecastMarker` tests

## Common Patterns

### Adding a New Primitive Type

If adding support for a new primitive type that needs validation (like `bool`, `char`):

1. Implement `TryFromByteArray` instead of `FromByteArray`
2. Add validation logic that returns `EnumFromBytesError` for invalid byte patterns
3. Implement `IntoByteArray` for infallible conversion
4. Add test coverage in [tests/primitive_types_test.rs]tests/primitive_types_test.rs

### Enum Implementation Pattern

Enums generate a raw wrapper type like:

```rust
#[repr(transparent)]
struct __byteable_raw_Status(u8); // or BigEndian<u8>, LittleEndian<u8>
```

The `TryFrom<Raw>` implementation validates discriminants and returns errors for invalid values.

### Version Coordination

When releasing new versions:

1. Update `byteable_derive` version in [byteable_derive/Cargo.toml]byteable_derive/Cargo.toml
2. Update main crate version and `byteable_derive` dependency in [Cargo.toml]Cargo.toml
3. Ensure compatibility - macro crate should be backward compatible when possible