use crate::color::convert::{ConvertFrom, ConvertInto};
use crate::color::{Color, Zero};
use crate::image::{Dimensions, Image, ImageMut};
pub trait AsTyped {
type Pixel: Color;
fn as_typed(&self) -> &[Self::Pixel];
}
pub trait AsTypedMut {
type Pixel: Color;
fn as_typed_mut(&mut self) -> &mut [Self::Pixel];
}
#[derive(Clone, Debug)]
pub struct RawPixBuf<T> {
width: usize,
height: usize,
buf: Box<[T]>,
}
impl<T> RawPixBuf<T> {
pub fn new(width: usize, height: usize) -> Self
where
T: Zero,
{
let buf = {
let buf = vec![const { T::ZERO }; width * height];
buf.into_boxed_slice()
};
RawPixBuf { width, height, buf }
}
pub fn new_from_dims<D: Dimensions>(dims: &D) -> Self
where
T: Zero,
{
let (width, height) = dims.dimensions();
Self::new(width, height)
}
#[inline]
pub fn from_vec(width: usize, height: usize, buf: Vec<u8>) -> Result<Self, Vec<u8>> {
let slice = buf.into_boxed_slice();
Self::from_boxed_slice(width, height, slice).map_err(Vec::from)
}
pub fn from_boxed_slice(
width: usize,
height: usize,
buf: Box<[u8]>,
) -> Result<Self, Box<[u8]>> {
let expected_len = width * height * std::mem::size_of::<T>();
if buf.len() != expected_len
|| !(buf.as_ptr() as usize).is_multiple_of(std::mem::align_of::<T>())
{
return Err(buf);
}
#[allow(clippy::cast_slice_from_raw_parts)]
let buf = unsafe {
let ptr: *mut T = Box::into_raw(buf) as _;
Box::from_raw(std::slice::from_raw_parts_mut(ptr, width * height))
};
Ok(RawPixBuf { width, height, buf })
}
}
impl<T> RawPixBuf<T> {
#[inline]
pub fn into_pixels(self) -> Vec<T> {
self.buf.into_vec()
}
}
impl<C: Color> AsTyped for RawPixBuf<C> {
type Pixel = C;
#[inline]
fn as_typed(&self) -> &[C] {
self.buf.as_ref()
}
}
impl<C: Color> AsTypedMut for RawPixBuf<C> {
type Pixel = C;
#[inline]
fn as_typed_mut(&mut self) -> &mut [C] {
self.buf.as_mut()
}
}
impl<T> AsRef<[u8]> for RawPixBuf<T> {
#[inline]
fn as_ref(&self) -> &[u8] {
unsafe {
let len = self.buf.len() * std::mem::size_of::<T>();
let ptr: *const u8 = self.buf.as_ptr() as _;
std::slice::from_raw_parts(ptr, len)
}
}
}
impl<T> AsMut<[u8]> for RawPixBuf<T> {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
unsafe {
let len = self.buf.len() * std::mem::size_of::<T>();
let ptr: *mut u8 = self.buf.as_mut_ptr() as _;
std::slice::from_raw_parts_mut(ptr, len)
}
}
}
impl<T> Dimensions for RawPixBuf<T> {
#[inline]
fn width(&self) -> usize {
self.width
}
#[inline]
fn height(&self) -> usize {
self.height
}
}
impl<C: Copy + Color> Image for RawPixBuf<C> {
type Pixel = C;
#[inline]
fn color_get(&self, x: usize, y: usize) -> C {
let width = self.width();
let buffer = self.as_typed();
buffer[y * width + x]
}
}
impl<C: Color> ImageMut for RawPixBuf<C> {
type Pixel = C;
#[inline]
fn color_set<P, ColorSpecialized>(&mut self, x: usize, y: usize, color: P)
where
P: ConvertInto<C, ColorSpecialized> + Color,
{
let width = self.width();
let buffer = self.as_typed_mut();
let color: C = color.convert_into();
buffer[y * width + x] = color;
}
}
impl<C1, C2> From<&RawPixBuf<C1>> for RawPixBuf<C2>
where
C1: Color + Copy,
C2: Color + Zero + ConvertFrom<C1>,
RawPixBuf<C1>: Dimensions,
{
fn from(buffer: &RawPixBuf<C1>) -> RawPixBuf<C2> {
let (width, height) = buffer.dimensions();
let mut new_buffer = RawPixBuf::new(width, height);
for y in 0..height {
for x in 0..width {
new_buffer.color_set(x, y, buffer.color_get(x, y));
}
}
new_buffer
}
}