fast image operations
Diffstat (limited to 'src/indexed/builder.rs')
| -rw-r--r-- | src/indexed/builder.rs | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/src/indexed/builder.rs b/src/indexed/builder.rs new file mode 100644 index 0000000..faa38c7 --- /dev/null +++ b/src/indexed/builder.rs @@ -0,0 +1,118 @@ +use super::{uint, IndexedImage as Image}; +use std::{marker::PhantomData, mem::MaybeUninit}; +impl<B, P> Image<B, P> { + /// creates a builder + pub const fn build<I, J>(w: u32, h: u32) -> Builder<B, P> + where + B: AsRef<[I]>, + P: AsRef<[J]>, + { + Builder::new(w, h) + } +} + +/// Safe [`Image`] builder. +#[must_use = "builder must be consumed"] +pub struct Builder<B, P> { + /// the width in a zeroable type. zeroable so as to make the check in [`buf`] easier. + width: u32, + /// the height in a zeroable type. + height: u32, + palette: Option<P>, + #[allow(clippy::missing_docs_in_private_items)] + _buffer: PhantomData<B>, +} +impl<B, P> Builder<B, P> { + /// create new builder + pub const fn new(w: u32, h: u32) -> Self { + Self { + width: w, + height: h, + _buffer: PhantomData, + palette: None, + } + } + + /// add a palette + pub fn pal(self, p: P) -> Self { + Self { + palette: Some(p), + ..self + } + } + + /// apply a buffer, and build + #[track_caller] + #[must_use = "what is it going to do?"] + #[allow(private_bounds)] + pub fn buf<I: uint, J>(self, buffer: B) -> Image<B, P> + where + B: AsRef<[I]>, + P: AsRef<[J]>, + { + Image::from_raw_parts( + crate::Image::build(self.width, self.height).buf(buffer), + self.palette.expect("require palette"), + ) + .unwrap() + } + + pub unsafe fn buf_unchecked<I>(self, buffer: B) -> Image<B, P> + where + B: AsRef<[I]>, + { + Image { + buffer: unsafe { crate::Image::build(self.width, self.height).buf_unchecked(buffer) }, + palette: self.palette.expect("require palette"), + } + } + + /// Allocates a zeroed buffer. + #[track_caller] + #[must_use] + pub fn alloc<I: uint, J>(self) -> Image<Box<[I]>, P> + where + P: AsRef<[J]>, + { + let palette = self.palette.expect("require palette"); + assert!(palette.as_ref().len() != 0, "need some palette"); + Image { + buffer: crate::Image::build(self.width, self.height).buf( + vec![I::default(); self.width as usize * self.height as usize].into_boxed_slice(), + ), + palette, + } + } + + pub fn uninit<I: uint, J>(self) -> Image<Box<[MaybeUninit<I>]>, P> + where + P: AsRef<[J]>, + { + Image { + buffer: crate::Image::build(self.width, self.height).buf(Box::new_uninit_slice( + self.width as usize * self.height as usize, + )), + palette: self.palette.expect("require palette"), + } + } + + /// Safety + /// + /// read implementation + pub unsafe fn from_iter<I: uint, J>( + self, + iter: impl Iterator<Item = ((u32, u32), I)> + ExactSizeIterator, + ) -> Image<Box<[I]>, P> + where + P: AsRef<[J]>, + { + debug_assert!(iter.len() >= self.width as usize * self.height as usize); + let mut me = self.uninit(); + // SAFETY: the pixel must be in bounds + iter.for_each(|((x, y), item)| unsafe { + me.pixel_mut(x, y).write(item); + }); + // SAFETY: all pixels must have been visited at least once + unsafe { me.assume_init() } + } +} |