use snafu::{Backtrace, Snafu};
use std::marker::PhantomData;
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum Error {
PixelIndexOutOfBounds { backtrace: Backtrace },
}
pub type Result<T> = std::result::Result<T, Error>;
pub trait PixelData {
type Pixel;
fn rows(&self) -> u32;
fn columns(&self) -> u32;
fn bits_per_pixel(&self) -> u32;
fn samples_per_pixel(&self) -> u16;
fn pixel_at(&self, width: u32, height: u32) -> Result<Self::Pixel>;
}
pub trait PixelDataMut: PixelData {
fn pixel_at_mut(&mut self, width: u32, height: u32) -> Result<&mut Self::Pixel>;
}
#[derive(Debug, Clone, PartialEq)]
pub struct InMemoryPixelData<C, P> {
phantom: PhantomData<P>,
data: C,
rows: u32,
cols: u32,
bpp: u32,
samples: u16,
}
impl<C, P> InMemoryPixelData<C, P> {
fn check_bounds(&self, w: u32, h: u32) -> Result<()> {
if w >= self.cols || h >= self.rows {
PixelIndexOutOfBoundsSnafu.fail()
} else {
Ok(())
}
}
pub fn into_raw_data(self) -> C {
self.data
}
pub fn raw_data(&self) -> &C {
&self.data
}
pub fn raw_data_mut(&mut self) -> &mut C {
&mut self.data
}
}
impl<C, P> PixelData for InMemoryPixelData<C, P>
where
P: Clone,
C: std::ops::Deref<Target = [P]>,
{
type Pixel = P;
fn rows(&self) -> u32 {
self.rows
}
fn columns(&self) -> u32 {
self.cols
}
fn bits_per_pixel(&self) -> u32 {
self.bpp
}
fn samples_per_pixel(&self) -> u16 {
self.samples
}
fn pixel_at(&self, w: u32, h: u32) -> Result<P> {
self.check_bounds(w, h).map(move |_| {
let i = (h * self.cols + w) as usize;
self.data[i].clone()
})
}
}
impl<C, P> PixelDataMut for InMemoryPixelData<C, P>
where
P: Clone,
C: std::ops::DerefMut<Target = [P]>,
{
fn pixel_at_mut(&mut self, w: u32, h: u32) -> Result<&mut P> {
self.check_bounds(w, h).map(move |_| {
let i = (h * self.cols + w) as usize;
&mut self.data[i]
})
}
}