mod error;
pub use error::CopyError;
#[cfg(test)]
mod tests;
#[cfg(feature = "padding_api")]
use core::mem::MaybeUninit;
mod aligned;
use aligned::AlignedData;
mod geometry;
pub use geometry::{PlaneGeometry, SubsamplingError};
use crate::pixel::Pixel;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Plane<T> {
pub(crate) data: AlignedData<T>,
pub(crate) geometry: PlaneGeometry,
}
impl<T> Plane<T> {
#[inline]
#[must_use]
pub fn width(&self) -> usize {
self.geometry.width()
}
#[inline]
#[must_use]
pub fn height(&self) -> usize {
self.geometry.height()
}
}
#[cfg(feature = "padding_api")]
impl<T> Plane<T> {
#[inline]
#[must_use]
pub fn new_uninit(geometry: PlaneGeometry) -> Plane<MaybeUninit<T>> {
let pixels = geometry.alloc_size();
Plane {
data: AlignedData::new_uninit(pixels),
geometry,
}
}
#[inline]
#[must_use]
pub fn geometry(&self) -> PlaneGeometry {
self.geometry
}
#[inline]
#[must_use]
pub fn data(&self) -> &[T] {
&self.data
}
#[inline]
#[must_use]
pub fn data_mut(&mut self) -> &mut [T] {
&mut self.data
}
}
#[cfg(feature = "padding_api")]
impl<T> Plane<MaybeUninit<T>> {
#[inline]
#[must_use]
pub unsafe fn assume_init(self) -> Plane<T> {
let data = unsafe { self.data.assume_init() };
Plane {
data,
geometry: self.geometry,
}
}
}
impl<T: Pixel> Plane<T> {
pub(crate) fn new(geometry: PlaneGeometry) -> Self {
let pixels = geometry.alloc_size();
Self {
data: AlignedData::new(pixels),
geometry,
}
}
#[inline]
#[must_use]
pub fn row(&self, y: usize) -> Option<&[T]> {
self.rows().nth(y)
}
#[inline]
#[must_use]
pub fn row_mut(&mut self, y: usize) -> Option<&mut [T]> {
self.rows_mut().nth(y)
}
#[inline]
#[must_use]
pub fn rows(&self) -> impl DoubleEndedIterator<Item = &[T]> + ExactSizeIterator {
self.data
.chunks_exact(self.geometry.stride())
.skip(self.geometry.pad_top())
.take(self.geometry.height())
.map(|row| {
let start_idx = self.geometry.pad_left();
let end_idx = start_idx + self.geometry.width();
unsafe { row.get_unchecked(start_idx..end_idx) }
})
}
#[inline]
pub fn rows_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut [T]> + ExactSizeIterator {
self.data
.chunks_exact_mut(self.geometry.stride())
.skip(self.geometry.pad_top())
.take(self.geometry.height())
.map(|row| {
let start_idx = self.geometry.pad_left();
let end_idx = start_idx + self.geometry.width();
unsafe { row.get_unchecked_mut(start_idx..end_idx) }
})
}
#[inline]
#[must_use]
pub fn pixel(&self, x: usize, y: usize) -> Option<T> {
let index = self.geometry.data_origin() + self.geometry.stride() * y + x;
self.data.get(index).copied()
}
#[inline]
pub fn pixel_mut(&mut self, x: usize, y: usize) -> Option<&mut T> {
let index = self.geometry.data_origin() + self.geometry.stride() * y + x;
self.data.get_mut(index)
}
#[inline]
#[must_use]
pub fn pixels(&self) -> impl DoubleEndedIterator<Item = T> + ExactSizeIterator {
let total = self.width() * self.height();
ExactSizeWrapper {
iter: self.rows().flatten().copied(),
len: total,
}
}
#[inline]
pub fn pixels_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut T> + ExactSizeIterator {
let total = self.width() * self.height();
ExactSizeWrapper {
iter: self.rows_mut().flatten(),
len: total,
}
}
#[inline]
#[must_use]
pub fn byte_data(&self) -> impl DoubleEndedIterator<Item = u8> + ExactSizeIterator {
let byte_width = size_of::<T>();
assert!(
byte_width <= 2,
"unsupported pixel byte width: {byte_width}"
);
let total = self.width() * self.height() * byte_width;
ExactSizeWrapper {
iter: self
.pixels()
.flat_map(move |pix| pix.into().to_le_bytes().into_iter().take(byte_width)),
len: total,
}
}
#[inline]
pub fn copy_from_slice(&mut self, src: &[T]) -> Result<(), CopyError> {
let width = self.width();
let pixel_count = width * self.height();
if pixel_count != src.len() {
return Err(CopyError::DataLength {
expected: pixel_count,
found: src.len(),
});
}
for (dst_row, src_row) in self.rows_mut().zip(src.chunks_exact(width)) {
dst_row.copy_from_slice(src_row);
}
Ok(())
}
#[inline]
pub fn copy_from_u8_slice(&mut self, src: &[u8]) -> Result<(), CopyError> {
self.copy_from_u8_slice_with_stride(src, self.width() * size_of::<T>())
}
#[inline]
pub fn copy_from_u8_slice_with_stride(
&mut self,
src: &[u8],
stride: usize,
) -> Result<(), CopyError> {
let byte_width = size_of::<T>();
assert!(
byte_width <= 2,
"unsupported pixel byte width: {byte_width}"
);
if stride < self.width() {
return Err(CopyError::InvalidStride {
stride,
width: self.width(),
});
}
let byte_count = stride * self.height();
if byte_count != src.len() {
return Err(CopyError::DataLength {
expected: byte_count,
found: src.len(),
});
}
let width = self.width();
if byte_width == 1 {
for (row_idx, dest_row) in self.rows_mut().enumerate() {
let src_offset = row_idx * stride;
let src_row = &src[src_offset..src_offset + width];
let src_row_typed = unsafe { &*(src_row as *const [u8] as *const [T]) };
dest_row.copy_from_slice(src_row_typed);
}
} else {
let row_byte_width = width * byte_width;
for (row_idx, dest_row) in self.rows_mut().enumerate() {
let src_offset = row_idx * stride;
let src_row = &src[src_offset..src_offset + row_byte_width];
for (dest_pixel, src_chunk) in dest_row.iter_mut().zip(src_row.chunks_exact(2)) {
let bytes =
unsafe { [*src_chunk.get_unchecked(0), *src_chunk.get_unchecked(1)] };
let dest = unsafe { &mut *(dest_pixel as *mut T as *mut u16) };
*dest = u16::from_le_bytes(bytes);
}
}
}
Ok(())
}
}
struct ExactSizeWrapper<I> {
iter: I,
len: usize,
}
impl<I: Iterator> Iterator for ExactSizeWrapper<I> {
type Item = I::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if let Some(item) = self.iter.next() {
self.len = self.len.saturating_sub(1);
Some(item)
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.len, Some(self.len))
}
}
impl<I: DoubleEndedIterator> DoubleEndedIterator for ExactSizeWrapper<I> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
if let Some(item) = self.iter.next_back() {
self.len = self.len.saturating_sub(1);
Some(item)
} else {
None
}
}
}
impl<I: Iterator> ExactSizeIterator for ExactSizeWrapper<I> {
#[inline]
fn len(&self) -> usize {
self.len
}
}