Skip to main content

pic_scale/
validation.rs

1/*
2 * Copyright (c) Radzivon Bartoshyk. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1.  Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * 2.  Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * 3.  Neither the name of the copyright holder nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29use crate::ImageSize;
30use std::error::Error;
31use std::fmt::Display;
32
33/// Buffer mismatch error description
34#[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/// Error enumeration type
44#[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}
67
68impl PicScaleError {
69    /// Returns error as int code
70    #[inline]
71    pub fn code(&self) -> usize {
72        match self {
73            PicScaleError::ZeroImageDimensions => 1,
74            PicScaleError::SourceImageIsTooLarge => 2,
75            PicScaleError::DestinationImageIsTooLarge => 3,
76            PicScaleError::BufferMismatch(_) => 4,
77            PicScaleError::InvalidStride(_, _) => 5,
78            PicScaleError::UnsupportedBitDepth(_) => 6,
79            PicScaleError::UnknownResizingFilter => 7,
80            PicScaleError::OutOfMemory(_) => 8,
81            PicScaleError::InvalidScratchSize { .. } => 9,
82            PicScaleError::InvalidSourceSize { .. } => 10,
83            PicScaleError::InvalidDestinationSize { .. } => 11,
84        }
85    }
86}
87
88impl Display for PicScaleError {
89    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
90        match self {
91            PicScaleError::InvalidStride(min_stride, real_stride) => f.write_fmt(format_args!(
92                "Stride must be at least {min_stride}, but received {real_stride}",
93            )),
94            PicScaleError::ZeroImageDimensions => {
95                f.write_str("One of image dimensions is 0, this should not happen")
96            }
97            PicScaleError::SourceImageIsTooLarge => {
98                f.write_str("Input image larger than memory capabilities")
99            }
100            PicScaleError::DestinationImageIsTooLarge => {
101                f.write_str("Destination image larger than memory capabilities")
102            }
103            PicScaleError::BufferMismatch(buffer_mismatch) => f.write_fmt(format_args!(
104                "Image buffer len expected to be {} [w({})*h({})*channels({})] but received {}",
105                buffer_mismatch.expected,
106                buffer_mismatch.width,
107                buffer_mismatch.height,
108                buffer_mismatch.channels,
109                buffer_mismatch.slice_len,
110            )),
111            PicScaleError::UnsupportedBitDepth(depth) => {
112                f.write_fmt(format_args!("Bit-depth must be in [1, 16] but got {depth}",))
113            }
114            PicScaleError::UnknownResizingFilter => {
115                f.write_str("Unknown resizing filter was requested")
116            }
117            PicScaleError::OutOfMemory(capacity) => f.write_fmt(format_args!(
118                "There is no enough memory to allocate {capacity} bytes"
119            )),
120            PicScaleError::InvalidScratchSize { expected, size } => f.write_fmt(format_args!(
121                "Scratch size must be at least {expected} bytes, but received {size}",
122            )),
123            PicScaleError::InvalidSourceSize { expected, size } => f.write_fmt(format_args!(
124                "Source size must be at least {:?} bytes, but received {:?}",
125                expected, size
126            )),
127            PicScaleError::InvalidDestinationSize { expected, size } => f.write_fmt(format_args!(
128                "Destination size must be at least {:?} bytes, but received {:?}",
129                expected, size
130            )),
131        }
132    }
133}
134
135impl Error for PicScaleError {}
136
137macro_rules! try_vec {
138    () => {
139        Vec::new()
140    };
141    ($elem:expr; $n:expr) => {{
142        let mut v = Vec::new();
143        v.try_reserve_exact($n)
144            .map_err(|_| crate::validation::PicScaleError::OutOfMemory($n))?;
145        v.resize($n, $elem);
146        v
147    }};
148}
149
150pub(crate) use try_vec;
151
152macro_rules! validate_scratch {
153    ($scratch: expr, $required_size: expr) => {{
154        if $scratch.len() < $required_size {
155            return Err(PicScaleError::InvalidScratchSize {
156                expected: $required_size,
157                size: $scratch.len(),
158            });
159        }
160        &mut $scratch[..$required_size]
161    }};
162}
163
164pub(crate) use validate_scratch;
165
166macro_rules! validate_sizes {
167    ($store: expr, $into: expr, $src_size: expr, $dst_size: expr) => {{
168        $into.validate()?;
169        $store.validate()?;
170        if $store.width != $src_size.width && $store.height != $src_size.height {
171            return Err(PicScaleError::InvalidSourceSize {
172                expected: $src_size,
173                size: $store.size(),
174            });
175        }
176        if $into.width != $dst_size.width && $into.height != $dst_size.height {
177            return Err(PicScaleError::InvalidDestinationSize {
178                expected: $src_size,
179                size: $store.size(),
180            });
181        }
182        if $store.width == $into.width && $store.height == $into.height {
183            $store.copied_to_mut($into);
184            return Ok(());
185        }
186    }};
187}
188
189pub(crate) use validate_sizes;