pub trait Codec {
type Value;
type Unit;
type DecodeError;
type EncodeError;
const MIN_UNITS_PER_VALUE: usize;
const MAX_ENCODE_UNITS_PER_VALUE: usize;
const MAX_DECODE_UNITS_PER_VALUE: usize;
const MAX_ENCODE_RESET_UNITS: usize = 0;
const MAX_ENCODE_FINISH_UNITS: usize = 0;
const MAX_DECODE_RESET_VALUES: usize = 0;
const MAX_DECODE_FINISH_VALUES: usize = 0;
// Required methods
unsafe fn encode(
&mut self,
value: &Self::Value,
output: &mut [Self::Unit],
output_index: usize,
) -> Result<usize, Self::EncodeError>;
unsafe fn decode(
&mut self,
input: &[Self::Unit],
input_index: usize,
) -> Result<(Self::Value, NonZeroUsize), DecodeFailure<Self::DecodeError>>;
// Provided methods
fn can_encode_value(&self, _value: &Self::Value) -> bool { ... }
fn encode_len(&self, _value: &Self::Value) -> usize { ... }
unsafe fn encode_reset(
&mut self,
_output: &mut [Self::Unit],
_output_index: usize,
) -> Result<usize, Self::EncodeError> { ... }
unsafe fn encode_finish(
&mut self,
_output: &mut [Self::Unit],
_output_index: usize,
) -> Result<usize, Self::EncodeError> { ... }
unsafe fn decode_reset(
&mut self,
_output: &mut [Self::Value],
_output_index: usize,
) -> Result<usize, Self::DecodeError> { ... }
unsafe fn decode_eof(
&mut self,
input: &[Self::Unit],
input_index: usize,
) -> Result<(Self::Value, NonZeroUsize), DecodeFailure<Self::DecodeError>> { ... }
unsafe fn decode_finish(
&mut self,
_output: &mut [Self::Value],
_output_index: usize,
) -> Result<usize, Self::DecodeError> { ... }
}Expand description
Encodes and decodes one value or codec quantum against a unit buffer.
Codec is the lowest-level abstraction in the codec stack. It is intended
for hot paths that have already validated buffer capacity and want to avoid
constructing subslices for every value. Higher-level transcoders and
convenience APIs are responsible for checked buffer management and owned
output allocation.
MIN_UNITS_PER_VALUE and MAX_DECODE_UNITS_PER_VALUE describe the readable
representation-width bounds for one decoded value. If fewer than the
minimum units are available, no complete value can exist, so a streaming
caller can request more input or report an incomplete EOF tail. The minimum
is also the smallest safety precondition checked callers must satisfy before
entering decode. The decode maximum bounds successful
consumption and incomplete-input requirements for one value.
MAX_ENCODE_UNITS_PER_VALUE is the independent value-agnostic upper bound
for main-phase encode output. Reserving that many units makes encoding safe
for every encodable value. Once a value and encode state are known, callers
may instead reserve the exact encode_len, which must
not exceed the encode maximum. Complete-lifecycle adapters that still need
to run encode_reset must reserve the maximum first
because reset may change the exact width.
A codec may keep decode-side and encode-side stream state. That state is an implementation detail owned by the codec. Callers do not snapshot or restore it; implementations must keep their own state internally consistent across every public operation. A failed decode attempt must not advance decode state, so callers can retry the same input after refilling their buffer or applying an invalid-input policy.
Decode operations see only the currently supplied input slice and codec
state. decode treats that slice as an open stream segment;
decode_eof receives the same preconditions after the
caller has established that no more units will arrive. Returning
DecodeFailure::Incomplete from decode requests more input for the
current value; it is not itself an EOF error. Codecs that need EOF-aware
maximal-munch parsing or reinterpretation of a trailing prefix can override
decode_eof without changing their streaming behavior.
An incomplete failure may also retain codec-specific context through
DecodeFailure::incomplete_with_source; stream drivers may ignore that
context while retrying and use it for detailed EOF diagnostics.
§Associated Types
Value: Logical value decoded from or encoded into the buffer. This may be a scalar such asu8,u16,u64, achar, a fixed quantum such as[u8; 3], or an owned value such asString/Vec<u8>. Adapters that need scratch initialization add their own bounds at the use site.Unit: Buffer unit used by the encoded representation. Implementations are typically scalar storage units such asu8,u16, orchar. Adapters that allocate owned output add their own initialization bounds at the use site.
Implementors must uphold the safety contract documented by
decode, encode,
encode_reset, and
decode_finish. Unchecked implementations must not
read or write outside the caller-provided ranges. Implementations should use
debug_assert! to state the expected buffer bounds at the unchecked entry
point.
Implementations must also guarantee that
MIN_UNITS_PER_VALUE is non-zero and no larger
than MAX_DECODE_UNITS_PER_VALUE, which
must also be non-zero. MAX_ENCODE_UNITS_PER_VALUE may be zero for a codec
that always buffers each accepted value instead of immediately emitting
units. Checked adapters enforce the decode-bound invariants with
compile-time assertions before using codec-provided bounds.
§Why the low-level methods are unchecked
The unsafe entry points are intentional: checked adapters validate the
index and capacity preconditions once, then call encode
and decode without rebuilding subslices or repeating
bounds checks for every value. The safe_vs_unchecked benchmark in
benches/transcode.rs compares the same 64 KiB copy loop in release mode.
Its result is workload- and toolchain-specific, so callers should use
checked adapters unless they can establish the documented preconditions at
a trusted boundary. Measure representative codec workloads before choosing
an unchecked entry point. Codec implementations should keep the unchecked
methods small and use debug_assert! for those assumptions.
§Examples
A minimal identity codec exposes its bounds and decodes one byte:
use core::convert::Infallible;
use core::num::NonZeroUsize;
use qubit_codec::Codec;
use qubit_codec::DecodeFailure;
struct Identity;
impl Identity {
fn new() -> Self { Self }
}
impl Codec for Identity {
type Value = u8;
type Unit = u8;
type DecodeError = Infallible;
type EncodeError = Infallible;
const MIN_UNITS_PER_VALUE: usize = 1;
const MAX_DECODE_UNITS_PER_VALUE: usize = 1;
const MAX_ENCODE_UNITS_PER_VALUE: usize = 1;
unsafe fn decode(&mut self, input: &[u8], index: usize)
-> Result<(u8, NonZeroUsize), DecodeFailure<Infallible>> {
Ok((input[index], NonZeroUsize::MIN))
}
unsafe fn encode(&mut self, value: &u8, output: &mut [u8], index: usize)
-> Result<usize, Infallible> {
output[index] = *value;
Ok(1)
}
}
let mut codec = Identity::new();
assert_eq!(codec.encode_len(&42), 1);
// SAFETY: the input contains the one readable unit required by Identity.
let (value, consumed) = unsafe { codec.decode(&[42], 0) }.unwrap();
assert_eq!((value, consumed.get()), (42, 1));Required Associated Constants§
Sourceconst MIN_UNITS_PER_VALUE: usize
const MIN_UNITS_PER_VALUE: usize
The minimum possible non-zero readable unit count for one decoded value.
This is the minimum readable width of any valid encoded value. Checked
callers use it for planning and fast impossibility checks. If a
streaming decoder has fewer than this many readable units, no complete
value can be present at the current position. Unsafe
decode callers must provide at least this many
readable units at index.
Default decode hooks use the input unit count as their output bound: an invalid-input policy may consume fewer units than a valid value and still emit one replacement value.
Sourceconst MAX_ENCODE_UNITS_PER_VALUE: usize
const MAX_ENCODE_UNITS_PER_VALUE: usize
The maximum unit count emitted when encoding one value.
This is a value-independent upper bound for the main encode phase. When
no concrete value is available, reserving this many writable units is
sufficient for any encodable value, without first calling
encode_len. For a known value, callers may reserve
only the exact length returned by encode_len instead. This bound does
not include output produced by encode reset or finish phases.
This is also the multiplier used by default encode hooks when estimating the maximum number of output units needed for an input value count.
The bound may be zero for a codec that buffers every accepted value and emits retained output only during a later lifecycle phase.
Sourceconst MAX_DECODE_UNITS_PER_VALUE: usize
const MAX_DECODE_UNITS_PER_VALUE: usize
The maximum non-zero unit count consumed to decode one value.
This is a value-independent upper bound for one complete encoded value
or codec quantum on the decode side. Successful decode consumption and
the required_total carried by DecodeFailure::Incomplete must not
exceed this bound.
Provided Associated Constants§
Sourceconst MAX_ENCODE_RESET_UNITS: usize = 0
const MAX_ENCODE_RESET_UNITS: usize = 0
The maximum unit count emitted when resetting encode state.
This bound covers only output written by
encode_reset. It does not include hook-owned
reset output or any ordinary encoded input values. It must cover every
reachable pre-reset encode state. Stateless codecs should use the
default 0.
Sourceconst MAX_ENCODE_FINISH_UNITS: usize = 0
const MAX_ENCODE_FINISH_UNITS: usize = 0
The maximum unit count emitted when finishing encode state at EOF.
This bound covers only output written by
encode_finish. It does not include hook-owned
finish output and must cover every reachable encode state, even when the
current stream has no pending finish output. Stateless codecs should use
the default 0. Codecs that emit a stream trailer (padding, checksum,
or end-of-stream marker) should override this with the exact maximum
unit count.
Sourceconst MAX_DECODE_RESET_VALUES: usize = 0
const MAX_DECODE_RESET_VALUES: usize = 0
The maximum value count emitted when resetting decode state.
This bound covers only values written by
decode_reset. It does not include hook-owned
reset output or values decoded from source units. It must cover every
reachable pre-reset decode state. Stateless codecs should use the
default 0. Codecs that emit a stream-start sentinel or BOM on reset
should override this.
Sourceconst MAX_DECODE_FINISH_VALUES: usize = 0
const MAX_DECODE_FINISH_VALUES: usize = 0
The maximum value count emitted when finishing decode state.
This bound covers only values written by
decode_finish. It does not include hook-owned
finish output and must cover every reachable decode state, even when the
current stream has no pending finish output. Stateless codecs should use
the default 0.
Required Associated Types§
Sourcetype DecodeError
type DecodeError
The type of errors reported when decoding malformed units.
Sourcetype EncodeError
type EncodeError
The type of errors reported when encoding an unsupported value.
Required Methods§
Sourceunsafe fn encode(
&mut self,
value: &Self::Value,
output: &mut [Self::Unit],
output_index: usize,
) -> Result<usize, Self::EncodeError>
unsafe fn encode( &mut self, value: &Self::Value, output: &mut [Self::Unit], output_index: usize, ) -> Result<usize, Self::EncodeError>
Encodes one borrowed value into output starting at output_index.
§Parameters
value: Value to encode.output: Destination unit buffer.output_index: Start index inoutput.
§Returns
Returns the number of written units.
A successful encode may return 0 when the codec accepted value into
internal encode-side state but intentionally deferred output. This is
the normal shape for accumulative encoders such as base64-byte
aggregators, shift-state encodings, or frame builders. In that case
encode_len for the same value and state must
also return 0, and the retained output must be emitted by a later
successful encode,
encode_finish, or codec-specific facade.
§Errors
Returns Self::EncodeError for encode-side state or representation
failures other than a value being outside the codec’s encodable domain.
Checked callers reject values for which
can_encode_value returns false before
entering this unsafe method. Implementations must leave their internal
state consistent when returning an error.
§Safety
The caller must guarantee that
can_encode_value returned true for
value. Starting at output_index, the caller must also provide either
at least
MAX_ENCODE_UNITS_PER_VALUE
writable
units, which is sufficient for every encodable value, or at least the
exact encode_len for the same value and codec
state. On success, implementations must return that exact written unit
count, including 0 for deliberate buffering, and the count must be no
larger than MAX_ENCODE_UNITS_PER_VALUE. Implementations must not write
beyond the exact encode_len capacity on either the success or error
path.
Sourceunsafe fn decode(
&mut self,
input: &[Self::Unit],
input_index: usize,
) -> Result<(Self::Value, NonZeroUsize), DecodeFailure<Self::DecodeError>>
unsafe fn decode( &mut self, input: &[Self::Unit], input_index: usize, ) -> Result<(Self::Value, NonZeroUsize), DecodeFailure<Self::DecodeError>>
Decodes one value from input starting at input_index.
§Parameters
input: Source unit buffer.input_index: Start index ininput.
§Returns
Returns the decoded value and the non-zero number of consumed units.
§Errors
Returns DecodeFailure::Incomplete when the visible input is a
valid prefix but more units are needed to decide or complete a value.
This reports a streaming boundary, not a final EOF condition; the
caller or higher-level adapter decides what an incomplete tail means
when the upstream source is closed. Codec-specific context may be
retained in the failure’s optional source field.
Returns DecodeFailure::Invalid when the units are malformed,
non-canonical, unmappable, or otherwise invalid for this codec and the
span is known or unknown. Unknown span is represented as
DecodeFailure::Invalid with an unknown consumed-unit hint.
Implementations must leave their internal state consistent when
returning an error.
§Safety
The caller must guarantee that input_index is a valid boundary in
input and that at least
MIN_UNITS_PER_VALUE
units are readable from input_index. Implementations must not read
beyond the currently available units under that precondition. They
may return DecodeFailure::Incomplete when those units are a
valid but incomplete prefix.
On success, implementations must return a consumed unit count no larger
than either the available input or
MAX_DECODE_UNITS_PER_VALUE. An
incomplete result’s required_total must also not exceed that maximum.
When returning DecodeFailure::Incomplete, implementations must
satisfy input.len() - input_index < required_total.get() and
required_total.get() <= Self::MAX_DECODE_UNITS_PER_VALUE. The bound
is the minimum total number of units from the value start, not the
number of additional units to append. With two units available and at
least one more needed, report three, not one or two.
The return type guarantees that successful decoding always consumes at
least one unit. Implementations should use debug_assert! to state
these unchecked entry-point assumptions.
Provided Methods§
Sourcefn can_encode_value(&self, _value: &Self::Value) -> bool
fn can_encode_value(&self, _value: &Self::Value) -> bool
Returns whether value is in this codec’s encodable value domain.
The default implementation returns true, which is correct for codecs
whose Value type contains only values they can encode.
Codecs whose logical value type is broader than their representation
domain, such as an ASCII codec with Value = char, must override this
method.
Checked encoder adapters call this method in the same codec state used
to query encode_len and enter the unsafe
encode method. Complete-lifecycle adapters do so after
encode_reset. Direct unsafe callers must uphold
the same ordering.
§Parameters
value: Value whose encodability is queried.
§Returns
Returns true when value may be passed to
encode_len and encode.
Sourcefn encode_len(&self, _value: &Self::Value) -> usize
fn encode_len(&self, _value: &Self::Value) -> usize
Returns the exact unit count this codec will write when encoding
value.
The default implementation returns
MAX_ENCODE_UNITS_PER_VALUE. This
default is correct only when every successful main encode writes exactly
that many units in the relevant codec state, as fixed-width codecs
normally do.
Variable-width, buffering, or otherwise state-dependent codecs must
override this method to report the true encoded length for encodable
values. The return value is never an estimate or an “unknown” marker:
it must equal the unit count encode subsequently
writes for the same value under the same codec state. It must also
never exceed
MAX_ENCODE_UNITS_PER_VALUE.
Callers that do not yet have a concrete value should use
MAX_ENCODE_UNITS_PER_VALUE directly instead of calling this method.
Default codec-backed encoders use this exact value for per-value output
capacity. The contract requires callers to use this method only when
can_encode_value returned true for the
same value.
§Parameters
value: Value whose encoded length is queried.
§Returns
Returns the unit count encode will write for an
encodable value.
A return value of 0 is valid for stateful encoders that accept a
value into internal state without immediately emitting units. Examples
include codecs that aggregate values into fixed-size quanta, shift-state
encodings, or framing layers that defer output until enough values have
been seen or EOF is finalized. Stateless and directly value-to-unit
codecs should continue returning a positive length.
Sourceunsafe fn encode_reset(
&mut self,
_output: &mut [Self::Unit],
_output_index: usize,
) -> Result<usize, Self::EncodeError>
unsafe fn encode_reset( &mut self, _output: &mut [Self::Unit], _output_index: usize, ) -> Result<usize, Self::EncodeError>
Emits stream-start output and resets encode-side state.
§Parameters
output: Destination unit buffer.output_index: Start index inoutput.
§Returns
Returns the number of reset units written.
§Errors
Returns Self::EncodeError when reset output cannot be emitted.
Implementations must leave encode state unchanged when returning an
error.
§Safety
The caller must guarantee that the implementation can write up to
MAX_ENCODE_RESET_UNITS units starting
at output_index.
Sourceunsafe fn encode_finish(
&mut self,
_output: &mut [Self::Unit],
_output_index: usize,
) -> Result<usize, Self::EncodeError>
unsafe fn encode_finish( &mut self, _output: &mut [Self::Unit], _output_index: usize, ) -> Result<usize, Self::EncodeError>
Emits EOF trailer output and finishes encode-side state.
This is the encode-side counterpart of
decode_finish. Codecs that append stream
trailers (padding, checksums, end-of-stream markers) emit them here.
Stateless codecs use the default no-op.
§Parameters
output: Destination unit buffer.output_index: Start index inoutput.
§Returns
Returns the number of finish units written.
§Errors
Returns Self::EncodeError when finish output cannot be emitted.
Implementations must leave their internal state consistent when
returning an error.
§Safety
The caller must guarantee that the implementation can write up to
MAX_ENCODE_FINISH_UNITS units
starting at output_index.
Sourceunsafe fn decode_reset(
&mut self,
_output: &mut [Self::Value],
_output_index: usize,
) -> Result<usize, Self::DecodeError>
unsafe fn decode_reset( &mut self, _output: &mut [Self::Value], _output_index: usize, ) -> Result<usize, Self::DecodeError>
Emits stream-start values and resets decode-side state.
This is the decode-side counterpart of
encode_reset. Codecs that emit a
stream-start marker or BOM before decoding a new stream emit them
here. Stateless codecs use the default no-op.
§Parameters
output: Destination value buffer.output_index: Start index inoutput.
§Returns
Returns the number of reset values written.
§Errors
Returns Self::DecodeError when reset output cannot be emitted.
Implementations must leave their internal state consistent when
returning an error.
§Safety
The caller must guarantee that the implementation can write up to
MAX_DECODE_RESET_VALUES values
starting at output_index.
Sourceunsafe fn decode_eof(
&mut self,
input: &[Self::Unit],
input_index: usize,
) -> Result<(Self::Value, NonZeroUsize), DecodeFailure<Self::DecodeError>>
unsafe fn decode_eof( &mut self, input: &[Self::Unit], input_index: usize, ) -> Result<(Self::Value, NonZeroUsize), DecodeFailure<Self::DecodeError>>
Decodes one value after the caller has established end of input.
This method has the same safety and state guarantees as
decode, but may resolve an otherwise incomplete
trailing prefix using EOF-aware format rules. The default preserves the
open-stream behavior by delegating to decode.
§Parameters
input: Final source unit buffer; no more units will arrive.input_index: Start index of the value ininput.
§Returns
Returns the decoded value and the non-zero number of consumed units.
§Errors
Returns DecodeFailure::Incomplete for an unresolved final prefix,
or DecodeFailure::Invalid for malformed input, as in
decode. An override may resolve a prefix at EOF.
When returning DecodeFailure::Incomplete, implementations must
satisfy input.len() - input_index < required_total.get() and
required_total.get() <= Self::MAX_DECODE_UNITS_PER_VALUE, as for
decode. required_total is the minimum total number
of units from the value start, not the number of additional units to
append: with two units available and at least one more needed, report
three, not one or two. This condition also applies at EOF.
§Safety
The caller must satisfy the same input-index and minimum-readable-unit
preconditions as decode. Implementations must not
read beyond the currently available units.
Sourceunsafe fn decode_finish(
&mut self,
_output: &mut [Self::Value],
_output_index: usize,
) -> Result<usize, Self::DecodeError>
unsafe fn decode_finish( &mut self, _output: &mut [Self::Value], _output_index: usize, ) -> Result<usize, Self::DecodeError>
Finishes decode-side EOF state into output.
decode_finish receives no source input. Callers must have already
handled any tail reported by DecodeFailure::Incomplete before
finishing decode state. Implementations may emit retained values or
validate internal EOF state, but they must not depend on re-reading the
incomplete source tail.
§Parameters
output: Destination value buffer.output_index: Start index inoutput.
§Returns
Returns the number of finished values written.
§Errors
Returns Self::DecodeError when retained decode state is invalid at
EOF. Implementations must leave their internal state consistent when
returning an error.
§Safety
The caller must guarantee that the implementation can write up to
MAX_DECODE_FINISH_VALUES values
starting at output_index.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".