#[derive(Debug, Clone, Copy)]
pub struct Rgb8Image<'a> {
data: &'a [u8],
width: usize,
height: usize,
}
impl<'a> Rgb8Image<'a> {
pub fn new(data: &'a [u8], width: usize, height: usize) -> Result<Self, ImageGeometryError> {
if width == 0 || height == 0 {
return Err(ImageGeometryError::ImageDimensions(ImageDimensions::new(
width, height,
)));
}
let expected = width
.checked_mul(height)
.and_then(|hw| hw.checked_mul(3))
.ok_or(ImageGeometryError::ImageDimensions(ImageDimensions::new(
width, height,
)))?;
if data.len() != expected {
return Err(ImageGeometryError::ImageDataLength(ImageDataLength::new(
data.len(),
expected,
)));
}
Ok(Self {
data,
width,
height,
})
}
#[inline]
pub const fn width(&self) -> usize {
self.width
}
#[inline]
pub const fn height(&self) -> usize {
self.height
}
#[inline]
pub const fn data(&self) -> &'a [u8] {
self.data
}
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum ImageGeometryError {
#[error(
"invalid image dimensions: {}×{} (zero, over the per-axis maximum, or size overflow)",
.0.width(),
.0.height()
)]
ImageDimensions(ImageDimensions),
#[error("image data length mismatch: expected {} bytes (w·h·3), got {}", .0.expected(), .0.got())]
ImageDataLength(ImageDataLength),
}
#[derive(Debug)]
pub struct ImageDimensions {
width: usize,
height: usize,
}
impl ImageDimensions {
#[inline(always)]
pub const fn new(width: usize, height: usize) -> Self {
Self { width, height }
}
#[inline(always)]
pub const fn width(&self) -> usize {
self.width
}
#[inline(always)]
pub const fn height(&self) -> usize {
self.height
}
}
#[derive(Debug)]
pub struct ImageDataLength {
got: usize,
expected: usize,
}
impl ImageDataLength {
#[inline(always)]
pub const fn new(got: usize, expected: usize) -> Self {
Self { got, expected }
}
#[inline(always)]
pub const fn got(&self) -> usize {
self.got
}
#[inline(always)]
pub const fn expected(&self) -> usize {
self.expected
}
}
#[cfg(test)]
mod tests;