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§
Sourcefn handle_invalid_decode(
&mut self,
codec: &mut C,
error: &C::DecodeError,
consumed: Option<NonZeroUsize>,
context: DecodeContext,
) -> Result<DecodeInvalidAction<C::Value>, TranscodeDecodeErrorOf<C>>
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, orNonewhen 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.
§Errors
Returns crate::TranscodeDecodeError when the policy rejects the
input with a codec-domain error.
§Panics
The engine panics if a consuming action exceeds
context.available() input units.
Provided Methods§
Sourcefn max_transcode_output_len(
&self,
_codec: &C,
input_len: usize,
) -> Result<usize, CapacityError>
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 the streaming decode phase, including conservative
capacity preflight in streaming and EOF operations, as required by
crate::Transcoder::max_transcode_output_len. It describes required
writable capacity, not only values actually emitted. It must not include
codec reset values, codec finish values, or hook finish output.
Streaming actions can emit at most one value for the current input
event or skip it; an emitted replacement consumes a non-zero number of
source units. The hook API has no separate operation for draining
hook-owned output without processing input. Use a custom
crate::Transcoder for streaming behavior beyond this action model,
such as one-to-many output or draining output without new input. The
bound may depend on immutable hook and codec configuration, but must
cover every reachable transient hook and codec state.
The bound must cover the preflight required by
handle_invalid_decode and
handle_incomplete_decode, even when
the chosen action skips input and emits no value. Zero actual output
does not imply zero required writable capacity. See the
trait example for the hook action model.
The default implementation returns input_len, which remains
conservative when a replacement policy consumes fewer units than a
valid codec value. Override it when codec or hook policy can produce a
larger streaming output bound than this default.
§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.
Sourcefn max_finish_output_len(&self, _codec: &C) -> usize
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.
Sourcefn handle_incomplete_decode(
&mut self,
_codec: &mut C,
_source: Option<&C::DecodeError>,
_required_total: NonZeroUsize,
_context: DecodeContext,
) -> Result<DecodeIncompleteAction<C::Value>, TranscodeDecodeErrorOf<C>>
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
Some only when the codec returned an incomplete failure carrying a
source, such as through
crate::DecodeFailure::incomplete_with_source. It is None when
the available tail is shorter than Codec::MIN_UNITS_PER_VALUE
and the codec was not called, or when the codec was called but
returned crate::DecodeFailure::incomplete without a source.
§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. At confirmed EOF,
crate::engine::TranscodeDecodeEngine requires one writable value
slot before invoking this method, even when the eventual action is
Skip or Reject; a capacity shortage does not invoke the hook or
change its state. crate::engine::TranscodeConvertEngine may invoke
the hook without target capacity: Skip can consume the tail, while
Emit can retain a pending value for encoding. A retry drains that
pending value without invoking the hook again for the same tail.
§Errors
Returns crate::TranscodeDecodeError when policy evaluation fails.
Sourcefn reset_hooks(&mut self, _codec: &mut C)
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.
Sourcefn finish_hooks(
&mut self,
_codec: &mut C,
_output: &mut [C::Value],
_output_index: usize,
) -> Result<usize, TranscodeDecodeErrorOf<C>>
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".