Expand description
§Zero-cost byte-backed representations
wire-repr generates safe borrowed views, constrained mutable views, and atomic
caller-buffer builders for binary layouts. Generated code works directly with byte
slices: it does not cast bytes to Rust structs, allocate, perform I/O, or depend on
alignment and ABI layout.
The crate is no_std, has no default features, and keeps domain policy in the
consumer. Layouts establish byte ownership, bounds, framing, and encoding mechanics;
callers remain responsible for magic values, reserved bits, checksums, and cross-field
semantics.
§Quick start
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).unwrap();
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; 5];
let (mut view, suffix) = HeaderBuilder::new()
.kind(7)
.length(256)
.flags(0b0000_1011)
.build_into(&mut output)
.unwrap();
view.set_kind(8).unwrap();
assert_eq!(view.as_bytes(), &[8, 0x01, 0x00, 0b0000_1011]);
assert_eq!(suffix, &[0]);§Parsing and represented bytes
Every generated immutable view provides two explicit entry points:
parse_prefixparses one representation and returns the disjoint suffix;parse_exactrequires the complete input to be exactly one representation.
as_bytes returns only the bytes owned by the representation. Accepted bytes are
borrowed and preserved verbatim, including opaque gaps and legal noncanonical encodings
accepted by a custom PrefixCodec. Parsing performs structural validation; it does
not reconstruct bytes from decoded values or apply consumer policy.
Fixed layouts expose View::WIDTH. Dynamic sequential layouts discover their represented
extent while validating prefix fields, bounded regions, padding, and alignment.
§Generated API
For layout Packet, wire_repr! generates a family centered on the declaration:
| Generated item | Purpose |
|---|---|
PacketView<'wire> | Immutable borrowed representation and field getters |
PacketViewMut<'wire> | Constrained mutable representation and eligible setters |
PacketBuilder<'value> | Fluent caller-buffer construction |
PacketError | Structural parse errors |
PacketMutationError | Fixed-field planning and setter errors |
PacketWriteError | Missing inputs, planning, extent, and capacity errors |
A field getter has the declared field name. Prefix fields also expose
<field>_encoded() so callers can inspect their exact accepted encoding. Bit projections
produce named bool or unsigned scalar getters without becoming independent byte owners.
Mutable views provide parse_prefix_mut, parse_exact_mut, as_view, and into_view.
Setters are generated only for same-width fields whose mutation cannot invalidate dynamic
framing. Mutable views deliberately do not expose unrestricted access to their backing
slice.
Builders use new, one fluent method per caller-supplied field, and build_into.
Length fields used by region(source) are derived from region inputs rather than supplied
separately. Builders finish all fallible planning and capacity checks before the first
write, so an error leaves the complete destination unchanged. Success returns the bounded
mutable view and its disjoint mutable suffix.
Generated error variants retain field or physical-position context. Their exact surface is visible on each generated layout because it depends on the declared codecs and layout shape.
§Layout kinds
Sequential layouts normally infer physical placement from declaration order:
wire_repr! {
pub layout Frame {
field payload_length: BeU16;
field payload: region(payload_length);
field checksum: BeU32;
}
}Fields, padding, and alignment may instead all use explicit one-based position values
when physical order must differ from declaration and API order. Mixing implicit and
explicit sequential placement is rejected.
Absolute layouts use mandatory zero-based offsets and may contain represented gaps:
wire_repr! {
pub absolute layout Header {
field magic: bytes(4) { offset: 0; }
field version: BeU16 { offset: 8; }
}
}Absolute layouts are fixed-width. They do not infer offsets and do not support prefix fields, regions, padding, or alignment.
See wire_repr! for the declaration grammar and generated-name reference.
§Field codecs and framing
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. bytes(N) exposes an opaque
borrowed span through Bytes.
Custom fixed-width fields use codec(path) and implement FixedCodec. Variable-width
prefix fields use prefix(path) and implement PrefixCodec. Both contracts separate
fallible planning from infallible emission through EncodePlan. This separation is what
lets generated setters and builders preserve whole-destination atomicity.
region(source) borrows an opaque span whose length is decoded from an earlier physical
field. Consumers can pass that span to a protocol-specific parser without teaching the
layout compiler domain semantics.
The codec module documents the implementor laws and extension boundary.
§Total semantic mappings
An eligible built-in fixed integer or bytes(N) field may add as TypePath, for example
field kind: BeU16 as crate::Kind; or
field address: bytes(4) as crate::Address;. The physical codec still owns byte decoding,
encoding, range errors, and atomicity; the mapped type is the nominal consumer-facing API.
Mapped fields generate field() for the semantic value and field_raw() for the raw codec
value. Eligible mutable fields also generate semantic and _raw setters, and builders
generate both fluent forms for the same input slot: the last call wins. A region-length
source exposes both getters but has neither setter nor builder input because the builder
derives its raw value from the region.
Mappings are deliberately total: getters use Semantic: From<Raw> and setters/builders
use Raw: From<Semantic>. Raw types are exact codec types, including u32 for U24 and
[u8; N] for bytes(N). There is no fallible semantic conversion layer. Consequently a
semantic U24 value can still produce an out-of-range raw u32, which the physical codec
rejects without changing the destination. Mapped byte values are owned arrays or wrappers;
unmapped bytes(N) continues to return borrowed Bytes (&[u8]).
Only built-in fixed integers and bytes(N) are eligible. Declared scalar Name: Codec;
instead declares a reusable codec-owning nominal wrapper; it is not an as Type mapping,
and mappings do not apply to declared scalar codecs, custom/direct codecs, prefix fields,
or regions. A mapping compiles to direct From calls around the existing codec operations:
no runtime metadata, allocation, or dynamic dispatch is introduced.
§Deliberate limits
wire-repr is a byte-representation compiler, not a runtime schema system. It does not
provide reflection, descriptors, schema walkers, repeated sequences, tagged unions,
arbitrary conditional fields, checksums, protocol state, allocation policy, or I/O.
Custom codecs and consumer validation remain ordinary explicit Rust.
Re-exports§
pub use codec::BeI16;pub use codec::BeI32;pub use codec::BeI64;pub use codec::BeI128;pub use codec::BeU16;pub use codec::BeU24;pub use codec::BeU32;pub use codec::BeU64;pub use codec::BeU128;pub use codec::Bytes;pub use codec::EncodePlan;pub use codec::ExactWidthError;pub use codec::FixedCodec;pub use codec::I8;pub use codec::LeI16;pub use codec::LeI32;pub use codec::LeI64;pub use codec::LeI128;pub use codec::LeU16;pub use codec::LeU24;pub use codec::LeU32;pub use codec::LeU64;pub use codec::LeU128;pub use codec::PrefixCodec;pub use codec::PrefixExtent;pub use codec::U8;pub use codec::U24RangeError;
Modules§
- codec
- Codec contracts and built-in codecs.
Macros§
- wire_
repr - Declares sequential or fixed absolute-offset byte-backed layouts.