j2k_transcode/jpeg_to_htj2k/error/
native_encode.rs1use core::fmt;
4
5use j2k_native::EncodeError;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9#[non_exhaustive]
10pub enum Htj2kEncodeErrorKind {
11 InvalidInput,
13 Unsupported,
15 ArithmeticOverflow,
17 HostResource,
19 Accelerator,
21 CodestreamValidation,
23 InternalInvariant,
25 Other,
27}
28
29#[derive(Debug, PartialEq, Eq)]
35pub struct Htj2kEncodeError {
36 source: EncodeError,
37}
38
39impl Htj2kEncodeError {
40 pub(super) const fn new(source: EncodeError) -> Self {
41 Self { source }
42 }
43
44 #[must_use]
46 pub const fn kind(&self) -> Htj2kEncodeErrorKind {
47 match self.source {
48 EncodeError::InvalidInput { .. } => Htj2kEncodeErrorKind::InvalidInput,
49 EncodeError::Unsupported { .. } => Htj2kEncodeErrorKind::Unsupported,
50 EncodeError::ArithmeticOverflow { .. } => Htj2kEncodeErrorKind::ArithmeticOverflow,
51 EncodeError::AllocationTooLarge { .. } | EncodeError::HostAllocationFailed { .. } => {
52 Htj2kEncodeErrorKind::HostResource
53 }
54 EncodeError::Accelerator { .. } => Htj2kEncodeErrorKind::Accelerator,
55 EncodeError::CodestreamValidation { .. } => Htj2kEncodeErrorKind::CodestreamValidation,
56 EncodeError::InternalInvariant { .. } => Htj2kEncodeErrorKind::InternalInvariant,
57 _ => Htj2kEncodeErrorKind::Other,
58 }
59 }
60}
61
62impl fmt::Display for Htj2kEncodeError {
63 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
64 self.source.fmt(formatter)
65 }
66}
67
68impl core::error::Error for Htj2kEncodeError {
69 fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
70 Some(&self.source)
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::{EncodeError, Htj2kEncodeError, Htj2kEncodeErrorKind};
77
78 #[test]
79 fn native_encode_kinds_remain_structured_behind_the_opaque_boundary() {
80 let cases = [
81 (
82 EncodeError::InvalidInput { what: "invalid" },
83 Htj2kEncodeErrorKind::InvalidInput,
84 ),
85 (
86 EncodeError::Unsupported {
87 what: "unsupported",
88 },
89 Htj2kEncodeErrorKind::Unsupported,
90 ),
91 (
92 EncodeError::ArithmeticOverflow { what: "overflow" },
93 Htj2kEncodeErrorKind::ArithmeticOverflow,
94 ),
95 (
96 EncodeError::AllocationTooLarge {
97 what: "workspace",
98 requested: 17,
99 cap: 16,
100 },
101 Htj2kEncodeErrorKind::HostResource,
102 ),
103 (
104 EncodeError::HostAllocationFailed {
105 what: "workspace",
106 bytes: 16,
107 },
108 Htj2kEncodeErrorKind::HostResource,
109 ),
110 (
111 EncodeError::Accelerator {
112 operation: "dispatch",
113 source: j2k::J2kEncodeStageError::internal_invariant("failed"),
114 },
115 Htj2kEncodeErrorKind::Accelerator,
116 ),
117 (
118 EncodeError::CodestreamValidation { detail: "invalid" },
119 Htj2kEncodeErrorKind::CodestreamValidation,
120 ),
121 (
122 EncodeError::InternalInvariant { what: "invalid" },
123 Htj2kEncodeErrorKind::InternalInvariant,
124 ),
125 ];
126
127 for (source, expected) in cases {
128 let error = Htj2kEncodeError::new(source);
129 assert_eq!(error.kind(), expected);
130 assert!(core::error::Error::source(&error)
131 .and_then(|source| source.downcast_ref::<EncodeError>())
132 .is_some());
133 }
134 }
135
136 #[test]
137 fn opaque_native_encode_error_retains_structural_equality() {
138 assert_eq!(
139 Htj2kEncodeError::new(EncodeError::InvalidInput { what: "fixture" }),
140 Htj2kEncodeError::new(EncodeError::InvalidInput { what: "fixture" })
141 );
142 }
143}