zenpixels_convert/
error.rs1use crate::{PixelDescriptor, TransferFunction};
4use core::fmt;
5
6#[derive(Debug, Clone, PartialEq)]
8pub enum ConvertError {
9 NoMatch { source: PixelDescriptor },
11 NoPath {
13 from: PixelDescriptor,
14 to: PixelDescriptor,
15 },
16 BufferSize { expected: usize, actual: usize },
18 InvalidWidth(u32),
20 EmptyFormatList,
22 UnsupportedTransfer {
24 from: TransferFunction,
25 to: TransferFunction,
26 },
27 AlphaNotOpaque,
29 DepthReductionForbidden,
31 AlphaRemovalForbidden,
33 RgbToGray,
35 AllocationFailed,
37 CmsError(alloc::string::String),
39 HdrTransferRequiresToneMapping,
44}
45
46impl fmt::Display for ConvertError {
47 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48 match self {
49 Self::NoMatch { source } => {
50 write!(
51 f,
52 "no supported format matches source {:?}/{:?}",
53 source.channel_type(),
54 source.layout()
55 )
56 }
57 Self::NoPath { from, to } => {
58 write!(
59 f,
60 "no conversion path from {:?}/{:?} to {:?}/{:?}",
61 from.channel_type(),
62 from.layout(),
63 to.channel_type(),
64 to.layout()
65 )
66 }
67 Self::BufferSize { expected, actual } => {
68 write!(
69 f,
70 "buffer size mismatch: expected {expected} bytes, got {actual}"
71 )
72 }
73 Self::InvalidWidth(w) => write!(f, "invalid width: {w}"),
74 Self::EmptyFormatList => write!(f, "supported format list is empty"),
75 Self::UnsupportedTransfer { from, to } => {
76 write!(f, "unsupported transfer conversion: {from:?} → {to:?}")
77 }
78 Self::AlphaNotOpaque => write!(f, "alpha channel is not fully opaque"),
79 Self::DepthReductionForbidden => write!(f, "depth reduction forbidden by policy"),
80 Self::AlphaRemovalForbidden => write!(f, "alpha removal forbidden by policy"),
81 Self::RgbToGray => {
82 write!(f, "RGB-to-grayscale requires explicit luma coefficients")
83 }
84 Self::AllocationFailed => write!(f, "buffer allocation failed"),
85 Self::CmsError(msg) => write!(f, "CMS transform failed: {msg}"),
86 Self::HdrTransferRequiresToneMapping => write!(
87 f,
88 "HDR source (PQ/HLG) requires tone mapping before conversion to SDR target"
89 ),
90 }
91 }
92}
93
94#[cfg(feature = "std")]
95impl std::error::Error for ConvertError {}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use alloc::format;
101
102 #[test]
103 fn display_no_match() {
104 let e = ConvertError::NoMatch {
105 source: PixelDescriptor::RGB8_SRGB,
106 };
107 let s = format!("{e}");
108 assert!(s.contains("no supported format"));
109 assert!(s.contains("U8"));
110 assert!(s.contains("Rgb"));
111 }
112
113 #[test]
114 fn display_no_path() {
115 let e = ConvertError::NoPath {
116 from: PixelDescriptor::RGB8_SRGB,
117 to: PixelDescriptor::GRAY8_SRGB,
118 };
119 let s = format!("{e}");
120 assert!(s.contains("no conversion path"));
121 }
122
123 #[test]
124 fn display_buffer_size() {
125 let e = ConvertError::BufferSize {
126 expected: 1024,
127 actual: 512,
128 };
129 let s = format!("{e}");
130 assert!(s.contains("1024"));
131 assert!(s.contains("512"));
132 }
133
134 #[test]
135 fn display_invalid_width() {
136 let e = ConvertError::InvalidWidth(0);
137 assert!(format!("{e}").contains("0"));
138 }
139
140 #[test]
141 fn display_empty_format_list() {
142 let s = format!("{}", ConvertError::EmptyFormatList);
143 assert!(s.contains("empty"));
144 }
145
146 #[test]
147 fn display_unsupported_transfer() {
148 let e = ConvertError::UnsupportedTransfer {
149 from: TransferFunction::Pq,
150 to: TransferFunction::Hlg,
151 };
152 let s = format!("{e}");
153 assert!(s.contains("Pq"));
154 assert!(s.contains("Hlg"));
155 }
156
157 #[test]
158 fn display_alpha_not_opaque() {
159 assert!(format!("{}", ConvertError::AlphaNotOpaque).contains("opaque"));
160 }
161
162 #[test]
163 fn display_depth_reduction_forbidden() {
164 assert!(format!("{}", ConvertError::DepthReductionForbidden).contains("forbidden"));
165 }
166
167 #[test]
168 fn display_alpha_removal_forbidden() {
169 assert!(format!("{}", ConvertError::AlphaRemovalForbidden).contains("forbidden"));
170 }
171
172 #[test]
173 fn display_rgb_to_gray() {
174 assert!(format!("{}", ConvertError::RgbToGray).contains("luma"));
175 }
176
177 #[test]
178 fn display_allocation_failed() {
179 assert!(format!("{}", ConvertError::AllocationFailed).contains("allocation"));
180 }
181
182 #[test]
183 fn display_cms_error() {
184 let e = ConvertError::CmsError(alloc::string::String::from("profile mismatch"));
185 let s = format!("{e}");
186 assert!(s.contains("CMS transform failed"));
187 assert!(s.contains("profile mismatch"));
188 }
189
190 #[test]
191 fn error_eq() {
192 assert_eq!(ConvertError::AlphaNotOpaque, ConvertError::AlphaNotOpaque);
193 assert_ne!(ConvertError::AlphaNotOpaque, ConvertError::RgbToGray);
194 }
195
196 #[test]
197 fn error_debug() {
198 let e = ConvertError::AllocationFailed;
199 let s = format!("{e:?}");
200 assert!(s.contains("AllocationFailed"));
201 }
202
203 #[test]
204 fn error_clone() {
205 let e = ConvertError::BufferSize {
206 expected: 100,
207 actual: 50,
208 };
209 let e2 = e.clone();
210 assert_eq!(e, e2);
211 }
212}