wire-repr 0.1.3

A no_std, no_alloc Rust library for wire representations.
Documentation
<h1 align="center">wire-repr</h1>

<p align="center">
  <strong>Zero-cost byte-backed representations for binary formats.</strong>
</p>

`wire-repr` generates safe borrowed views, constrained mutable views, and atomic
caller-buffer builders from compact layout declarations. It is designed for network
protocols, file headers, storage pages, firmware formats, IPC, and other binary data
where exact bytes and explicit ownership matter.

> [!IMPORTANT]
> Generated views borrow ordinary byte slices. They do not reinterpret bytes as Rust
> structs and do not depend on alignment, ABI layout, allocation, or `unsafe`.

---

## ✨ What it does

- **Zero-copy views.** Parse directly over caller-owned bytes and retain exact represented
  spans, including legal noncanonical prefix encodings.
- **Direct generated code.** Fixed getters compile to ordinary loads, endian conversions,
  shifts, and masks—without runtime schemas, reflection, or field lookup.
- **Atomic writes.** Builders plan the complete representation before touching caller
  output; an error leaves the whole destination unchanged.
- **Explicit framing.** `parse_prefix` returns one bounded representation plus its suffix,
  while `parse_exact` rejects unrelated trailing bytes.
- **Consumer-owned semantics.** The framework owns bounds and layout. Consumers keep
  ownership of magic values, reserved-byte policy, checksums, and cross-field rules.
- **Small runtime.** The public crate is `no_std`, `no_alloc`, dependency-free at target
  runtime, and safe Rust only.

## 🚀 Quick start

Add the facade crate:

```toml
[dependencies]
wire-repr = { version = "0.1", default-features = false }
```

Declare a sequential layout. Physical placement is inferred from declaration order:

```rust
use wire_repr::wire_repr;

wire_repr! {
    pub layout Header {
        field kind: U8;
        field length: BeU16;
        field flags: U8 {
            projections {
                bit enabled: 0;
                bits mode: 1..=3;
            }
        }
    }
}

let input = [7, 0x01, 0x00, 0b0000_1011, 0xff];
let (view, suffix) = HeaderView::parse_prefix(&input).expect("valid header");

assert_eq!(view.as_bytes(), &input[..4]);
assert_eq!(suffix, &[0xff]);
assert_eq!(view.kind(), 7);
assert_eq!(view.length(), 256);
assert!(view.enabled());
assert_eq!(view.mode(), 5);

let mut output = [0u8; 4];
let (built, suffix) = HeaderBuilder::new()
    .kind(7)
    .length(256)
    .flags(0b0000_1011)
    .build_into(&mut output)
    .expect("complete builder");

assert_eq!(built.as_bytes(), &input[..4]);
assert!(suffix.is_empty());
```

> [!NOTE]
> `parse_prefix` excludes the suffix from the generated view. Use `parse_exact` when the
> entire input must be exactly one representation.

## 🧭 Layout model

### Sequential layouts

Sequential layouts use source order by default. Fields, padding, and alignment occupy
contiguous one-based physical positions:

```rust
wire_repr::wire_repr! {
    pub layout Record {
        field kind: U8;
        padding { length: 3; }
        align { boundary: 8; }
        field flags: BeU16;
    }
}
```

Use explicit `position` on **every** physical entry only when wire order must differ from
API and documentation order:

```rust
wire_repr::wire_repr! {
    pub layout Reordered {
        field checksum: BeU16 { position: 2; }
        field tag: U8 { position: 1; }
    }
}
```

Mixing explicit and implicit placement is rejected. Declaration order always controls
the generated API and rustdoc order; explicit positions control only physical order.

### Absolute layouts

Absolute layouts use mandatory zero-based byte offsets:

```rust
wire_repr::wire_repr! {
    pub absolute layout DatabaseHeader {
        field magic: bytes(16) { offset: 0; }
        field version: BeU32 { offset: 16; }
    }
}
```

Gaps remain represented bytes and are preserved verbatim. Overlapping codec extents are
rejected before input access. Absolute layouts are fixed-width and deliberately do not
infer offsets or support padding and alignment entries.

## 🧩 Fields and framing

### Fixed values and byte spans

Built-in fixed codecs cover unsigned 8/16/24/32/64/128-bit integers and signed
8/16/32/64/128-bit integers in the applicable byte orders. Fixed codecs decode every exact-width bit pattern; domain
validation remains consumer-owned.

Use `bytes(N)` when a field owns fixed-width bytes without interpreting them. Its getter
returns the original borrowed `&[u8]`. Builders and setters check only the exact width
before mutation.

### Bit projections

Unsigned built-in storage fields can expose named immutable projections:

