qubit-codec 0.5.0

Core codec traits and buffer conversion primitives for Rust
Documentation
/*******************************************************************************
 *
 *    Copyright (c) 2026 Haixing Hu.
 *
 *    SPDX-License-Identifier: Apache-2.0
 *
 *    Licensed under the Apache License, Version 2.0.
 *
 ******************************************************************************/
//! Internal decode-step result used by buffered converters.

use core::num::NonZeroUsize;

use super::{
    convert_state::ConvertState,
    decode_state::DecodeState,
    pending_value::PendingValue,
    transcode_progress::TranscodeProgress,
};

/// Result of one decode step in the converter loop.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub(super) enum DecodeStep<Value> {
    /// A source value was decoded or emitted by policy.
    Decoded {
        /// Decoded logical value.
        value: Value,
        /// Number of consumed source units.
        consumed: NonZeroUsize,
        /// Source input index used for downstream encode context.
        input_index: usize,
    },
    /// Source input was consumed without producing a value.
    Skipped {
        /// Number of consumed source units.
        consumed: NonZeroUsize,
    },
    /// More source input is required before decoding can continue.
    NeedInput {
        /// Additional source units required to continue.
        additional: NonZeroUsize,
        /// Source units available at the incomplete boundary.
        available: usize,
    },
}

impl<Value> DecodeStep<Value> {
    /// Creates a decoded-value step.
    ///
    /// # Parameters
    ///
    /// - `value`: Decoded logical value.
    /// - `consumed`: Number of consumed source units.
    /// - `input_index`: Source index used for downstream encode context.
    ///
    /// # Returns
    ///
    /// Returns a decoded step.
    #[inline(always)]
    pub(super) const fn decoded(value: Value, consumed: NonZeroUsize, input_index: usize) -> Self {
        Self::Decoded {
            value,
            consumed,
            input_index,
        }
    }

    /// Creates a skipped-input step.
    ///
    /// # Parameters
    ///
    /// - `consumed`: Number of consumed source units.
    ///
    /// # Returns
    ///
    /// Returns a skipped step.
    #[inline(always)]
    pub(super) const fn skipped(consumed: NonZeroUsize) -> Self {
        Self::Skipped { consumed }
    }

    /// Creates a missing-input step.
    ///
    /// # Parameters
    ///
    /// - `additional`: Additional source units required to continue.
    /// - `available`: Source units currently available.
    ///
    /// # Returns
    ///
    /// Returns a need-input step.
    #[inline(always)]
    pub(super) const fn need_input(additional: NonZeroUsize, available: usize) -> Self {
        Self::NeedInput { additional, available }
    }

    /// Applies this decode step to the current conversion state.
    ///
    /// For each variant:
    ///
    /// - `Decoded`: advances input cursor and passes the decoded value into the
    ///   converter encode path.
    /// - `Skipped`: only advances input cursor.
    /// - `NeedInput`: returns [`TranscodeProgress`] requesting additional input.
    ///
    /// # Parameters
    ///
    /// - `state`: Current conversion-call state.
    /// - `encode`: Callback to emit a decoded value into the shared convert
    ///   state.
    ///
    /// # Type Parameters
    ///
    /// - `Input`: Input-unit type stored in the active [`ConvertState`].
    /// - `Output`: Output-unit type stored in the active [`ConvertState`].
    /// - `Error`: Error type produced by the encode callback.
    /// - `F`: Callback type that consumes a decoded value and updates state.
    ///
    /// # Returns
    ///
    /// Returns:
    /// - `Ok(Some(progress))` when conversion must stop,
    /// - `Ok(None)` when conversion can continue, or
    /// - `Err(error)` when emitting the decoded value fails.
    #[inline]
    pub(super) fn apply_to_convert_state<Input, Output, Error, F>(
        self,
        state: &mut ConvertState<'_, Input, Output>,
        mut encode: F,
    ) -> Result<Option<TranscodeProgress>, Error>
    where
        F: FnMut(PendingValue<Value>, &mut ConvertState<'_, Input, Output>) -> Result<Option<TranscodeProgress>, Error>,
    {
        match self {
            Self::Decoded {
                value,
                consumed,
                input_index,
            } => {
                state.advance_input(consumed.get());
                encode(PendingValue::new(value, input_index), state)
            }
            Self::Skipped { consumed } => {
                state.advance_input(consumed.get());
                Ok(None)
            }
            Self::NeedInput { additional, available } => Ok(Some(state.need_input_progress(additional, available))),
        }
    }

    /// Applies this decode step to the current decode state.
    ///
    /// # Parameters
    ///
    /// - `state`: Current decode-call state.
    ///
    /// # Type Parameters
    ///
    /// - `Unit`: Decode input-unit type represented by this [`DecodeState`].
    ///
    /// # Returns
    ///
    /// Returns optional public stop progress when decoding cannot continue in this
    /// call.
    #[must_use]
    #[inline]
    pub(super) fn apply_to_decode_state<Unit>(
        self,
        state: &mut DecodeState<'_, Unit, Value>,
    ) -> Option<TranscodeProgress> {
        match self {
            Self::Decoded { value, consumed, .. } => {
                if state.needs_output() {
                    return Some(state.need_output_progress());
                }
                state.emit(value, consumed);
                None
            }
            Self::Skipped { consumed } => {
                state.skip(consumed);
                None
            }
            Self::NeedInput { additional, available } => Some(state.need_input_progress_with(additional, available)),
        }
    }
}