1#[cfg(feature = "cuda-runtime")]
6use super::Arc;
7use super::{
8 BatchGroupInfo, BatchInfrastructureError, Error, IndexedBatchError, J2kDecodeWarning,
9 PreparedBatchGroup, Rect, Surface,
10};
11use crate::CudaHtj2kProfileReport;
12
13#[derive(Debug, thiserror::Error)]
15#[non_exhaustive]
16pub enum CudaBatchError {
17 #[error(transparent)]
19 Infrastructure(#[from] BatchInfrastructureError),
20 #[error("CUDA batch group containing source indices {source_indices:?} failed: {source}")]
24 GroupExecution {
25 source_indices: Vec<usize>,
27 #[source]
29 source: Box<Error>,
30 },
31}
32
33impl CudaBatchError {
34 #[allow(
35 clippy::disallowed_methods,
36 reason = "error construction preserves its infallible public signature while retaining affected source indices"
37 )]
38 pub(super) fn group(group: &PreparedBatchGroup, source: impl Into<Error>) -> Self {
39 Self::GroupExecution {
40 source_indices: group.source_indices().to_vec(),
41 source: Box::new(source.into()),
42 }
43 }
44
45 #[cfg(feature = "cuda-runtime")]
48 #[doc(hidden)]
49 pub fn completion_is_uncertain(&self) -> bool {
50 match self {
51 Self::GroupExecution { source, .. } => source.completion_is_uncertain(),
52 Self::Infrastructure(_) => false,
53 }
54 }
55
56 #[doc(hidden)]
59 #[must_use]
60 pub fn session_is_unusable(&self) -> bool {
61 match self {
62 Self::Infrastructure(_) => true,
63 Self::GroupExecution { source, .. } => source.session_is_unusable(),
64 }
65 }
66}
67
68#[cfg(test)]
69mod classification_tests {
70 use j2k_core::BatchInfrastructureError;
71
72 use super::CudaBatchError;
73 use crate::Error;
74
75 fn group_error(source: Error) -> CudaBatchError {
76 CudaBatchError::GroupExecution {
77 source_indices: vec![3],
78 source: Box::new(source),
79 }
80 }
81
82 #[test]
83 fn cuda_batch_session_classification_is_owned_by_codec_errors() {
84 assert!(
85 CudaBatchError::Infrastructure(BatchInfrastructureError::EmptyBatchPlan)
86 .session_is_unusable()
87 );
88 assert!(group_error(Error::CudaUnavailable).session_is_unusable());
89 assert!(!group_error(Error::capability_rejected(
90 j2k_core::CapabilityRejection::contract_violation("test contract rejection")
91 ))
92 .session_is_unusable());
93 }
94}
95
96#[derive(Debug, thiserror::Error)]
102#[error("CUDA batch group containing source indices {source_indices:?} failed: {source}")]
103pub struct CudaBatchGroupError {
104 source_indices: Vec<usize>,
105 #[source]
106 source: Box<Error>,
107}
108
109impl CudaBatchGroupError {
110 #[cfg(feature = "cuda-runtime")]
111 #[allow(
112 clippy::disallowed_methods,
113 reason = "error construction preserves its infallible public signature while retaining affected source indices"
114 )]
115 pub(super) fn new(group: &PreparedBatchGroup, source: Error) -> Self {
116 Self {
117 source_indices: group.source_indices().to_vec(),
118 source: Box::new(source),
119 }
120 }
121
122 #[cfg(feature = "cuda-runtime")]
123 pub(super) fn from_parts(source_indices: Vec<usize>, source: Error) -> Self {
124 Self {
125 source_indices,
126 source: Box::new(source),
127 }
128 }
129
130 #[must_use]
132 pub fn source_indices(&self) -> &[usize] {
133 &self.source_indices
134 }
135
136 #[must_use]
138 pub fn source(&self) -> &Error {
139 &self.source
140 }
141
142 #[must_use]
144 pub fn into_parts(self) -> (Vec<usize>, Error) {
145 (self.source_indices, *self.source)
146 }
147}
148
149#[derive(Debug)]
151pub struct CudaBatchGroup {
152 pub(super) info: BatchGroupInfo,
153 pub(super) source_indices: Vec<usize>,
154 pub(super) decoded_rects: Vec<Rect>,
155 pub(super) warnings: Vec<Vec<J2kDecodeWarning>>,
156 pub(super) surfaces: Vec<Surface>,
157 pub(super) profile_report: CudaHtj2kProfileReport,
158 #[cfg(feature = "cuda-runtime")]
159 pub(super) dense_output: CudaResidentBatchBuffer,
160}
161
162#[cfg(feature = "cuda-runtime")]
168#[derive(Debug)]
169pub struct CudaResidentBatchBuffer {
170 pub(super) buffer: Arc<j2k_cuda_runtime::CudaDeviceBuffer>,
171 pub(super) ranges: Vec<j2k_cuda_runtime::CudaDeviceBufferRange>,
172}
173
174#[cfg(feature = "cuda-runtime")]
175impl CudaResidentBatchBuffer {
176 #[must_use]
178 pub fn buffer(&self) -> &j2k_cuda_runtime::CudaDeviceBuffer {
179 &self.buffer
180 }
181
182 #[must_use]
184 pub fn ranges(&self) -> &[j2k_cuda_runtime::CudaDeviceBufferRange] {
185 &self.ranges
186 }
187}
188
189impl CudaBatchGroup {
190 #[must_use]
192 pub const fn info(&self) -> &BatchGroupInfo {
193 &self.info
194 }
195
196 #[must_use]
198 pub fn source_indices(&self) -> &[usize] {
199 &self.source_indices
200 }
201
202 #[must_use]
204 pub fn decoded_rects(&self) -> &[Rect] {
205 &self.decoded_rects
206 }
207
208 #[must_use]
210 pub fn warnings(&self) -> &[Vec<J2kDecodeWarning>] {
211 &self.warnings
212 }
213
214 #[must_use]
220 pub fn surfaces(&self) -> &[Surface] {
221 &self.surfaces
222 }
223
224 #[doc(hidden)]
226 #[must_use]
227 pub const fn profile_report(&self) -> &CudaHtj2kProfileReport {
228 &self.profile_report
229 }
230
231 #[cfg(feature = "cuda-runtime")]
237 #[must_use]
238 pub const fn dense_output(&self) -> &CudaResidentBatchBuffer {
239 &self.dense_output
240 }
241
242 #[must_use]
244 #[expect(
245 clippy::type_complexity,
246 reason = "the tuple mirrors the group's five explicitly documented owners"
247 )]
248 #[cfg(not(feature = "cuda-runtime"))]
249 pub fn into_parts(
250 self,
251 ) -> (
252 BatchGroupInfo,
253 Vec<usize>,
254 Vec<Rect>,
255 Vec<Vec<J2kDecodeWarning>>,
256 Vec<Surface>,
257 ) {
258 (
259 self.info,
260 self.source_indices,
261 self.decoded_rects,
262 self.warnings,
263 self.surfaces,
264 )
265 }
266
267 #[cfg(feature = "cuda-runtime")]
270 #[must_use]
271 #[expect(
272 clippy::type_complexity,
273 reason = "the tuple mirrors the group's explicitly documented owners"
274 )]
275 pub fn into_parts(
276 self,
277 ) -> (
278 BatchGroupInfo,
279 Vec<usize>,
280 Vec<Rect>,
281 Vec<Vec<J2kDecodeWarning>>,
282 Vec<Surface>,
283 CudaResidentBatchBuffer,
284 ) {
285 (
286 self.info,
287 self.source_indices,
288 self.decoded_rects,
289 self.warnings,
290 self.surfaces,
291 self.dense_output,
292 )
293 }
294}
295
296#[derive(Debug)]
298pub struct CudaBatchDecodeResult {
299 pub(super) groups: Vec<CudaBatchGroup>,
300 pub(super) errors: Vec<IndexedBatchError>,
301 pub(super) group_errors: Vec<CudaBatchGroupError>,
302}
303
304impl CudaBatchDecodeResult {
305 #[must_use]
307 pub fn groups(&self) -> &[CudaBatchGroup] {
308 &self.groups
309 }
310
311 #[must_use]
313 pub fn errors(&self) -> &[IndexedBatchError] {
314 &self.errors
315 }
316
317 #[must_use]
319 pub fn group_errors(&self) -> &[CudaBatchGroupError] {
320 &self.group_errors
321 }
322
323 #[must_use]
326 pub fn into_parts(
327 self,
328 ) -> (
329 Vec<CudaBatchGroup>,
330 Vec<IndexedBatchError>,
331 Vec<CudaBatchGroupError>,
332 ) {
333 (self.groups, self.errors, self.group_errors)
334 }
335}