Qubit Codec (rs-codec)
qubit-codec addresses a recurring problem in format and adapter crates: once a
team defines how one logical value maps to encoded units, it still needs owned
one-shot APIs, caller-buffered streaming, and optional policy hooks. Rebuilding
indices, capacity bounds, progress, and reset/finish lifecycle in each layer
produces incompatible public surfaces for the same representation rules. This
crate centralizes those mechanics while the format crate keeps domain encoding
and errors. It does not ship concrete binary formats, character sets, Base64,
hex, percent encoding, or general-purpose std::io extensions.
A binary format crate example
A protocol crate must encode 0x1234 as [0x12, 0x34], decode the reverse,
treat a lone input byte as incomplete instead of entering the unsafe decode
entry, and encode a batch of values into a caller-owned buffer—all from one
Codec implementation. Callers that only need a single owned conversion use
CodecValueEncoder / CodecValueDecoder; callers that own the destination
buffer use CodecTranscodeEncoder without duplicating bound arithmetic.
Installation
[]
= "0.16"
The default feature set is empty. Enable io only for the qubit-io buffered
bridges, and enable registry for global value codec registration and the
register_value_string_codec! / register_value_bytes_codec! macros. The features are independent:
[]
= "0.17"
= { = "0.16", = ["io"] }
[]
= { = "0.16", = ["registry"] }
Quick start
Implement the representation rule once, then expose owned encoding:
use ;
use ;
;
let mut encoder = new;
let bytes = encoder.encode.expect;
assert_eq!;
The lifecycle-aware decode example shows when
CodecValueDecoder::decode_lifecycle is required instead of strict one-value
decode. The user guide continues this fixed-width scenario
with owned decode, incomplete input, caller-buffered streaming, policy hooks,
and optional qubit-io integration.
The same U16BeCodec can back both owned helpers and batch encoding into a
caller buffer:
use ;
assert_eq!;
assert_eq!;
assert_eq!;
Checked adapters establish index and capacity preconditions before the unsafe
Codec entry points; a one-byte input therefore surfaces as incomplete or
transcode failure rather than undefined behavior. See the user guide
for incremental transcode, EOF handling, and engines with hooks.
What it provides
- Core value/unit contract:
Codec,DecodeFailure, and explicit encode/decode bounds for checked adapters. - Owned whole-value facades:
ValueEncoder,ValueDecoder,CodecValueEncoder,CodecValueDecoder, including lifecycle-aware decode when reset or finish values are declared. - Strict caller-buffered conversion:
Transcoder,CodecTranscodeEncoder,CodecTranscodeDecoder,CodecTranscodeConverter, withTranscodeProgressandTranscodeStatusfor backpressure. - Policy-aware engines:
engine::TranscodeEncodeEngine,engine::TranscodeDecodeEngine,engine::TranscodeConvertEngine, and hooks such asDecodeIncompleteActionfor incomplete tails after EOF is known. - Byte order helpers:
ByteOrder,ByteOrderSpec,BigEndian,LittleEndian,NativeEndian. - With
registry: validated stable IDs,ValueStringCodecDescriptor,ValueBytesCodecDescriptor,ValueStringCodecRegistry,ValueBytesCodecRegistry, andregister_value_string_codec!/register_value_bytes_codec!for type-checked erased whole-value codecs (string or bytes wire) fixed at registration time. - With
io: sync and partial-I/O async transcode input/output bridges overqubit-io.
The crate does not implement domain formats or character-set tables on its own.
Codec::decode separates incomplete visible prefixes from invalid domain input
through DecodeFailure; an incomplete prefix is not an EOF decision by itself.
In the same codec state, Codec::encode_len must match a successful
Codec::encode, including intentional zero-output buffering. A Transcoder
follows reset -> transcode/transcode_eof -> finish; NeedInput leaves its tail
with the caller, NeedOutput requires more destination capacity, and Complete
means all visible input from the call's start index was consumed. Capacity bounds
must cover every reachable transient state; owned adapters may allocate while
streaming APIs use caller-provided buffers. Registry lookup is by validated ID
and execution checks the erased input type before invoking user code.
Learn more
Testing
# Run tests with the default feature set
# Run tests with all declared features
# Project CI checks
# Check code coverage
License
Copyright (c) 2025 - 2026. Haixing Hu. All rights reserved.
Licensed under the Apache License, Version 2.0. See LICENSE for the full license text.
Contributing
Contributions are welcome. Please follow the Rust API guidelines, keep public
API documentation and tests current, and run ./align-ci.sh to format code and
./ci-check.sh to satisfy CI requirements before submitting a pull request.
Author
Haixing Hu - Qubit Co. Ltd.
Repository: https://github.com/qubit-ltd/rs-codec