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}