Skip to main content

qubit_codec/transcode/engine/
decode_context.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//! Decode context passed to buffered decoder policy hooks.
9
10/// Context for one codec decode attempt inside a buffered decoder engine.
11///
12/// Input positions are source-unit indexes. Output positions use the driving
13/// engine's output domain: decoded values for [`TranscodeDecodeEngine`], and
14/// target encoding units for [`TranscodeConvertEngine`]. `output_written` is
15/// relative to the current call and does not count intermediate decoded
16/// values in a converter.
17///
18/// [`TranscodeDecodeEngine`]: crate::engine::TranscodeDecodeEngine
19/// [`TranscodeConvertEngine`]: crate::engine::TranscodeConvertEngine
20///
21/// # Examples
22///
23/// ```
24/// use qubit_codec::engine::DecodeContext;
25///
26/// let context = DecodeContext::new(0, 0, 0, 0, 2);
27/// assert_eq!(context.available(), 2);
28/// ```
29#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
30pub struct DecodeContext {
31    /// Absolute source index where this `transcode` call starts.
32    input_start: usize,
33    /// Absolute source index where the attempted value starts.
34    input_index: usize,
35    /// Absolute output index where this call starts, in the driving engine's
36    /// output domain.
37    output_start: usize,
38    /// Absolute output index where the next output would be written, in the
39    /// driving engine's output domain.
40    output_index: usize,
41    /// Units visible to the codec from `input_index`.
42    available: usize,
43}
44
45impl DecodeContext {
46    /// Creates a decode context.
47    ///
48    /// # Parameters
49    ///
50    /// - `input_start`: Absolute source index where this `transcode` call
51    ///   starts.
52    /// - `input_index`: Absolute source index where the attempted value starts.
53    /// - `output_start`: Absolute output index where this call starts, in the
54    ///   driving engine's output domain.
55    /// - `output_index`: Absolute output index where the next output would be
56    ///   written, in the driving engine's output domain.
57    /// - `available`: Units visible to the codec from `input_index`.
58    ///
59    /// # Returns
60    ///
61    /// Returns a decode context.
62    ///
63    /// # Panics
64    ///
65    /// Panics when `input_index < input_start` or
66    /// `output_index < output_start`.
67    #[inline]
68    #[must_use]
69    pub const fn new(
70        input_start: usize,
71        input_index: usize,
72        output_start: usize,
73        output_index: usize,
74        available: usize,
75    ) -> Self {
76        assert!(
77            input_start <= input_index,
78            "decode context input index must not precede input start",
79        );
80        assert!(
81            output_start <= output_index,
82            "decode context output index must not precede output start",
83        );
84        Self {
85            input_start,
86            input_index,
87            output_start,
88            output_index,
89            available,
90        }
91    }
92
93    /// Returns the absolute source index where this `transcode` call starts.
94    ///
95    /// # Returns
96    ///
97    /// Returns the input start index.
98    #[inline]
99    #[must_use]
100    pub const fn input_start(self) -> usize {
101        self.input_start
102    }
103
104    /// Returns the absolute source index where the attempted value starts.
105    ///
106    /// # Returns
107    ///
108    /// Returns the current input index.
109    #[inline]
110    #[must_use]
111    pub const fn input_index(self) -> usize {
112        self.input_index
113    }
114
115    /// Returns the absolute output index where this call starts, in the
116    /// driving engine's output domain.
117    ///
118    /// # Returns
119    ///
120    /// Returns the output start index.
121    #[inline]
122    #[must_use]
123    pub const fn output_start(self) -> usize {
124        self.output_start
125    }
126
127    /// Returns the absolute output index where the next output would be
128    /// written, in the driving engine's output domain.
129    ///
130    /// # Returns
131    ///
132    /// Returns the current output index.
133    #[inline]
134    #[must_use]
135    pub const fn output_index(self) -> usize {
136        self.output_index
137    }
138
139    /// Returns units visible to the codec from [`Self::input_index`].
140    ///
141    /// # Returns
142    ///
143    /// Returns the available input-unit count.
144    #[inline]
145    #[must_use]
146    pub const fn available(self) -> usize {
147        self.available
148    }
149
150    /// Returns input units consumed since this `transcode` call started.
151    ///
152    /// # Returns
153    ///
154    /// Returns `input_index - input_start`.
155    #[inline]
156    #[must_use]
157    pub const fn input_used(self) -> usize {
158        self.input_index - self.input_start
159    }
160
161    /// Returns output written since this call started, in the driving
162    /// engine's output domain. For a converter, this counts target encoding
163    /// units rather than intermediate decoded values.
164    ///
165    /// # Returns
166    ///
167    /// Returns `output_index - output_start`.
168    #[inline]
169    #[must_use]
170    pub const fn output_written(self) -> usize {
171        self.output_index - self.output_start
172    }
173}