#[cfg(feature = "cuda-runtime")]
use super::Arc;
use super::{
BatchGroupInfo, BatchInfrastructureError, Error, IndexedBatchError, J2kDecodeWarning,
PreparedBatchGroup, Rect, Surface,
};
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum CudaBatchError {
#[error(transparent)]
Infrastructure(#[from] BatchInfrastructureError),
#[error("CUDA batch group containing source indices {source_indices:?} failed: {source}")]
GroupExecution {
source_indices: Vec<usize>,
#[source]
source: Box<Error>,
},
}
impl CudaBatchError {
#[allow(
clippy::disallowed_methods,
reason = "error construction preserves its infallible public signature while retaining affected source indices"
)]
pub(super) fn group(group: &PreparedBatchGroup, source: Error) -> Self {
Self::GroupExecution {
source_indices: group.source_indices().to_vec(),
source: Box::new(source),
}
}
#[cfg(feature = "cuda-runtime")]
#[doc(hidden)]
pub fn completion_is_uncertain(&self) -> bool {
match self {
Self::GroupExecution { source, .. } => source.completion_is_uncertain(),
Self::Infrastructure(_) => false,
}
}
#[doc(hidden)]
#[must_use]
pub fn session_is_unusable(&self) -> bool {
match self {
Self::Infrastructure(_) => true,
Self::GroupExecution { source, .. } => source.session_is_unusable(),
}
}
}
#[cfg(test)]
mod classification_tests {
use j2k_core::BatchInfrastructureError;
use super::CudaBatchError;
use crate::Error;
fn group_error(source: Error) -> CudaBatchError {
CudaBatchError::GroupExecution {
source_indices: vec![3],
source: Box::new(source),
}
}
#[test]
fn cuda_batch_session_classification_is_owned_by_codec_errors() {
assert!(
CudaBatchError::Infrastructure(BatchInfrastructureError::EmptyBatchPlan)
.session_is_unusable()
);
assert!(group_error(Error::CudaUnavailable).session_is_unusable());
assert!(!group_error(Error::UnsupportedCudaRequest {
reason: "test contract rejection",
})
.session_is_unusable());
}
}
#[derive(Debug, thiserror::Error)]
#[error("CUDA batch group containing source indices {source_indices:?} failed: {source}")]
pub struct CudaBatchGroupError {
source_indices: Vec<usize>,
#[source]
source: Box<Error>,
}
impl CudaBatchGroupError {
#[cfg(feature = "cuda-runtime")]
#[allow(
clippy::disallowed_methods,
reason = "error construction preserves its infallible public signature while retaining affected source indices"
)]
pub(super) fn new(group: &PreparedBatchGroup, source: Error) -> Self {
Self {
source_indices: group.source_indices().to_vec(),
source: Box::new(source),
}
}
#[cfg(feature = "cuda-runtime")]
pub(super) fn from_parts(source_indices: Vec<usize>, source: Error) -> Self {
Self {
source_indices,
source: Box::new(source),
}
}
#[must_use]
pub fn source_indices(&self) -> &[usize] {
&self.source_indices
}
#[must_use]
pub fn source(&self) -> &Error {
&self.source
}
#[must_use]
pub fn into_parts(self) -> (Vec<usize>, Error) {
(self.source_indices, *self.source)
}
}
#[derive(Debug)]
pub struct CudaBatchGroup {
pub(super) info: BatchGroupInfo,
pub(super) source_indices: Vec<usize>,
pub(super) decoded_rects: Vec<Rect>,
pub(super) warnings: Vec<Vec<J2kDecodeWarning>>,
pub(super) surfaces: Vec<Surface>,
#[cfg(feature = "cuda-runtime")]
pub(super) dense_output: CudaResidentBatchBuffer,
}
#[cfg(feature = "cuda-runtime")]
#[derive(Debug)]
pub struct CudaResidentBatchBuffer {
pub(super) buffer: Arc<j2k_cuda_runtime::CudaDeviceBuffer>,
pub(super) ranges: Vec<j2k_cuda_runtime::CudaDeviceBufferRange>,
}
#[cfg(feature = "cuda-runtime")]
impl CudaResidentBatchBuffer {
#[must_use]
pub fn buffer(&self) -> &j2k_cuda_runtime::CudaDeviceBuffer {
&self.buffer
}
#[must_use]
pub fn ranges(&self) -> &[j2k_cuda_runtime::CudaDeviceBufferRange] {
&self.ranges
}
}
impl CudaBatchGroup {
#[must_use]
pub const fn info(&self) -> &BatchGroupInfo {
&self.info
}
#[must_use]
pub fn source_indices(&self) -> &[usize] {
&self.source_indices
}
#[must_use]
pub fn decoded_rects(&self) -> &[Rect] {
&self.decoded_rects
}
#[must_use]
pub fn warnings(&self) -> &[Vec<J2kDecodeWarning>] {
&self.warnings
}
#[must_use]
pub fn surfaces(&self) -> &[Surface] {
&self.surfaces
}
#[cfg(feature = "cuda-runtime")]
#[must_use]
pub const fn dense_output(&self) -> &CudaResidentBatchBuffer {
&self.dense_output
}
#[must_use]
#[expect(
clippy::type_complexity,
reason = "the tuple mirrors the group's five explicitly documented owners"
)]
#[cfg(not(feature = "cuda-runtime"))]
pub fn into_parts(
self,
) -> (
BatchGroupInfo,
Vec<usize>,
Vec<Rect>,
Vec<Vec<J2kDecodeWarning>>,
Vec<Surface>,
) {
(
self.info,
self.source_indices,
self.decoded_rects,
self.warnings,
self.surfaces,
)
}
#[cfg(feature = "cuda-runtime")]
#[must_use]
#[expect(
clippy::type_complexity,
reason = "the tuple mirrors the group's explicitly documented owners"
)]
pub fn into_parts(
self,
) -> (
BatchGroupInfo,
Vec<usize>,
Vec<Rect>,
Vec<Vec<J2kDecodeWarning>>,
Vec<Surface>,
CudaResidentBatchBuffer,
) {
(
self.info,
self.source_indices,
self.decoded_rects,
self.warnings,
self.surfaces,
self.dense_output,
)
}
}
#[derive(Debug)]
pub struct CudaBatchDecodeResult {
pub(super) groups: Vec<CudaBatchGroup>,
pub(super) errors: Vec<IndexedBatchError>,
pub(super) group_errors: Vec<CudaBatchGroupError>,
}
impl CudaBatchDecodeResult {
#[must_use]
pub fn groups(&self) -> &[CudaBatchGroup] {
&self.groups
}
#[must_use]
pub fn errors(&self) -> &[IndexedBatchError] {
&self.errors
}
#[must_use]
pub fn group_errors(&self) -> &[CudaBatchGroupError] {
&self.group_errors
}
#[must_use]
pub fn into_parts(
self,
) -> (
Vec<CudaBatchGroup>,
Vec<IndexedBatchError>,
Vec<CudaBatchGroupError>,
) {
(self.groups, self.errors, self.group_errors)
}
}