```rust
field flags: U8 {
    projections {
        bit enabled: 0;
        bits mode: 1..=3;
    }
}
```

Bit zero is the decoded value's least-significant bit regardless of wire endianness.
The storage field remains the only byte owner; projection getters are direct shift/mask
operations with no runtime metadata or dispatch.

### Prefix fields

A sequential field backed by a custom `PrefixCodec` discovers its exact encoded width
during structural parsing:

```rust
field name: prefix(crate::Terminated);
```

The generated view preserves the exact accepted bytes. `name()` returns the decoded
value, while `name_encoded()` exposes its original encoding. Parsing validates the
prefix extent once and rejects any codec claim beyond the remaining input.

### Bounded regions

A region borrows an opaque span whose length comes from an earlier physical field:

```rust
wire_repr::wire_repr! {
    pub layout Frame {
        field payload_length: BeU16;
        field payload: region(payload_length);
        field checksum: BeU32;
    }
}
```

Dynamic builders accept the region bytes and derive its length source automatically.
A source may be declared later in explicit-position source order, but it must physically
precede every region it frames. Regions may be empty and remain available as exact
borrowed bytes for a consumer-owned inner parser.

> [!TIP]
> Keep unsupported or application-specific material as `bytes(N)` or `region(length)`,
> then parse it with a small consumer-owned view. The framework should not learn domain
> policy merely to move a slice boundary.

## ✍️ Mutation and building

Generated mutable views preserve the same represented extent as immutable views.
Same-width fixed fields receive typed setters when changing them cannot invalidate
region framing. Prefix fields, regions, and region length sources do not receive
in-place setters, and mutable views never expose unrestricted access to the full backing
slice.

Builders preflight codec plans, checked arithmetic, derived region lengths, and output
capacity before writing. A successful build returns the bounded mutable view together
with its disjoint suffix. A failed build leaves every caller-owned output byte unchanged.
Padding, alignment bytes, absolute gaps, and suffixes are therefore preserved rather
than silently normalized.

## 🔬 What reaches the CPU

Generated fixed-layout operations are ordinary safe Rust: direct byte loads, endian
conversion, shifts, masks, and bounded copies. There are no runtime descriptors, schema
walkers, erased codecs, hidden allocation, or dynamic dispatch.

For example, with Rust 1.91.0 targeting `x86_64-unknown-linux-gnu`, the generated
big-endian `u16` getter and its handwritten safe-Rust equivalent compile to the same
optimized body (compiler-local labels simplified):

```asm
cmpq    $2, %rsi
jne     .invalid
movzwl  (%rdi), %edx
rolw    $8, %dx
movw    $1, %ax
retq
.invalid:
xorl    %eax, %eax
retq
```

The generated fixed builder is likewise merged by the optimizer with its handwritten
equivalent. Its complete operation shape is a capacity check, endian conversion, and
one store—no framework calls:

```asm
cmpq    $2, %rsi
jb      .short
rolw    $8, %dx
movw    %dx, (%rdi)
.short:
cmpq    $2, %rsi
setae   %al
retq
```

The [probe source](wire-repr/tests/codegen.rs) covers getters, projections, mutation,
and builders. The [pinned release-codegen gate](ci/check-codegen.py) compares each one
against equivalent handwritten safe Rust and rejects extra instructions, calls, panic
paths, allocation, or dynamic dispatch:

```sh
python3 ci/check-codegen.py
```

The stable contract is the optimized operation shape and absence of framework
machinery—not fragile textual assembly snapshots tied to register allocation or labels.

## ⚠️ Deliberate limits

> [!NOTE]
> `wire-repr` is a byte-representation compiler, not a universal schema VM or protocol
> runtime.

- Repeated sequences and arbitrary conditional fields are not supported.
- Prefix fields and bounded regions are sequential-only.
- Absolute layouts remain fixed-width and explicit-offset-only.
- The framework does not own checksums, semantic relationships, protocol state, I/O, or
  allocation policy.
- Custom codecs remain explicit Rust types rather than runtime descriptors.

For the normative ownership, parsing, mutation, and extension rules, see
[`ARCHITECTURE.md`](ARCHITECTURE.md). Generated APIs and codec contracts are documented
in the [crate documentation](https://docs.rs/wire-repr).

## 📦 Workspace and contract

The repository contains two crates:

- `wire-repr` — public `no_std` runtime facade and `wire_repr!` reexport;
- `wire-repr-macros` — host-side procedural-macro compiler.

The target-runtime contract is Rust 1.91, edition 2024, empty default features, no
allocation, no runtime dependencies, and `unsafe_code = "deny"`.

## 📄 License

MIT © 2026 SilentBless. See [LICENSE](LICENSE).