1use crate::ImageSize;
30use std::error::Error;
31use std::fmt::Display;
32
33#[derive(Copy, Clone, Debug)]
35pub struct PicScaleBufferMismatch {
36 pub expected: usize,
37 pub width: usize,
38 pub height: usize,
39 pub channels: usize,
40 pub slice_len: usize,
41}
42
43#[derive(Debug)]
45pub enum PicScaleError {
46 ZeroImageDimensions,
47 SourceImageIsTooLarge,
48 DestinationImageIsTooLarge,
49 BufferMismatch(PicScaleBufferMismatch),
50 InvalidStride(usize, usize),
51 UnsupportedBitDepth(usize),
52 UnknownResizingFilter,
53 OutOfMemory(usize),
54 InvalidScratchSize {
55 expected: usize,
56 size: usize,
57 },
58 InvalidSourceSize {
59 expected: ImageSize,
60 size: ImageSize,
61 },
62 InvalidDestinationSize {
63 expected: ImageSize,
64 size: ImageSize,
65 },
66 EmptyPlan,
67}
68
69impl PicScaleError {
70 #[inline]
72 pub fn code(&self) -> usize {
73 match self {
74 PicScaleError::ZeroImageDimensions => 1,
75 PicScaleError::SourceImageIsTooLarge => 2,
76 PicScaleError::DestinationImageIsTooLarge => 3,
77 PicScaleError::BufferMismatch(_) => 4,
78 PicScaleError::InvalidStride(_, _) => 5,
79 PicScaleError::UnsupportedBitDepth(_) => 6,
80 PicScaleError::UnknownResizingFilter => 7,
81 PicScaleError::OutOfMemory(_) => 8,
82 PicScaleError::InvalidScratchSize { .. } => 9,
83 PicScaleError::InvalidSourceSize { .. } => 10,
84 PicScaleError::InvalidDestinationSize { .. } => 11,
85 PicScaleError::EmptyPlan => 12,
86 }
87 }
88}
89
90impl Display for PicScaleError {
91 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92 match self {
93 PicScaleError::InvalidStride(min_stride, real_stride) => f.write_fmt(format_args!(
94 "Stride must be at least {min_stride}, but received {real_stride}",
95 )),
96 PicScaleError::ZeroImageDimensions => {
97 f.write_str("One of image dimensions is 0, this should not happen")
98 }
99 PicScaleError::SourceImageIsTooLarge => {
100 f.write_str("Input image larger than memory capabilities")
101 }
102 PicScaleError::DestinationImageIsTooLarge => {
103 f.write_str("Destination image larger than memory capabilities")
104 }
105 PicScaleError::BufferMismatch(buffer_mismatch) => f.write_fmt(format_args!(
106 "Image buffer len expected to be {} [w({})*h({})*channels({})] but received {}",
107 buffer_mismatch.expected,
108 buffer_mismatch.width,
109 buffer_mismatch.height,
110 buffer_mismatch.channels,
111 buffer_mismatch.slice_len,
112 )),
113 PicScaleError::UnsupportedBitDepth(depth) => {
114 f.write_fmt(format_args!("Bit-depth must be in [1, 16] but got {depth}",))
115 }
116 PicScaleError::UnknownResizingFilter => {
117 f.write_str("Unknown resizing filter was requested")
118 }
119 PicScaleError::OutOfMemory(capacity) => f.write_fmt(format_args!(
120 "There is no enough memory to allocate {capacity} bytes"
121 )),
122 PicScaleError::InvalidScratchSize { expected, size } => f.write_fmt(format_args!(
123 "Scratch size must be at least {expected} bytes, but received {size}",
124 )),
125 PicScaleError::InvalidSourceSize { expected, size } => f.write_fmt(format_args!(
126 "Source size must be at least {:?} bytes, but received {:?}",
127 expected, size
128 )),
129 PicScaleError::InvalidDestinationSize { expected, size } => f.write_fmt(format_args!(
130 "Destination size must be at least {:?} bytes, but received {:?}",
131 expected, size
132 )),
133 PicScaleError::EmptyPlan => {
134 f.write_str("Multi-step scaling appeared to be an empty one")
135 }
136 }
137 }
138}
139
140impl Error for PicScaleError {}
141
142macro_rules! try_vec {
143 () => {
144 Vec::new()
145 };
146 ($elem:expr; $n:expr) => {{
147 let mut v = Vec::new();
148 v.try_reserve_exact($n)
149 .map_err(|_| crate::validation::PicScaleError::OutOfMemory($n))?;
150 v.resize($n, $elem);
151 v
152 }};
153}
154
155pub(crate) use try_vec;
156
157macro_rules! validate_scratch {
158 ($scratch: expr, $required_size: expr) => {{
159 if $scratch.len() < $required_size {
160 return Err(PicScaleError::InvalidScratchSize {
161 expected: $required_size,
162 size: $scratch.len(),
163 });
164 }
165 &mut $scratch[..$required_size]
166 }};
167}
168
169pub(crate) use validate_scratch;
170
171macro_rules! validate_sizes {
172 ($store: expr, $into: expr, $src_size: expr, $dst_size: expr) => {{
173 $into.validate()?;
174 $store.validate()?;
175 if $store.width != $src_size.width && $store.height != $src_size.height {
176 return Err(PicScaleError::InvalidSourceSize {
177 expected: $src_size,
178 size: $store.size(),
179 });
180 }
181 if $into.width != $dst_size.width && $into.height != $dst_size.height {
182 return Err(PicScaleError::InvalidDestinationSize {
183 expected: $dst_size,
184 size: $into.size(),
185 });
186 }
187 if $store.width == $into.width && $store.height == $into.height {
188 $store.copied_to_mut($into);
189 return Ok(());
190 }
191 }};
192}
193
194pub(crate) use validate_sizes;