Skip to main content

TranscodeDecodeHooks

Trait TranscodeDecodeHooks 

Source
pub trait TranscodeDecodeHooks<C>
where C: Codec,
{ // Required method fn handle_invalid_decode( &mut self, codec: &mut C, error: &C::DecodeError, consumed: Option<NonZeroUsize>, context: DecodeContext, ) -> Result<DecodeInvalidAction<C::Value>, TranscodeDecodeErrorOf<C>>; // Provided methods fn max_transcode_output_len( &self, _codec: &C, input_len: usize, ) -> Result<usize, CapacityError> { ... } fn max_finish_output_len(&self, _codec: &C) -> usize { ... } fn handle_incomplete_decode( &mut self, _codec: &mut C, _source: Option<&C::DecodeError>, _required_total: NonZeroUsize, _context: DecodeContext, ) -> Result<DecodeIncompleteAction<C::Value>, TranscodeDecodeErrorOf<C>> { ... } fn reset_hooks(&mut self, _codec: &mut C) { ... } fn finish_hooks( &mut self, _codec: &mut C, _output: &mut [C::Value], _output_index: usize, ) -> Result<usize, TranscodeDecodeErrorOf<C>> { ... } }
Expand description

Policy hooks for crate::engine::TranscodeDecodeEngine.

Hooks own policy state, such as malformed-input replacement behavior. The engine passes the codec into hook methods when policy code needs codec metadata.

Implement this trait when a buffered decoder needs policy decisions after the low-level codec reports an error. The engine handles input/output cursor bookkeeping, output-capacity checks, and successful one-value decodes; hooks decide whether invalid or EOF-incomplete input should be skipped, replaced, or returned as an error.

The hook receives a DecodeContext with absolute input/output cursors, so errors can include useful positions without duplicating engine arithmetic. Stateful hooks may also use finish_hooks to emit final values after the caller has supplied all input and completed EOF decoding.

§Examples

This hook replaces malformed units with b'?' and otherwise lets the engine keep decoding. At EOF, implementations may also override Self::handle_incomplete_decode to repair or discard a trailing partial value.

use core::convert::Infallible;
use core::num::NonZeroUsize;

use qubit_codec::Codec;
use qubit_codec::DecodeFailure;
use qubit_codec::TranscodeDecodeError;
use qubit_codec::engine::DecodeContext;
use qubit_codec::engine::DecodeInvalidAction;
use qubit_codec::engine::TranscodeDecodeHooks;

#[derive(Clone, Copy)]
struct MyCodec;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum MyDecodeError {
    Malformed { consumed: NonZeroUsize },
}

impl Codec for MyCodec {
    type Value = u8;
    type Unit = u8;
    type DecodeError = MyDecodeError;
    type EncodeError = Infallible;

    const MIN_UNITS_PER_VALUE: usize = 1;
    const MAX_ENCODE_UNITS_PER_VALUE: usize = 1;
    const MAX_DECODE_UNITS_PER_VALUE: usize = 1;

    unsafe fn decode(
        &mut self,
        input: &[u8],
        index: usize,
    ) -> Result<(u8, NonZeroUsize), DecodeFailure<Self::DecodeError>> {
        match input[index] {
            0xff => Err(DecodeFailure::invalid(
                MyDecodeError::Malformed {
                    consumed: NonZeroUsize::MIN,
                },
                NonZeroUsize::MIN,
            )),
            value => Ok((value, NonZeroUsize::MIN)),
        }
    }

    unsafe fn encode(
        &mut self,
        value: &u8,
        output: &mut [u8],
        index: usize,
    ) -> Result<usize, Self::EncodeError> {
        output[index] = *value;
        Ok(1)
    }
}

#[derive(Default)]
struct ReplacementHooks;

impl TranscodeDecodeHooks<MyCodec> for ReplacementHooks {
    fn handle_invalid_decode(
        &mut self,
        _codec: &mut MyCodec,
        error: &MyDecodeError,
        consumed: Option<NonZeroUsize>,
        _context: DecodeContext,
    ) -> Result<DecodeInvalidAction<u8>, TranscodeDecodeError<MyDecodeError>> {
        match error {
            MyDecodeError::Malformed { .. } => {
                Ok(DecodeInvalidAction::Emit {
                    value: b'?',
                    consumed: consumed.expect("codec reported malformed width"),
                })
            }
        }
    }
}

let mut hooks = ReplacementHooks::default();
let mut codec = MyCodec;
let context = DecodeContext::new(0, 0, 0, 0, 1);
let error = MyDecodeError::Malformed { consumed: NonZeroUsize::MIN };
let action = hooks.handle_invalid_decode(
    &mut codec, &error, Some(NonZeroUsize::MIN), context,
).expect("replacement policy accepts malformed input");
assert!(matches!(action, DecodeInvalidAction::Emit { value: b'?', consumed }
    if consumed == NonZeroUsize::MIN));

§Type Parameters

  • C: Low-level codec owned by the engine.

Required Methods§

Source

fn handle_invalid_decode( &mut self, codec: &mut C, error: &C::DecodeError, consumed: Option<NonZeroUsize>, context: DecodeContext, ) -> Result<DecodeInvalidAction<C::Value>, TranscodeDecodeErrorOf<C>>

Handles a codec-domain invalid decode error during transcode.

§Parameters
  • codec: Low-level codec owned by the engine.
  • error: Invalid domain error returned by the codec.
  • consumed: Known invalid input units that may be consumed by non-strict policies, or None when the codec cannot state an invalid span length.
  • context: Decode attempt context.
§Returns

Returns the action selected by this hook policy.

Returned consuming actions must not consume more than context.available() input units.

The engine treats violations as hook bugs and panics.

§Errors

Returns crate::TranscodeDecodeError when the policy rejects the input with a codec-domain error.

Provided Methods§

Source

fn max_transcode_output_len( &self, _codec: &C, input_len: usize, ) -> Result<usize, CapacityError>

Returns an upper bound for decoded values produced from input_len units.

This bound covers only the streaming decode phase. It must not include codec reset values, codec finish values, or hook finish output. It may depend on immutable hook and codec configuration, but it must cover every reachable transient hook and codec state, including the maximum hook-owned pending output that may be drained during transcode.

The default implementation returns input_len, which remains conservative when a replacement policy consumes fewer units than a valid codec value. Override it when hook policy can emit more than one value per source unit or when hook-owned pending output can be drained during transcode.

§Parameters
  • codec: Low-level codec owned by the engine.
  • input_len: Number of source units the caller plans to decode.
§Returns

Returns a conservative upper bound for streaming output.

§Errors

Returns CapacityError::OutputLengthOverflow when the bound cannot be represented as usize.

Source

fn max_finish_output_len(&self, _codec: &C) -> usize

Returns an upper bound for values emitted by finishing hook-owned state.

finish never receives more input. Implementations must report the maximum output that could be derived from hook-owned state in any reachable transient stream state, not only what happens to remain when this method is called.

The default implementation returns 0. Override it when finish_hooks can write trailers, delayed replacements, or any other hook-owned final output. Do not include Codec::MAX_DECODE_FINISH_VALUES; the engine adds the codec finish bound separately.

§Parameters
  • codec: Low-level codec owned by the engine.
§Returns

Returns the finite, transient-state-independent final-output upper bound.

Source

fn handle_incomplete_decode( &mut self, _codec: &mut C, _source: Option<&C::DecodeError>, _required_total: NonZeroUsize, _context: DecodeContext, ) -> Result<DecodeIncompleteAction<C::Value>, TranscodeDecodeErrorOf<C>>

Handles a codec value left incomplete after end of input.

The engine calls this method only from transcode_eof. source is the codec-domain context attached to crate::DecodeFailure::Incomplete, or None when the engine stopped before calling the codec because the available tail is shorter than Codec::MIN_UNITS_PER_VALUE.

§Parameters
  • codec: Low-level codec owned by the engine.
  • source: Optional domain error explaining the incomplete tail.
  • required_total: Minimum source units required to retry decoding.
  • context: Decode attempt context.
§Returns

Returns the EOF policy action. Skip and Emit consume every source unit available in context; Emit additionally requires one writable output slot.

§Errors

Returns crate::TranscodeDecodeError when policy evaluation fails.

Source

fn reset_hooks(&mut self, _codec: &mut C)

Runs hook-owned cleanup as part of stream reset.

Called before Codec::decode_reset writes its own reset output. Stateless hooks may use the default no-op.

§Parameters
  • codec: Low-level codec owned by the engine.
Source

fn finish_hooks( &mut self, _codec: &mut C, _output: &mut [C::Value], _output_index: usize, ) -> Result<usize, TranscodeDecodeErrorOf<C>>

Finishes hook-owned state and writes any retained output.

The default implementation is a no-op for stateless decode hooks. Stateful hooks may emit final values such as checksums, reset markers, or other trailer data. The caller must provide at least TranscodeDecodeHooks::max_finish_output_len writable slots from output_index. Implementations must not write beyond that declared final-output bound.

Called after Codec::decode_finish has written its own finish output.

§Parameters
  • codec: Low-level codec owned by the engine.
  • output: Output value slice visible to the hook.
  • output_index: Absolute output value index where writing starts.
§Returns

Returns the number of values written by finalization. This count must not exceed TranscodeDecodeHooks::max_finish_output_len.

§Errors

Returns a transcode decode error when hook-owned state cannot be finalized.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§