use core::fmt;
use j2k_native::EncodeError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Htj2kEncodeErrorKind {
InvalidInput,
Unsupported,
ArithmeticOverflow,
HostResource,
Accelerator,
CodestreamValidation,
InternalInvariant,
Other,
}
#[derive(Debug, PartialEq, Eq)]
pub struct Htj2kEncodeError {
source: EncodeError,
}
impl Htj2kEncodeError {
pub(super) const fn new(source: EncodeError) -> Self {
Self { source }
}
#[must_use]
pub const fn kind(&self) -> Htj2kEncodeErrorKind {
match self.source {
EncodeError::InvalidInput { .. } => Htj2kEncodeErrorKind::InvalidInput,
EncodeError::Unsupported { .. } => Htj2kEncodeErrorKind::Unsupported,
EncodeError::ArithmeticOverflow { .. } => Htj2kEncodeErrorKind::ArithmeticOverflow,
EncodeError::AllocationTooLarge { .. } | EncodeError::HostAllocationFailed { .. } => {
Htj2kEncodeErrorKind::HostResource
}
EncodeError::Accelerator { .. } => Htj2kEncodeErrorKind::Accelerator,
EncodeError::CodestreamValidation { .. } => Htj2kEncodeErrorKind::CodestreamValidation,
EncodeError::InternalInvariant { .. } => Htj2kEncodeErrorKind::InternalInvariant,
_ => Htj2kEncodeErrorKind::Other,
}
}
}
impl fmt::Display for Htj2kEncodeError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.source.fmt(formatter)
}
}
impl core::error::Error for Htj2kEncodeError {
fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
Some(&self.source)
}
}
#[cfg(test)]
mod tests {
use super::{EncodeError, Htj2kEncodeError, Htj2kEncodeErrorKind};
#[test]
fn native_encode_kinds_remain_structured_behind_the_opaque_boundary() {
let cases = [
(
EncodeError::InvalidInput { what: "invalid" },
Htj2kEncodeErrorKind::InvalidInput,
),
(
EncodeError::Unsupported {
what: "unsupported",
},
Htj2kEncodeErrorKind::Unsupported,
),
(
EncodeError::ArithmeticOverflow { what: "overflow" },
Htj2kEncodeErrorKind::ArithmeticOverflow,
),
(
EncodeError::AllocationTooLarge {
what: "workspace",
requested: 17,
cap: 16,
},
Htj2kEncodeErrorKind::HostResource,
),
(
EncodeError::HostAllocationFailed {
what: "workspace",
bytes: 16,
},
Htj2kEncodeErrorKind::HostResource,
),
(
EncodeError::Accelerator {
operation: "dispatch",
source: j2k::J2kEncodeStageError::internal_invariant("failed"),
},
Htj2kEncodeErrorKind::Accelerator,
),
(
EncodeError::CodestreamValidation { detail: "invalid" },
Htj2kEncodeErrorKind::CodestreamValidation,
),
(
EncodeError::InternalInvariant { what: "invalid" },
Htj2kEncodeErrorKind::InternalInvariant,
),
];
for (source, expected) in cases {
let error = Htj2kEncodeError::new(source);
assert_eq!(error.kind(), expected);
assert!(core::error::Error::source(&error)
.and_then(|source| source.downcast_ref::<EncodeError>())
.is_some());
}
}
#[test]
fn opaque_native_encode_error_retains_structural_equality() {
assert_eq!(
Htj2kEncodeError::new(EncodeError::InvalidInput { what: "fixture" }),
Htj2kEncodeError::new(EncodeError::InvalidInput { what: "fixture" })
);
}
}