#![allow(private_bounds)]
mod builder;
use std::mem::MaybeUninit;
use crate::Image;
#[allow(non_camel_case_types)]
trait uint: Default + Copy + TryInto<usize> {
fn nat(self) -> usize {
self.try_into().ok().unwrap()
}
}
macro_rules! int {
($($t:ty)+) => {
$(impl uint for $t {})+
};
}
int!(u8 u16 u32 u64 usize u128);
#[derive(Clone)]
pub struct IndexedImage<INDEX, PALETTE> {
buffer: Image<INDEX, 1>,
palette: PALETTE, }
impl<I, P> IndexedImage<I, P> {
pub fn to<PIXEL: Copy, INDEX: uint, const CHANNELS: usize>(
&self,
) -> Image<Box<[PIXEL]>, CHANNELS>
where
P: AsRef<[[PIXEL; CHANNELS]]>,
I: AsRef<[INDEX]>,
{
unsafe {
self.buffer.map(|x| {
x.as_ref()
.iter()
.flat_map(|x| *self.palette.as_ref().get_unchecked(x.nat()))
.collect()
})
}
}
pub unsafe fn set_unchecked<INDEX: Copy>(&mut self, x: u32, y: u32, pixel: INDEX)
where
I: AsMut<[INDEX]>,
{
unsafe { *self.pixel_mut(x, y) = pixel };
}
pub unsafe fn pixel_mut<INDEX: Copy>(&mut self, x: u32, y: u32) -> &mut INDEX
where
I: AsMut<[INDEX]>,
{
let p = self.buffer.at(x, y);
unsafe { self.raw().buffer.get_unchecked_mut(p) }
}
pub fn set<INDEX: uint, PIXEL>(&mut self, x: u32, y: u32, pixel: INDEX)
where
I: AsMut<[INDEX]>,
P: AsRef<[PIXEL]>,
{
assert!(self.buffer.width() < x);
assert!(self.buffer.height() < x);
assert!(pixel.nat() < self.palette.as_ref().len());
unsafe { self.set_unchecked(x, y, pixel) };
}
pub unsafe fn raw<INDEX>(&mut self) -> Image<&mut [INDEX], 1>
where
I: AsMut<[INDEX]>,
{
self.buffer.as_mut()
}
pub fn into_raw_parts(self) -> (Image<I, 1>, P) {
(self.buffer, self.palette)
}
pub fn from_raw_parts<INDEX: uint, PIXEL>(
buffer: Image<I, 1>,
palette: P,
) -> Result<Self, &'static str>
where
I: AsRef<[INDEX]>,
P: AsRef<[PIXEL]>,
{
let good = buffer.chunked().all(|[x]| x.nat() < palette.as_ref().len());
good.then_some(Self { buffer, palette })
.ok_or("not all indexes are in palette")
}
}
impl<P, I: uint> IndexedImage<Box<[MaybeUninit<I>]>, P> {
pub unsafe fn assume_init(self) -> IndexedImage<Box<[I]>, P> {
IndexedImage {
buffer: unsafe { self.buffer.mapped(|x| x.assume_init()) },
..self
}
}
}