fast image operations
Diffstat (limited to 'src/builder.rs')
-rw-r--r--src/builder.rs92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/builder.rs b/src/builder.rs
new file mode 100644
index 0000000..ec0e518
--- /dev/null
+++ b/src/builder.rs
@@ -0,0 +1,92 @@
+//! safe builder for the image
+//!
+//! does not let you do funny things
+use std::marker::PhantomData;
+
+use crate::Image;
+
+impl<B, const C: usize> Image<B, C> {
+ /// creates a builder
+ pub const fn build<I>(w: u32, h: u32) -> Builder<B, C>
+ where
+ B: AsRef<[I]>,
+ {
+ Builder::new(w, h)
+ }
+}
+
+/// Safe [`Image`] builder.
+#[must_use = "builder must be consumed"]
+pub struct Builder<B, const C: usize> {
+ /// 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,
+ #[allow(clippy::missing_docs_in_private_items)]
+ _buffer: PhantomData<B>,
+}
+impl<B, const C: usize> Builder<B, C> {
+ /// create new builder
+ pub const fn new(w: u32, h: u32) -> Self {
+ Self {
+ width: w,
+ height: h,
+ _buffer: PhantomData,
+ }
+ }
+
+ /// apply a buffer, and build
+ #[track_caller]
+ #[must_use = "what is it going to do?"]
+ pub fn buf<I>(self, buffer: B) -> Image<B, C>
+ where
+ B: AsRef<[I]>,
+ {
+ let len = C as u32 * self.width * self.height;
+ assert!(
+ buffer.as_ref().len() as u32 == len,
+ "invalid buffer size (expected {len}, got {})",
+ buffer.as_ref().len()
+ );
+ // SAFETY: checked!
+ unsafe { self.buf_unchecked(buffer) }
+ }
+ /// apply a buffer, and build (length unchecked)
+ #[track_caller]
+ #[must_use = "what is it going to do?"]
+ pub unsafe fn buf_unchecked<I>(self, buffer: B) -> Image<B, C>
+ where
+ B: AsRef<[I]>,
+ {
+ Image {
+ buffer,
+ width: self.width.try_into().expect("passed zero width to builder"),
+ height: self
+ .height
+ .try_into()
+ .expect("passed zero height to builder"),
+ }
+ }
+}
+
+impl<const C: usize> Builder<Vec<u8>, C> {
+ /// allocate this image
+ #[must_use = "what is it going to do?"]
+ pub fn alloc(self) -> Image<Vec<u8>, C> {
+ Image::alloc(self.width, self.height)
+ }
+}
+
+impl<T: Copy, const C: usize> Builder<Box<[T]>, C> {
+ /// Fill this image with a certain pixel.
+ /// ```
+ /// # use fimg::Image;
+ ///
+ /// // fill black
+ /// Image::build(50, 50).fill([0, 0, 0, 255]);
+ /// ```
+ pub fn fill(self, with: [T; C]) -> Image<Box<[T]>, C> {
+ Image::build(self.width, self.height)
+ .buf((0..self.width * self.height).flat_map(|_| with).collect())
+ }
+}