use AsRef instead of Deref

This commit is contained in:
bendn 2023-10-04 10:19:52 +07:00
parent 101ca55d29
commit f465e25077
No known key found for this signature in database
GPG key ID: 0D9D3A2A3B2A93D6
12 changed files with 101 additions and 63 deletions

View file

@ -1,6 +1,6 @@
[package] [package]
name = "fimg" name = "fimg"
version = "0.4.13" version = "0.4.14"
authors = ["bend-n <bend.n@outlook.com>"] authors = ["bend-n <bend.n@outlook.com>"]
license = "MIT" license = "MIT"
edition = "2021" edition = "2021"

View file

@ -3,12 +3,13 @@ use fimg::*;
macro_rules! bench { macro_rules! bench {
(fn $name: ident() { run $fn: ident() } $($namec:ident)?) => { (fn $name: ident() { run $fn: ident() } $($namec:ident)?) => {
fn $name() { fn $name() {
let mut bytes = *include_bytes!("4_128x128.imgbuf");
let mut img: Image<_, 4> = let mut img: Image<_, 4> =
Image::build(128, 128).buf(include_bytes!("4_128x128.imgbuf").to_vec()); Image::build(128, 128).buf(&mut bytes);
for _ in 0..256 { for _ in 0..256 {
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
unsafe { unsafe {
img.$fn() img.as_mut().$fn()
}; };
} }
} }

View file

@ -1,7 +1,7 @@
use fimg::*; use fimg::*;
fn tri() { fn tri() {
let mut b = [0u8; 1000 * 1000 * 4]; let mut i: Image<_, 4> = fimg::make!(4 channels 1000 x 1000);
let mut i = Image::<&mut [u8], 4>::build(1000, 1000).buf(&mut b); i.as_mut()
i.tri((0., 0.), (1000., 500.), (0., 999.), [255, 255, 255, 255]); .tri((0., 0.), (1000., 500.), (0., 999.), [255, 255, 255, 255]);
} }
iai::main!(tri); iai::main!(tri);

View file

@ -1,7 +1,7 @@
use fimg::*; use fimg::*;
fn overlay_3on3at() { fn overlay_3on3at() {
let mut a: Image<_, 3> = Image::alloc(128, 128); let mut a = fimg::make!(3 channels 128 x 128);
let b: Image<&[u8], 3> = Image::build(8, 8).buf(include_bytes!("3_8x8.imgbuf")); let b: Image<&[u8], 3> = Image::build(8, 8).buf(include_bytes!("3_8x8.imgbuf"));
for x in 0..16 { for x in 0..16 {
for y in 0..16 { for y in 0..16 {
@ -11,7 +11,7 @@ fn overlay_3on3at() {
} }
fn overlay_4on3at() { fn overlay_4on3at() {
let mut a: Image<_, 3> = Image::alloc(128, 128); let mut a = fimg::make!(3 channels 128 x 128);
let b: Image<&[u8], 4> = Image::build(8, 8).buf(include_bytes!("4_8x8.imgbuf")); let b: Image<&[u8], 4> = Image::build(8, 8).buf(include_bytes!("4_8x8.imgbuf"));
for x in 0..16 { for x in 0..16 {
for y in 0..16 { for y in 0..16 {
@ -21,7 +21,7 @@ fn overlay_4on3at() {
} }
fn overlay_4on4at() { fn overlay_4on4at() {
let mut a: Image<_, 4> = Image::alloc(128, 128); let mut a = fimg::make!(4 channels 128 x 128);
let b: Image<&[u8], 4> = Image::build(8, 8).buf(include_bytes!("4_8x8.imgbuf")); let b: Image<&[u8], 4> = Image::build(8, 8).buf(include_bytes!("4_8x8.imgbuf"));
for x in 0..16 { for x in 0..16 {
for y in 0..16 { for y in 0..16 {

View file

@ -1,6 +1,4 @@
//! Manages the affine image transformations. //! Manages the affine image transformations.
use std::ops::DerefMut;
use crate::{cloner::ImageCloner, Image}; use crate::{cloner::ImageCloner, Image};
impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> { impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
@ -45,7 +43,7 @@ impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
} }
} }
impl<const CHANNELS: usize, T: DerefMut<Target = [u8]>> Image<T, CHANNELS> { impl<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>> Image<T, CHANNELS> {
/// Flip an image vertically. /// Flip an image vertically.
pub fn flip_v(&mut self) { pub fn flip_v(&mut self) {
for y in 0..self.height() / 2 { for y in 0..self.height() / 2 {
@ -127,7 +125,7 @@ impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
} }
} }
impl<const CHANNELS: usize, T: DerefMut<Target = [u8]>> Image<T, CHANNELS> { impl<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>> Image<T, CHANNELS> {
/// Rotate an image 180 degrees clockwise. /// Rotate an image 180 degrees clockwise.
pub fn rot_180(&mut self) { pub fn rot_180(&mut self) {
self.flatten_mut().reverse(); self.flatten_mut().reverse();
@ -162,7 +160,7 @@ impl<const CHANNELS: usize, T: DerefMut<Target = [u8]>> Image<T, CHANNELS> {
/// # Safety /// # Safety
/// ///
/// UB if supplied image not square /// UB if supplied image not square
unsafe fn crev<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(mut img: Image<T, CHANNELS>) { unsafe fn crev<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>>(mut img: Image<T, CHANNELS>) {
debug_assert_eq!(img.width(), img.height()); debug_assert_eq!(img.width(), img.height());
let size = img.width() as usize; let size = img.width() as usize;
let b = img.flatten_mut(); let b = img.flatten_mut();
@ -202,7 +200,7 @@ unsafe fn transpose_out<const CHANNELS: usize>(
/// # Safety /// # Safety
/// ///
/// UB if supplied image rectangular /// UB if supplied image rectangular
unsafe fn transpose<const CHANNELS: usize, T: DerefMut<Target = [u8]>>( unsafe fn transpose<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>>(
img: &mut Image<T, CHANNELS>, img: &mut Image<T, CHANNELS>,
) { ) {
debug_assert_eq!(img.width(), img.height()); debug_assert_eq!(img.width(), img.height());
@ -220,7 +218,7 @@ unsafe fn transpose<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(
/// # Safety /// # Safety
/// ///
/// UB if image not square /// UB if image not square
unsafe fn transpose_non_power_of_two<const CHANNELS: usize, T: DerefMut<Target = [u8]>>( unsafe fn transpose_non_power_of_two<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>>(
img: &mut Image<T, CHANNELS>, img: &mut Image<T, CHANNELS>,
) { ) {
debug_assert_eq!(img.width(), img.height()); debug_assert_eq!(img.width(), img.height());
@ -239,7 +237,7 @@ const TILE: usize = 4;
/// # Safety /// # Safety
/// ///
/// be careful /// be careful
unsafe fn transpose_tile<const CHANNELS: usize, T: DerefMut<Target = [u8]>>( unsafe fn transpose_tile<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>>(
img: &mut Image<T, CHANNELS>, img: &mut Image<T, CHANNELS>,
row: usize, row: usize,
col: usize, col: usize,
@ -275,7 +273,7 @@ unsafe fn transpose_tile<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(
/// # Safety /// # Safety
/// ///
/// be careful /// be careful
unsafe fn transpose_diag<const CHANNELS: usize, T: DerefMut<Target = [u8]>>( unsafe fn transpose_diag<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>>(
img: &mut Image<T, CHANNELS>, img: &mut Image<T, CHANNELS>,
pos: usize, pos: usize,
size: usize, size: usize,

View file

@ -1,9 +1,9 @@
//! `Box<cat>` //! `Box<cat>`
use std::ops::{DerefMut, Range}; use std::ops::Range;
use crate::Image; use crate::Image;
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> { impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// Draw a bordered box /// Draw a bordered box
/// ``` /// ```
/// # use fimg::Image; /// # use fimg::Image;

View file

@ -1,8 +1,8 @@
//! draw 2d circles //! draw 2d circles
use crate::Image; use crate::Image;
use std::ops::DerefMut;
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// Draws a circle, using the [Bresenham's circle](https://en.wikipedia.org/wiki/Midpoint_circle_algorithm) algorithm. /// Draws a circle, using the [Bresenham's circle](https://en.wikipedia.org/wiki/Midpoint_circle_algorithm) algorithm.
/// ``` /// ```
/// # use fimg::Image; /// # use fimg::Image;

View file

@ -1,7 +1,7 @@
//! adds a `line` function to Image //! adds a `line` function to Image
#![allow(clippy::missing_docs_in_private_items)] #![allow(clippy::missing_docs_in_private_items)]
use crate::Image; use crate::Image;
use std::{iter::Iterator, ops::DerefMut}; use std::iter::Iterator;
/// taken from [bresenham-rs](https://github.com/mbr/bresenham-rs) /// taken from [bresenham-rs](https://github.com/mbr/bresenham-rs)
pub struct Bresenham { pub struct Bresenham {
@ -127,7 +127,7 @@ impl Iterator for Bresenham {
} }
} }
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> { impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// Draw a line from point a to point b. /// Draw a line from point a to point b.
/// ///
/// Points not in bounds will not be included. /// Points not in bounds will not be included.

View file

@ -2,12 +2,11 @@
use std::{ use std::{
cmp::{max, min}, cmp::{max, min},
f32::consts::TAU, f32::consts::TAU,
ops::DerefMut,
}; };
use crate::Image; use crate::Image;
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> { impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// Draws a filled polygon from a slice of points. Please close your poly. (first == last) /// Draws a filled polygon from a slice of points. Please close your poly. (first == last)
/// ///
/// Borrowed from [imageproc](https://docs.rs/imageproc/latest/src/imageproc/drawing/polygon.rs.html#31), modified for less allocations. /// Borrowed from [imageproc](https://docs.rs/imageproc/latest/src/imageproc/drawing/polygon.rs.html#31), modified for less allocations.

View file

@ -1,9 +1,9 @@
//! trongle drawing //! trongle drawing
use std::ops::DerefMut;
use crate::Image; use crate::Image;
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> { impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// Draw a (filled) triangle /// Draw a (filled) triangle
/// ``` /// ```
/// # use fimg::*; /// # use fimg::*;

View file

@ -233,7 +233,7 @@ impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
/// ``` /// ```
pub const fn make<'a, const WIDTH: u32, const HEIGHT: u32>() -> Image<&'a [u8], CHANNELS> pub const fn make<'a, const WIDTH: u32, const HEIGHT: u32>() -> Image<&'a [u8], CHANNELS>
where where
[(); CHANNELS * WIDTH as usize * HEIGHT as usize]: Sized, [(); CHANNELS * WIDTH as usize * HEIGHT as usize]:,
{ {
Image { Image {
width: NonZeroU32::new(WIDTH).expect("passed zero width to builder"), width: NonZeroU32::new(WIDTH).expect("passed zero width to builder"),
@ -243,7 +243,40 @@ impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
} }
} }
impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> { #[macro_export]
/// Create a <code>[Image]<[[u8]; N], C></code> with ease. If your looking for a <code>[Image]<&'static [[u8]]></code>, try [`Image::make`].
///
/// ```
/// let mut i = fimg::make!(4 channels 128 x 128);
/// ```
///
/// Implementation note:
/// This is doable with a const generic fn, but it returns a `fimg::Image<[u8; fimg::::{impl#7}::array::{constant#1}], _>` which means you cant actually type it, so its useless.
macro_rules! make {
($channels:literal channels $w:literal x $h: literal) => {
unsafe {
Image::<_, $channels>::new(
match ::core::num::NonZeroU32::new($w) {
Some(n) => n,
None => panic!("width is 0"),
},
match ::core::num::NonZeroU32::new($h) {
::core::option::Option::Some(n) => n,
::core::option::Option::None => panic!("height is 0"),
},
[0_u8; $channels * $w * $h],
)
}
};
}
impl<T: AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// The size of the underlying buffer.
#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.buffer.as_ref().len()
}
/// # Safety /// # Safety
/// ///
/// the output index is not guranteed to be in bounds /// the output index is not guranteed to be in bounds
@ -271,7 +304,7 @@ impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS
}; };
// SAFETY: 🧐 is unsound? 😖 // SAFETY: 🧐 is unsound? 😖
let index = unsafe { index.unchecked_mul(CHANNELS) }; let index = unsafe { index.unchecked_mul(CHANNELS) };
debug_assert!(self.buffer.len() > index); debug_assert!(self.len() > index);
index index
} }
@ -284,24 +317,24 @@ impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS
/// Reference this image. /// Reference this image.
pub fn as_ref(&self) -> Image<&[u8], CHANNELS> { pub fn as_ref(&self) -> Image<&[u8], CHANNELS> {
// SAFETY: we got constructed okay, parameters must be valid // SAFETY: we got constructed okay, parameters must be valid
unsafe { Image::new(self.width, self.height, &*self.buffer) } unsafe { Image::new(self.width, self.height, self.buffer.as_ref()) }
} }
#[inline] #[inline]
/// Returns a iterator over every pixel /// Returns a iterator over every pixel
pub fn chunked(&self) -> impl DoubleEndedIterator<Item = &[u8; CHANNELS]> { pub fn chunked(&self) -> impl DoubleEndedIterator<Item = &[u8; CHANNELS]> {
// SAFETY: 0 sized images illegal // SAFETY: 0 sized images illegal
unsafe { assert_unchecked!(self.buffer.len() > CHANNELS) }; unsafe { assert_unchecked!(self.len() > CHANNELS) };
// SAFETY: no half pixels! // SAFETY: no half pixels!
unsafe { assert_unchecked!(self.buffer.len() % CHANNELS == 0) }; unsafe { assert_unchecked!(self.len() % CHANNELS == 0) };
self.buffer.array_chunks::<CHANNELS>() self.buffer.as_ref().array_chunks::<CHANNELS>()
} }
#[inline] #[inline]
/// Flatten the chunks of this image into a slice of slices. /// Flatten the chunks of this image into a slice of slices.
pub fn flatten(&self) -> &[[u8; CHANNELS]] { pub fn flatten(&self) -> &[[u8; CHANNELS]] {
// SAFETY: buffer cannot have half pixels // SAFETY: buffer cannot have half pixels
unsafe { self.buffer.as_chunks_unchecked::<CHANNELS>() } unsafe { self.buffer.as_ref().as_chunks_unchecked::<CHANNELS>() }
} }
/// Return a pixel at (x, y). /// Return a pixel at (x, y).
@ -312,13 +345,19 @@ impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS
#[inline] #[inline]
pub unsafe fn pixel(&self, x: u32, y: u32) -> [u8; CHANNELS] { pub unsafe fn pixel(&self, x: u32, y: u32) -> [u8; CHANNELS] {
// SAFETY: x and y in bounds, slice is okay // SAFETY: x and y in bounds, slice is okay
let ptr = unsafe { self.buffer.get_unchecked(self.slice(x, y)).as_ptr().cast() }; let ptr = unsafe {
self.buffer
.as_ref()
.get_unchecked(self.slice(x, y))
.as_ptr()
.cast()
};
// SAFETY: slice always returns a length of `CHANNELS`, so we `cast()` it for convenience. // SAFETY: slice always returns a length of `CHANNELS`, so we `cast()` it for convenience.
unsafe { *ptr } unsafe { *ptr }
} }
} }
impl<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> { impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
/// Return a mutable reference to a pixel at (x, y). /// Return a mutable reference to a pixel at (x, y).
/// # Safety /// # Safety
/// ///
@ -329,30 +368,30 @@ impl<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANN
// SAFETY: we have been told x, y is in bounds. // SAFETY: we have been told x, y is in bounds.
let idx = self.slice(x, y); let idx = self.slice(x, y);
// SAFETY: slice should always return a valid index // SAFETY: slice should always return a valid index
unsafe { self.buffer.get_unchecked_mut(idx) } unsafe { self.buffer.as_mut().get_unchecked_mut(idx) }
} }
#[inline] #[inline]
/// Returns a iterator over every pixel, mutably /// Returns a iterator over every pixel, mutably
pub fn chunked_mut(&mut self) -> impl Iterator<Item = &mut [u8; CHANNELS]> { pub fn chunked_mut(&mut self) -> impl Iterator<Item = &mut [u8; CHANNELS]> {
// SAFETY: 0 sized images are not allowed // SAFETY: 0 sized images are not allowed
unsafe { assert_unchecked!(self.buffer.len() > CHANNELS) }; unsafe { assert_unchecked!(self.len() > CHANNELS) };
// SAFETY: buffer cannot have half pixels // SAFETY: buffer cannot have half pixels
unsafe { assert_unchecked!(self.buffer.len() % CHANNELS == 0) }; unsafe { assert_unchecked!(self.len() % CHANNELS == 0) };
self.buffer.array_chunks_mut::<CHANNELS>() self.buffer.as_mut().array_chunks_mut::<CHANNELS>()
} }
/// Create a mutref to this image /// Create a mutref to this image
pub fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> { pub fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
// SAFETY: construction went okay // SAFETY: construction went okay
unsafe { Image::new(self.width, self.height, &mut self.buffer) } unsafe { Image::new(self.width, self.height, self.buffer.as_mut()) }
} }
#[inline] #[inline]
/// Flatten the chunks of this image into a mutable slice of slices. /// Flatten the chunks of this image into a mutable slice of slices.
pub fn flatten_mut(&mut self) -> &mut [[u8; CHANNELS]] { pub fn flatten_mut(&mut self) -> &mut [[u8; CHANNELS]] {
// SAFETY: buffer cannot have half pixels // SAFETY: buffer cannot have half pixels
unsafe { self.buffer.as_chunks_unchecked_mut::<CHANNELS>() } unsafe { self.buffer.as_mut().as_chunks_unchecked_mut::<CHANNELS>() }
} }
/// # Safety /// # Safety
@ -363,13 +402,13 @@ impl<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANN
unsafe fn copy_within(&mut self, src: std::ops::Range<usize>, dest: usize) { unsafe fn copy_within(&mut self, src: std::ops::Range<usize>, dest: usize) {
let std::ops::Range { start, end } = src; let std::ops::Range { start, end } = src;
debug_assert!( debug_assert!(
dest <= self.buffer.len() - end - start, dest <= self.buffer.as_ref().len() - end - start,
"dest is out of bounds" "dest is out of bounds"
); );
#[allow(clippy::multiple_unsafe_ops_per_block)] #[allow(clippy::multiple_unsafe_ops_per_block)]
// SAFETY: the caller better be good // SAFETY: the caller better be good
unsafe { unsafe {
let ptr = self.buffer.as_mut_ptr(); let ptr = self.buffer.as_mut().as_mut_ptr();
std::ptr::copy_nonoverlapping(ptr.add(start), ptr.add(dest), end - start) std::ptr::copy_nonoverlapping(ptr.add(start), ptr.add(dest), end - start)
}; };
} }
@ -399,7 +438,7 @@ impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
} }
impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> { impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
/// Allocates a new image /// Allocates a new image. If `width` and `height` are constant, try using [`make`].
/// ///
/// # Panics /// # Panics
/// ///
@ -417,7 +456,7 @@ impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
/// helper macro for defining the save() method. /// helper macro for defining the save() method.
macro_rules! save { macro_rules! save {
($channels:literal == $clr:ident ($clrhuman:literal)) => { ($channels:literal == $clr:ident ($clrhuman:literal)) => {
impl<T: std::ops::Deref<Target = [u8]>> Image<T, $channels> { impl<T: AsRef<[u8]>> Image<T, $channels> {
#[cfg(feature = "save")] #[cfg(feature = "save")]
#[doc = "Save this "] #[doc = "Save this "]
#[doc = $clrhuman] #[doc = $clrhuman]
@ -436,7 +475,7 @@ macro_rules! save {
(0.15000, 0.06000), (0.15000, 0.06000),
)); ));
let mut writer = enc.write_header().unwrap(); let mut writer = enc.write_header().unwrap();
writer.write_image_data(&self.buffer).unwrap(); writer.write_image_data(self.buffer.as_ref()).unwrap();
} }
} }
}; };

View file

@ -2,7 +2,6 @@
use crate::cloner::ImageCloner; use crate::cloner::ImageCloner;
use super::{assert_unchecked, Image}; use super::{assert_unchecked, Image};
use std::ops::{Deref, DerefMut};
use std::simd::{simd_swizzle, Simd, SimdInt, SimdPartialOrd}; use std::simd::{simd_swizzle, Simd, SimdInt, SimdPartialOrd};
/// Trait for layering a image ontop of another, with a offset to the second image. /// Trait for layering a image ontop of another, with a offset to the second image.
@ -100,7 +99,7 @@ unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) {
} }
} }
impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> Overlay<Image<U, 4>> for Image<T, 4> { impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> Overlay<Image<U, 4>> for Image<T, 4> {
#[inline] #[inline]
unsafe fn overlay(&mut self, with: &Image<U, 4>) -> &mut Self { unsafe fn overlay(&mut self, with: &Image<U, 4>) -> &mut Self {
debug_assert!(self.width() == with.width()); debug_assert!(self.width() == with.width());
@ -108,7 +107,8 @@ impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> Overlay<Image<U, 4>> f
for (i, other_pixels) in with.chunked().enumerate() { for (i, other_pixels) in with.chunked().enumerate() {
if other_pixels[3] >= 128 { if other_pixels[3] >= 128 {
// SAFETY: outside are bounds of index from slice // SAFETY: outside are bounds of index from slice
let own_pixels = unsafe { self.buffer.get_unchecked_mut(i * 4..i * 4 + 4) }; let own_pixels =
unsafe { self.buffer.as_mut().get_unchecked_mut(i * 4..i * 4 + 4) };
own_pixels.copy_from_slice(other_pixels); own_pixels.copy_from_slice(other_pixels);
} }
} }
@ -127,7 +127,7 @@ impl ClonerOverlay<4, 4> for ImageCloner<'_, 4> {
} }
} }
impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 4>> for Image<T, 3> { impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 4>> for Image<T, 3> {
#[inline] #[inline]
unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self { unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self {
// SAFETY: caller upholds this // SAFETY: caller upholds this
@ -142,9 +142,9 @@ impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 4>>
+ with.width() as usize) + with.width() as usize)
* 3; * 3;
// SAFETY: index is in bounds // SAFETY: index is in bounds
let rgb = unsafe { self.buffer.get_unchecked_mut(o_x) }; let rgb = unsafe { self.buffer.as_mut().get_unchecked_mut(o_x) };
// SAFETY: bounds are outside index // SAFETY: bounds are outside index
let rgba = unsafe { with.buffer.get_unchecked(i_x) }; let rgba = unsafe { with.buffer.as_ref().get_unchecked(i_x) };
// SAFETY: arguments are 🟢 // SAFETY: arguments are 🟢
unsafe { blit(rgb, rgba) } unsafe { blit(rgb, rgba) }
} }
@ -163,7 +163,7 @@ impl ClonerOverlayAt<4, 3> for ImageCloner<'_, 3> {
} }
} }
impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 3>> for Image<T, 3> { impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 3>> for Image<T, 3> {
/// Overlay a RGB image(with) => self at coordinates x, y. /// Overlay a RGB image(with) => self at coordinates x, y.
/// As this is a `RGBxRGB` operation, blending is unnecessary, /// As this is a `RGBxRGB` operation, blending is unnecessary,
/// and this is simply a copy. /// and this is simply a copy.
@ -182,12 +182,12 @@ impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 3>>
..((j + y as usize) * self.width() as usize + x as usize + ($n as usize)) ..((j + y as usize) * self.width() as usize + x as usize + ($n as usize))
* 3; * 3;
// <= because ".." range // <= because ".." range
debug_assert!(o_x.end <= self.buffer().len()); debug_assert!(o_x.end <= self.buffer().as_ref().len());
debug_assert!(i_x.end <= with.buffer().len()); debug_assert!(i_x.end <= with.buffer().as_ref().len());
// SAFETY: bounds are ✅ // SAFETY: bounds are ✅
let a = unsafe { self.buffer.get_unchecked_mut(o_x) }; let a = unsafe { self.buffer.as_mut().get_unchecked_mut(o_x) };
// SAFETY: we are in ⬜! // SAFETY: we are in ⬜!
let b = unsafe { with.buffer.get_unchecked(i_x) }; let b = unsafe { with.buffer.as_ref().get_unchecked(i_x) };
a.copy_from_slice(b); a.copy_from_slice(b);
} }
}}; }};
@ -202,19 +202,20 @@ impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 3>>
} }
} }
impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> Overlay<Image<U, 4>> for Image<T, 3> { impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> Overlay<Image<U, 4>> for Image<T, 3> {
#[inline] #[inline]
unsafe fn overlay(&mut self, with: &Image<U, 4>) -> &mut Self { unsafe fn overlay(&mut self, with: &Image<U, 4>) -> &mut Self {
debug_assert!(self.width() == with.width()); debug_assert!(self.width() == with.width());
debug_assert!(self.height() == with.height()); debug_assert!(self.height() == with.height());
for (i, chunk) in with for (i, chunk) in with
.buffer .buffer
.as_ref()
.chunks_exact(with.width() as usize * 4) .chunks_exact(with.width() as usize * 4)
.enumerate() .enumerate()
{ {
// SAFETY: all the bounds are good // SAFETY: all the bounds are good
let rgb = unsafe { let rgb = unsafe {
self.buffer.get_unchecked_mut( self.buffer.as_mut().get_unchecked_mut(
i * with.width() as usize * 3..(i + 1) * with.width() as usize * 3, i * with.width() as usize * 3..(i + 1) * with.width() as usize * 3,
) )
}; };
@ -236,7 +237,7 @@ impl ClonerOverlay<4, 3> for ImageCloner<'_, 3> {
} }
} }
impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 4>> for Image<T, 4> { impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 4>> for Image<T, 4> {
#[inline] #[inline]
unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self { unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self {
for j in 0..with.height() { for j in 0..with.height() {