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