qubit-codec 0.15.1

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.
// =============================================================================
//! Buffered decoder adapter backed by a low-level codec.

use super::super::engine::TranscodeDecodeEngine;
use super::CodecTranscodeDecodeHooks;
use crate::CapacityError;
use crate::Codec;
use crate::TranscodeDecodeErrorOf;
use crate::TranscodeDecoder;
use crate::TranscodeProgress;
use crate::Transcoder;

/// Decodes encoded units into caller-provided value buffers by using a
/// [`Codec`].
///
/// `CodecTranscodeDecoder` is a policy-free bridge from the low-level unchecked
/// [`Codec`] contract to [`Transcoder`] and [`TranscodeDecoder`]. It
/// leaves incomplete input tails in the caller-provided input slice while the
/// stream remains open. Call [`Transcoder::transcode_eof`] after upstream EOF
/// so codecs can apply their [`Codec::decode_eof`] policy to a trailing prefix.
///
/// # Type Parameters
///
/// - `C`: Low-level codec used to decode values.
///
/// # Examples
///
/// ```
/// use qubit_codec::{Codec, CodecTranscodeDecoder};
///
/// fn make_decoder<C: Codec>(codec: C) -> CodecTranscodeDecoder<C> {
///     CodecTranscodeDecoder::new(codec)
/// }
/// ```
#[derive(Debug, Default)]
pub struct CodecTranscodeDecoder<C> {
    /// Common buffered decoding engine.
    engine: TranscodeDecodeEngine<C, CodecTranscodeDecodeHooks>,
}

impl<C> CodecTranscodeDecoder<C>
where
    C: Codec,
{
    /// Creates a buffered decoder backed by `codec`.
    ///
    /// # Parameters
    ///
    /// - `codec`: Low-level codec used to decode values.
    ///
    /// # Returns
    ///
    /// Returns a buffered decoder adapter for the supplied codec.
    #[inline]
    #[must_use]
    pub fn new(codec: C) -> Self {
        Self {
            engine: TranscodeDecodeEngine::new(codec, CodecTranscodeDecodeHooks),
        }
    }

    /// Returns a shared reference to the wrapped codec.
    #[inline(always)]
    #[must_use]
    pub fn codec(&self) -> &C {
        self.engine.codec()
    }

    /// Returns a mutable reference to the wrapped codec.
    ///
    /// Mutating a codec during an active stream can invalidate that stream's
    /// assumptions; reset the adapter before continuing with the new codec
    /// configuration.
    #[inline(always)]
    #[must_use]
    pub fn codec_mut(&mut self) -> &mut C {
        self.engine.codec_mut()
    }

    /// Consumes the adapter and returns its wrapped codec.
    ///
    /// Any buffered lifecycle state and internal hooks are discarded.
    #[inline(always)]
    #[must_use]
    pub fn into_codec(self) -> C {
        self.engine.into_parts().0
    }
}

impl<C> Transcoder for CodecTranscodeDecoder<C>
where
    C: Codec,
{
    type Input = C::Unit;
    type Output = C::Value;
    type Error = TranscodeDecodeErrorOf<C>;

    /// Returns an upper bound for decoded values produced from `input_len`
    /// units.
    ///
    /// # Parameters
    ///
    /// - `input_len`: Source units the caller plans to decode.
    ///
    /// # Returns
    ///
    /// Returns a conservative upper bound for decoded values.
    #[inline(always)]
    fn max_transcode_output_len(&self, input_len: usize) -> Result<usize, CapacityError> {
        self.engine.max_transcode_output_len(input_len)
    }

    /// Returns the global maximum values emitted by finishing internal state.
    ///
    /// # Returns
    ///
    /// Returns the number of values that may still be emitted by finishing
    /// state.
    #[inline(always)]
    fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
        self.engine.max_finish_output_len()
    }

    /// Returns the global maximum values emitted when resetting internal state.
    #[inline(always)]
    fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
        self.engine.max_reset_output_len()
    }

    /// Runs before-reset cleanup for decoder state.
    #[inline(always)]
    fn reset(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
        self.engine.reset(output, output_index)
    }

    /// Decodes source units into logical values.
    ///
    /// # Parameters
    ///
    /// - `input`: Source unit slice.
    /// - `input_index`: Absolute source index where decoding starts.
    /// - `output`: Destination value slice.
    /// - `output_index`: Absolute output value index where writing starts.
    ///
    /// # Returns
    ///
    /// Returns conversion progress for consumed and written counters.
    ///
    /// # Errors
    ///
    /// Returns a decode error when indices are invalid or when conversion fails
    /// under hook policy.
    #[inline(always)]
    fn transcode(
        &mut self,
        input: &[C::Unit],
        input_index: usize,
        output: &mut [C::Value],
        output_index: usize,
    ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
        self.engine.transcode(input, input_index, output, output_index)
    }

    /// Transcodes an input segment while marking it as the end of the stream.
    ///
    /// This forwarding implementation lets the engine apply EOF-specific
    /// decoder behavior before returning progress to the caller.
    #[inline(always)]
    fn transcode_eof(
        &mut self,
        input: &[C::Unit],
        input_index: usize,
        output: &mut [C::Value],
        output_index: usize,
    ) -> Result<TranscodeProgress, TranscodeDecodeErrorOf<C>> {
        self.engine.transcode_eof(input, input_index, output, output_index)
    }

    /// Finishes internally retained output after EOF.
    ///
    /// # Parameters
    ///
    /// - `output`: Destination value slice for final retained values.
    /// - `output_index`: Absolute output value index where writing starts.
    ///
    /// # Returns
    ///
    /// Returns the number of values written by finalization.
    ///
    /// # Errors
    ///
    /// Returns a finish error if finalization cannot complete.
    #[inline(always)]
    fn finish(&mut self, output: &mut [C::Value], output_index: usize) -> Result<usize, TranscodeDecodeErrorOf<C>> {
        self.engine.finish(output, output_index)
    }
}

impl<C> TranscodeDecoder for CodecTranscodeDecoder<C>
where
    C: Codec,
{
    type DecodeError = C::DecodeError;
}