pub struct TranscodeConvertEngine<D, E, DH, EH>where
D: Codec,
E: Codec<Value = D::Value>,
DH: TranscodeDecodeHooks<D>,
EH: TranscodeEncodeHooks<E>,{ /* private fields */ }Expand description
Reusable buffered conversion engine for codec-backed converters.
The engine owns reusable buffered decode and encode engines. It keeps
common converter control flow private: index validation, pending-value
retention, pending flush, decode-error policy dispatch, encode attempts,
output-capacity checks, and crate::TranscodeStatus reporting.
Use this type to build a streaming converter over two one-value Codec
implementations that share the same logical value type. Each hot-path step
decodes one source unit sequence into a value, then immediately tries to
encode that value into the target output buffer. If the target buffer lacks
capacity, the decoded value is retained in an internal pending slot and
must be drained before more source input is consumed, preserving output
order across buffer turns.
TranscodeConvertEngine is intentionally batch-oriented. Its public
Self::transcode method drives a source/output buffer loop and reuses the
same unchecked codec and hook primitives as crate::TranscodeDecodeEngine
and crate::TranscodeEncodeEngine. It does not call one-value public
transcoders in the hot path.
For strict codec-backed conversion with default decode and encode policies,
use crate::CodecTranscodeConverter. Use TranscodeConvertEngine
directly when either side needs custom malformed-input repair, encode
planning, skipped values, or finish-time output.
The engine follows the same lifecycle as crate::Transcoder:
reset → transcode* → finish → reset. Call Self::reset before starting
a new logical stream and Self::finish after EOF once any incomplete
source tail has been handled.
§Example
use core::{
convert::Infallible,
num::NonZeroUsize,
};
use qubit_codec::{
Codec,
DecodeContext,
DecodeFailure,
EncodeContext,
EncodeOutcome,
TranscodeConvertEngine,
TranscodeDecodeHooks,
TranscodeEncodeHooks,
TranscodeStatus,
};
#[derive(Clone, Copy)]
struct SourceCodec;
#[derive(Clone, Copy)]
struct TargetCodec;
impl Codec for SourceCodec {
type Value = u8;
type Unit = u8;
type DecodeError = Infallible;
type EncodeError = Infallible;
const MIN_UNITS_PER_VALUE: NonZeroUsize = NonZeroUsize::MIN;
const MAX_UNITS_PER_VALUE: NonZeroUsize = NonZeroUsize::MIN;
unsafe fn decode(
&mut self,
input: &[u8],
index: usize,
) -> Result<(u8, NonZeroUsize), DecodeFailure<Self::DecodeError>> {
Ok((input[index].wrapping_add(1), NonZeroUsize::MIN))
}
unsafe fn encode(
&mut self,
value: &u8,
output: &mut [u8],
index: usize,
) -> Result<NonZeroUsize, Self::EncodeError> {
output[index] = *value;
Ok(NonZeroUsize::MIN)
}
}
impl Codec for TargetCodec {
type Value = u8;
type Unit = u8;
type DecodeError = Infallible;
type EncodeError = Infallible;
const MIN_UNITS_PER_VALUE: NonZeroUsize = NonZeroUsize::MIN;
const MAX_UNITS_PER_VALUE: NonZeroUsize = NonZeroUsize::MIN;
unsafe fn decode(
&mut self,
input: &[u8],
index: usize,
) -> Result<(u8, NonZeroUsize), DecodeFailure<Self::DecodeError>> {
Ok((input[index], NonZeroUsize::MIN))
}
unsafe fn encode(
&mut self,
value: &u8,
output: &mut [u8],
index: usize,
) -> Result<NonZeroUsize, Self::EncodeError> {
output[index] = *value;
Ok(NonZeroUsize::MIN)
}
}
struct StrictDecodeHooks;
impl TranscodeDecodeHooks<SourceCodec> for StrictDecodeHooks {
type Error = Infallible;
fn handle_invalid_decode(
&mut self,
_codec: &mut SourceCodec,
error: Infallible,
_consumed: Option<NonZeroUsize>,
_context: DecodeContext,
) -> Result<qubit_codec::DecodeInvalidAction<u8>, Self::Error> {
match error {}
}
}
struct StrictEncodeHooks;
impl TranscodeEncodeHooks<TargetCodec> for StrictEncodeHooks {
type Error = Infallible;
fn encode_value(
&mut self,
codec: &mut TargetCodec,
context: EncodeContext<'_, u8, u8>,
) -> Result<EncodeOutcome, Self::Error> {
let required = TargetCodec::MAX_UNITS_PER_VALUE;
if context.available_output() < required.get() {
return Ok(EncodeOutcome::need_output(required));
}
let (value, _, output, output_index) = context.into_parts();
let written = unsafe { codec.encode(value, output, output_index) }
.map(NonZeroUsize::get)
.unwrap();
Ok(EncodeOutcome::consumed(written))
}
}
let mut engine = TranscodeConvertEngine::new(
SourceCodec,
TargetCodec,
StrictDecodeHooks,
StrictEncodeHooks,
);
let input = [1_u8, 2, 3];
let mut output = [0_u8; 2];
let progress = engine.transcode(&input, 0, &mut output, 0)?;
match progress.status() {
TranscodeStatus::NeedOutput { output_index, .. } => {
assert_eq!(2, output_index);
assert_eq!([2, 3], output);
// Drain `output[..output_index]`, then resume at
// `progress.read()` with fresh output capacity.
}
TranscodeStatus::Complete => unreachable!("output is intentionally short"),
TranscodeStatus::NeedInput { .. } => unreachable!("input is complete"),
}§Type Parameters
D: Source-side decoder codec.E: Target-side encoder codec.DH: Source-side decode hooks.EH: Target-side encode hooks.
Implementations§
Source§impl<D, E, DH, EH> TranscodeConvertEngine<D, E, DH, EH>where
D: Codec,
E: Codec<Value = D::Value>,
DH: TranscodeDecodeHooks<D>,
EH: TranscodeEncodeHooks<E>,
impl<D, E, DH, EH> TranscodeConvertEngine<D, E, DH, EH>where
D: Codec,
E: Codec<Value = D::Value>,
DH: TranscodeDecodeHooks<D>,
EH: TranscodeEncodeHooks<E>,
Sourcepub fn new(decoder: D, encoder: E, decode_hooks: DH, encode_hooks: EH) -> Self
pub fn new(decoder: D, encoder: E, decode_hooks: DH, encode_hooks: EH) -> Self
Creates a buffered converter engine.
The caller supplies decode hooks and encode hooks directly.
§Parameters
decoder: Low-level codec used for source decoding.encoder: Low-level codec used for target encoding.decode_hooks: Decode-side policy hooks.encode_hooks: Encode-side policy hooks.
§Returns
Returns a buffered converter engine.
§Panics
In debug builds, panics when either codec violates the
Codec::MIN_UNITS_PER_VALUE / Codec::MAX_UNITS_PER_VALUE ordering
invariant. Release builds skip this check because the invariant is the
responsibility of each Codec implementation.
Sourcepub fn max_output_len(&self, input_len: usize) -> Result<usize, CapacityError>
pub fn max_output_len(&self, input_len: usize) -> Result<usize, CapacityError>
Returns an upper bound for target units produced from input_len units.
The bound sums three parts: any retained pending value, the maximum decoded values from the source side, and the maximum target units for those values on the encode side.
§Parameters
input_len: Number of source units the caller plans to convert.
§Returns
Returns a conservative upper bound, or a capacity error on arithmetic overflow.
Sourcepub fn max_reset_output_len(&self) -> Result<usize, CapacityError>
pub fn max_reset_output_len(&self) -> Result<usize, CapacityError>
Returns the maximum target units emitted when resetting stream state.
Covers decode-side reset values (encoded to target units) plus
encode-side reset units. Most codecs are stateless and return 0
for Codec::MAX_DECODE_RESET_VALUES; in that case this equals the
encode reset bound only.
§Returns
Returns the combined decode-reset and encode-reset output bound, or a capacity error on arithmetic overflow.
Sourcepub fn max_finish_output_len(&self) -> Result<usize, CapacityError>
pub fn max_finish_output_len(&self) -> Result<usize, CapacityError>
Returns the maximum target units emitted by finishing retained state.
The bound covers a retained pending value, decode-side finish values (encoded to target units), and encode-side finish units.
§Returns
Returns the combined pending, decode-finish, and encode-finish output bound, or a capacity error on arithmetic overflow.
Sourcepub fn transcode(
&mut self,
input: &[D::Unit],
input_index: usize,
output: &mut [E::Unit],
output_index: usize,
) -> Result<TranscodeProgress, TranscodeError<TranscodeConvertEngineError<TranscodeDecodeEngineError<<D as Codec>::DecodeError, <DH as TranscodeDecodeHooks<D>>::Error>, TranscodeEncodeEngineError<<E as Codec>::EncodeError, <EH as TranscodeEncodeHooks<E>>::Error>>>>
pub fn transcode( &mut self, input: &[D::Unit], input_index: usize, output: &mut [E::Unit], output_index: usize, ) -> Result<TranscodeProgress, TranscodeError<TranscodeConvertEngineError<TranscodeDecodeEngineError<<D as Codec>::DecodeError, <DH as TranscodeDecodeHooks<D>>::Error>, TranscodeEncodeEngineError<<E as Codec>::EncodeError, <EH as TranscodeEncodeHooks<E>>::Error>>>>
Converts source units into target units.
The engine drains any retained pending value before consuming new input. Each loop iteration decodes one source value and immediately attempts to encode it. Conversion stops when the input tail is incomplete, when the output buffer cannot hold the next encoded value, or when the visible input is exhausted.
§Parameters
input: Complete input unit slice visible to the converter.input_index: Absolute input index where conversion starts.output: Complete output unit slice visible to the converter.output_index: Absolute output index where writing starts.
§Returns
Returns conversion progress describing input units consumed, target units written, and why conversion stopped.
§Errors
Returns hook errors when indices are invalid or concrete conversion fails. Invalid output indices are reported through the encode-side error path.
Sourcepub fn finish(
&mut self,
output: &mut [E::Unit],
output_index: usize,
) -> Result<usize, TranscodeError<TranscodeConvertEngineError<TranscodeDecodeEngineError<<D as Codec>::DecodeError, <DH as TranscodeDecodeHooks<D>>::Error>, TranscodeEncodeEngineError<<E as Codec>::EncodeError, <EH as TranscodeEncodeHooks<E>>::Error>>>>
pub fn finish( &mut self, output: &mut [E::Unit], output_index: usize, ) -> Result<usize, TranscodeError<TranscodeConvertEngineError<TranscodeDecodeEngineError<<D as Codec>::DecodeError, <DH as TranscodeDecodeHooks<D>>::Error>, TranscodeEncodeEngineError<<E as Codec>::EncodeError, <EH as TranscodeEncodeHooks<E>>::Error>>>>
Finishes retained output after EOF.
Finalization drains a pending decoded value first, then lets the
source-side decode hooks emit final values, encodes those values through
the target-side encode hooks, and finally finishes target-side encode
hook state. The decode-finish value buffer used for this cold path
requires D::Value: Default; the normal Self::transcode loop does
not.
§Parameters
output: Complete output unit slice visible to the converter.output_index: Absolute output index where writing starts.
§Returns
Returns the number of target units written during finalization.
§Errors
Returns a converter error when output capacity checks fail or when hook finalization fails.
§Panics
Panics in debug builds when a retained pending value or decode-finish
value cannot be encoded within the capacity reserved by
Self::max_finish_output_len.
Sourcepub fn reset(
&mut self,
output: &mut [E::Unit],
output_index: usize,
) -> Result<usize, TranscodeError<TranscodeConvertEngineError<TranscodeDecodeEngineError<<D as Codec>::DecodeError, <DH as TranscodeDecodeHooks<D>>::Error>, TranscodeEncodeEngineError<<E as Codec>::EncodeError, <EH as TranscodeEncodeHooks<E>>::Error>>>>
pub fn reset( &mut self, output: &mut [E::Unit], output_index: usize, ) -> Result<usize, TranscodeError<TranscodeConvertEngineError<TranscodeDecodeEngineError<<D as Codec>::DecodeError, <DH as TranscodeDecodeHooks<D>>::Error>, TranscodeEncodeEngineError<<E as Codec>::EncodeError, <EH as TranscodeEncodeHooks<E>>::Error>>>>
Clears retained conversion state, runs before-reset hooks, and emits stream-start encode output.
Reset clears any retained pending value, drains decode-side reset
values through the target encoder, then emits encode-side reset units.
The caller must provide enough output capacity for
Self::max_reset_output_len.
§Parameters
output: Complete output unit slice visible to the converter.output_index: Absolute output index where writing starts.
§Returns
Returns the number of target units written while resetting stream state.
§Errors
Returns a converter error if reset validation or target reset output emission fails.
§Panics
Panics in debug builds when decode-reset values cannot be encoded
within the capacity reserved by Self::max_reset_output_len.
Trait Implementations§
Source§impl<D, E, DH, EH> Debug for TranscodeConvertEngine<D, E, DH, EH>
impl<D, E, DH, EH> Debug for TranscodeConvertEngine<D, E, DH, EH>
Source§impl<D, E, DH, EH> Default for TranscodeConvertEngine<D, E, DH, EH>where
D: Codec + Default,
E: Codec<Value = D::Value> + Default,
DH: TranscodeDecodeHooks<D> + Default,
EH: TranscodeEncodeHooks<E> + Default,
impl<D, E, DH, EH> Default for TranscodeConvertEngine<D, E, DH, EH>where
D: Codec + Default,
E: Codec<Value = D::Value> + Default,
DH: TranscodeDecodeHooks<D> + Default,
EH: TranscodeEncodeHooks<E> + Default,
Source§impl<D, E, DH, EH> Transcoder<<D as Codec>::Unit, <E as Codec>::Unit> for TranscodeConvertEngine<D, E, DH, EH>where
D: Codec,
E: Codec<Value = D::Value>,
D::Value: Default,
DH: TranscodeDecodeHooks<D>,
EH: TranscodeEncodeHooks<E>,
impl<D, E, DH, EH> Transcoder<<D as Codec>::Unit, <E as Codec>::Unit> for TranscodeConvertEngine<D, E, DH, EH>where
D: Codec,
E: Codec<Value = D::Value>,
D::Value: Default,
DH: TranscodeDecodeHooks<D>,
EH: TranscodeEncodeHooks<E>,
Source§fn max_output_len(&self, input_len: usize) -> Result<usize, CapacityError>
fn max_output_len(&self, input_len: usize) -> Result<usize, CapacityError>
Returns an upper bound for target units produced from input_len
units.
Source§fn max_finish_output_len(&self) -> Result<usize, CapacityError>
fn max_finish_output_len(&self) -> Result<usize, CapacityError>
Returns an upper bound for target units emitted by finishing retained state.
Source§fn max_reset_output_len(&self) -> Result<usize, CapacityError>
fn max_reset_output_len(&self) -> Result<usize, CapacityError>
Returns an upper bound for target units emitted when resetting stream state.
Source§fn reset(
&mut self,
output: &mut [E::Unit],
output_index: usize,
) -> Result<usize, TranscodeError<Self::Error>>
fn reset( &mut self, output: &mut [E::Unit], output_index: usize, ) -> Result<usize, TranscodeError<Self::Error>>
Clears retained conversion state and emits target reset output.
Source§fn transcode(
&mut self,
input: &[D::Unit],
input_index: usize,
output: &mut [E::Unit],
output_index: usize,
) -> Result<TranscodeProgress, TranscodeError<Self::Error>>
fn transcode( &mut self, input: &[D::Unit], input_index: usize, output: &mut [E::Unit], output_index: usize, ) -> Result<TranscodeProgress, TranscodeError<Self::Error>>
Converts source units into target units.
Source§fn finish(
&mut self,
output: &mut [E::Unit],
output_index: usize,
) -> Result<usize, TranscodeError<Self::Error>>
fn finish( &mut self, output: &mut [E::Unit], output_index: usize, ) -> Result<usize, TranscodeError<Self::Error>>
Finishes retained converter output after EOF.