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
/*******************************************************************************
*
* Copyright (c) 2026 Haixing Hu.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0.
*
******************************************************************************/
//! Error reported while finishing buffered output.
use thiserror::Error;
use super::capacity_error::CapacityError;
/// Error reported by one-shot buffered finalization.
///
/// `finish` methods require enough output capacity to write all final output in
/// one call. This type separates caller capacity mistakes from semantic errors
/// reported by the concrete codec or hook policy.
#[derive(Clone, Copy, Debug, Eq, Error, Hash, PartialEq)]
pub enum FinishError<E> {
/// Finish-output bound arithmetic overflowed.
#[error("finish output capacity planning failed: {source}")]
Capacity {
/// Capacity planning error.
#[source]
source: CapacityError,
},
/// The caller supplied an output index outside the output slice.
#[error("invalid finish output index {index} for output length {len}")]
InvalidOutputIndex {
/// Invalid output index supplied by the caller.
index: usize,
/// Length of the output slice.
len: usize,
},
/// The output slice cannot hold all final output.
#[error("insufficient finish output at index {output_index}: required {required} units, available {available}")]
InsufficientOutput {
/// Absolute output index where finalization would start writing.
output_index: usize,
/// Output units required to finish in one call.
required: usize,
/// Output units available from `output_index`.
available: usize,
},
/// The underlying codec or hook policy rejected finalization.
#[error("finish failed: {source}")]
Source {
/// Error returned by the concrete codec or hook policy.
#[source]
source: E,
},
}
impl<E> FinishError<E> {
/// Creates a finish error from capacity planning failure.
///
/// # Parameters
///
/// - `source`: Capacity planning error reported while computing the finish bound.
///
/// # Returns
///
/// Returns a finish error wrapping `source`.
#[must_use]
#[inline(always)]
pub const fn capacity(source: CapacityError) -> Self {
Self::Capacity { source }
}
/// Creates an invalid-output-index finish error.
///
/// # Parameters
///
/// - `index`: Output index supplied by the caller.
/// - `len`: Length of the output slice.
///
/// # Returns
///
/// Returns an invalid-output-index finish error.
#[must_use]
#[inline(always)]
pub const fn invalid_output_index(index: usize, len: usize) -> Self {
Self::InvalidOutputIndex { index, len }
}
/// Creates an insufficient-output finish error.
///
/// # Parameters
///
/// - `output_index`: Output index supplied by the caller.
/// - `required`: Output units required to finish in one call.
/// - `available`: Output units available from `output_index`.
///
/// # Returns
///
/// Returns an insufficient-output finish error.
#[must_use]
#[inline(always)]
pub const fn insufficient_output(output_index: usize, required: usize, available: usize) -> Self {
Self::InsufficientOutput {
output_index,
required,
available,
}
}
/// Creates a finish error from an underlying semantic error.
///
/// # Parameters
///
/// - `source`: Error returned by the concrete codec or hook policy.
///
/// # Returns
///
/// Returns a finish error wrapping `source`.
#[must_use]
#[inline(always)]
pub const fn source(source: E) -> Self {
Self::Source { source }
}
/// Maps the underlying semantic error while preserving capacity failures.
///
/// # Type Parameters
///
/// - `T`: Target semantic error type.
/// - `F`: Mapping function type.
///
/// # Parameters
///
/// - `map`: Function used to map the underlying semantic error.
///
/// # Returns
///
/// Returns a finish error with the mapped semantic error type.
#[inline]
pub fn map_source<T, F>(self, map: F) -> FinishError<T>
where
F: FnOnce(E) -> T,
{
match self {
Self::Capacity { source } => FinishError::Capacity { source },
Self::InvalidOutputIndex { index, len } => FinishError::InvalidOutputIndex { index, len },
Self::InsufficientOutput {
output_index,
required,
available,
} => FinishError::InsufficientOutput {
output_index,
required,
available,
},
Self::Source { source } => FinishError::Source { source: map(source) },
}
}
/// Validates that an output slice can hold one-shot final output.
///
/// # Parameters
///
/// - `output_len`: Length of the output slice.
/// - `output_index`: Output index supplied by the caller.
/// - `required`: Output units required to finish in one call.
///
/// # Returns
///
/// Returns `Ok(())` when output capacity is sufficient.
///
/// # Errors
///
/// Returns [`FinishError::InvalidOutputIndex`] when `output_index` is beyond
/// the slice, or [`FinishError::InsufficientOutput`] when fewer than
/// `required` units are writable from `output_index`.
#[inline]
pub fn ensure_output_capacity(output_len: usize, output_index: usize, required: usize) -> Result<(), Self> {
if output_index > output_len {
return Err(Self::invalid_output_index(output_index, output_len));
}
let available = output_len - output_index;
if available < required {
return Err(Self::insufficient_output(output_index, required, available));
}
Ok(())
}
}