Skip to main content

TranscodeConvertEngine

Struct TranscodeConvertEngine 

Source
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>,

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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>>>>
where D::Value: Default,

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.

Source

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>>>>
where D::Value: Default,

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>
where D: Codec + Debug, E: Codec<Value = D::Value> + Debug, DH: TranscodeDecodeHooks<D> + Debug, EH: TranscodeEncodeHooks<E> + Debug, D::Value: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
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,

Source§

fn default() -> Self

Creates a default buffered converter engine.

§Returns

Returns a converter engine constructed from default codecs and hooks.

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>,

Source§

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>

Returns an upper bound for target units emitted by finishing retained state.

Source§

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>>

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>>

Converts source units into target units.

Source§

fn finish( &mut self, output: &mut [E::Unit], output_index: usize, ) -> Result<usize, TranscodeError<Self::Error>>

Finishes retained converter output after EOF.

Source§

type Error = TranscodeConvertEngineError<TranscodeDecodeEngineError<<D as Codec>::DecodeError, <DH as TranscodeDecodeHooks<D>>::Error>, TranscodeEncodeEngineError<<E as Codec>::EncodeError, <EH as TranscodeEncodeHooks<E>>::Error>>

Domain error reported by semantic conversion failures.

Auto Trait Implementations§

§

impl<D, E, DH, EH> Freeze for TranscodeConvertEngine<D, E, DH, EH>
where D: Freeze, DH: Freeze, E: Freeze, EH: Freeze, <D as Codec>::Value: Freeze,

§

impl<D, E, DH, EH> RefUnwindSafe for TranscodeConvertEngine<D, E, DH, EH>

§

impl<D, E, DH, EH> Send for TranscodeConvertEngine<D, E, DH, EH>
where D: Send, DH: Send, E: Send, EH: Send, <D as Codec>::Value: Send,

§

impl<D, E, DH, EH> Sync for TranscodeConvertEngine<D, E, DH, EH>
where D: Sync, DH: Sync, E: Sync, EH: Sync, <D as Codec>::Value: Sync,

§

impl<D, E, DH, EH> Unpin for TranscodeConvertEngine<D, E, DH, EH>
where D: Unpin, DH: Unpin, E: Unpin, EH: Unpin, <D as Codec>::Value: Unpin,

§

impl<D, E, DH, EH> UnsafeUnpin for TranscodeConvertEngine<D, E, DH, EH>

§

impl<D, E, DH, EH> UnwindSafe for TranscodeConvertEngine<D, E, DH, EH>
where D: UnwindSafe, DH: UnwindSafe, E: UnwindSafe, EH: UnwindSafe, <D as Codec>::Value: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.