Skip to main content

qubit_codec/transcode/engine/
decode_invalid_action.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Invalid-decode actions returned by buffered decoder policy hooks.
9
10use core::num::NonZeroUsize;
11
12use crate::Codec;
13
14/// Invalid-decode action for a codec-backed decode hook.
15pub type DecodeInvalidActionOf<C> = DecodeInvalidAction<<C as Codec>::Value>;
16
17/// Action selected after a codec reports invalid encoded input.
18///
19/// Incomplete input is not a policy action. Codecs report it with
20/// [`crate::DecodeFailure::Incomplete`], and the decode engine converts it
21/// directly into [`crate::TranscodeStatus::NeedInput`].
22///
23/// # Type Parameters
24///
25/// - `Value`: Decoded output value type.
26#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
27#[non_exhaustive]
28pub enum DecodeInvalidAction<Value> {
29    /// Reject the current invalid input.
30    ///
31    /// The decode engine reports the original codec decode error as
32    /// [`crate::TranscodeDecodeError::Domain`] at the current input index.
33    Reject,
34
35    /// Consume invalid input without producing output.
36    ///
37    /// `consumed` must not exceed the hook context's available input count.
38    /// Over-consuming is a hook contract violation and panics in the engine.
39    Skip {
40        /// Source units to consume.
41        consumed: NonZeroUsize,
42    },
43
44    /// Produce one replacement value and consume source units.
45    ///
46    /// `consumed` must not exceed the hook context's available input count.
47    /// Over-consuming is a hook contract violation and panics in the engine.
48    Emit {
49        /// Value to write to the output buffer.
50        value: Value,
51        /// Source units to consume.
52        consumed: NonZeroUsize,
53    },
54}
55
56impl<Value> DecodeInvalidAction<Value> {
57    /// Validates a policy-reported consumed source-unit count against available
58    /// input.
59    ///
60    /// # Parameters
61    ///
62    /// - `consumed`: Source units requested by the concrete policy.
63    /// - `available`: Source units visible from the current decode cursor.
64    ///
65    /// # Returns
66    ///
67    /// Returns the validated non-zero consumed count.
68    ///
69    /// # Panics
70    ///
71    /// Panics when `available == 0` or when `consumed > available`.
72    #[inline(always)]
73    #[must_use]
74    pub(super) fn bound_consumed(
75        consumed: NonZeroUsize,
76        available: usize,
77    ) -> NonZeroUsize {
78        assert!(
79            available > 0,
80            "DecodeInvalidAction cannot consume empty input",
81        );
82        assert!(
83            consumed.get() <= available,
84            "DecodeInvalidAction consumed units must not exceed available input",
85        );
86        consumed
87    }
88}