1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*******************************************************************************
*
* Copyright (c) 2026 Haixing Hu.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0.
*
******************************************************************************/
//! Mutable state for one buffered decode call.
use core::num::NonZeroUsize;
use super::{
decode_context::DecodeContext,
transcode_progress::TranscodeProgress,
};
/// Mutable state for one buffered decode call.
pub(super) struct DecodeState<'a, Unit, Value> {
/// Complete input unit slice visible to the decoder.
input: &'a [Unit],
/// Absolute source index where this call starts.
input_start: usize,
/// Complete output value slice visible to the decoder.
output: &'a mut [Value],
/// Absolute output index where this call starts.
output_start: usize,
/// Absolute source index for the next decode attempt.
input_cursor: usize,
/// Absolute output index for the next emitted value.
output_cursor: usize,
}
impl<'a, Unit, Value> DecodeState<'a, Unit, Value> {
/// Creates mutable decode state.
///
/// # Parameters
///
/// - `input`: Complete input unit slice visible to the decoder.
/// - `input_index`: Absolute source index where decoding starts.
/// - `output`: Complete output value slice visible to the decoder.
/// - `output_index`: Absolute output index where writing starts.
///
/// # Returns
///
/// Returns initialized decode state with cursors at the requested start
/// positions.
#[inline(always)]
pub(super) fn new(input: &'a [Unit], input_index: usize, output: &'a mut [Value], output_index: usize) -> Self {
debug_assert!(input_index <= input.len(), "input index must be within the input slice");
Self {
input,
input_start: input_index,
output,
output_start: output_index,
input_cursor: input_index,
output_cursor: output_index,
}
}
/// Returns the complete input slice.
///
/// # Returns
///
/// Returns the full input slice visible to this decode call.
#[inline(always)]
pub(super) fn input(&self) -> &[Unit] {
self.input
}
/// Returns whether there is still input to decode.
///
/// # Returns
///
/// Returns `true` when there are input units remaining.
#[inline(always)]
pub(super) fn has_input(&self) -> bool {
self.input_cursor < self.input.len()
}
/// Returns whether the output slice has no slot for the next value.
///
/// # Returns
///
/// Returns `true` when no output slot remains for the next value.
#[inline(always)]
pub(super) fn needs_output(&self) -> bool {
self.output_cursor == self.output.len()
}
/// Returns input units visible from the current input cursor.
#[inline(always)]
fn available(&self) -> usize {
self.input.len() - self.input_cursor
}
/// Returns a public decode context snapshot.
///
/// # Returns
///
/// Returns the current [`DecodeContext`].
#[inline(always)]
pub(super) fn context(&self) -> DecodeContext {
DecodeContext::new(
self.input_start,
self.input_cursor,
self.output_start,
self.output_cursor,
self.available(),
)
}
/// Advances the input cursor without emitting output.
///
/// # Parameters
///
/// - `consumed`: Input units consumed by the current operation.
///
/// # Returns
///
/// Returns unit `()`.
#[inline(always)]
pub(super) fn skip(&mut self, consumed: NonZeroUsize) {
let consumed = consumed.get();
assert!(
consumed <= self.available(),
"decode step consumed beyond available input",
);
self.input_cursor += consumed;
}
/// Emits a decoded value and advances both cursors.
///
/// # Parameters
///
/// - `value`: Decoded value to write to output.
/// - `consumed`: Input units consumed by this decode step.
///
/// # Returns
///
/// Returns unit `()`.
#[inline(always)]
pub(super) fn emit(&mut self, value: Value, consumed: NonZeroUsize) {
let consumed = consumed.get();
assert!(
consumed <= self.available(),
"decode step consumed beyond available input",
);
assert!(!self.needs_output(), "decode step emitted without output capacity",);
// SAFETY: `needs_output()` returned false, so the output cursor points
// at a writable slot.
unsafe {
*self.output.get_unchecked_mut(self.output_cursor) = value;
}
self.input_cursor += consumed;
self.output_cursor += 1;
}
/// Returns completed progress for the current cursors.
///
/// # Returns
///
/// Returns a completed [`TranscodeProgress`].
#[inline(always)]
pub(super) fn complete_progress(&self) -> TranscodeProgress {
TranscodeProgress::complete(
self.input_cursor - self.input_start,
self.output_cursor - self.output_start,
)
}
/// Returns progress for a missing output slot.
///
/// # Returns
///
/// Returns progress with [`TranscodeStatus::NeedOutput`].
#[inline(always)]
pub(super) fn need_output_progress(&self) -> TranscodeProgress {
let context = self.context();
TranscodeProgress::need_output(
context.output_index,
NonZeroUsize::MIN,
0,
self.input_cursor - self.input_start,
self.output_cursor - self.output_start,
)
}
/// Returns progress for a policy-selected need-input stop.
///
/// # Parameters
///
/// - `additional`: Additional source units required to continue.
/// - `available`: Source units visible at the stop boundary.
///
/// # Returns
///
/// Returns progress at the current decode cursor.
#[inline(always)]
pub(super) fn need_input_progress_with(&self, additional: NonZeroUsize, available: usize) -> TranscodeProgress {
TranscodeProgress::need_input(
self.input_cursor,
additional,
available,
self.input_cursor - self.input_start,
self.output_cursor - self.output_start,
)
}
}