use crate::texels::{MaxAligned, TexelRange};
use crate::{AsTexel, Texel};
use ::alloc::boxed::Box;
use core::{alloc, cmp};
mod matrix;
mod planar;
mod relocated;
mod upsampling;
use crate::image::{Coord, ImageMut, ImageRef};
pub use crate::stride::{BadStrideError, StrideSpec, StridedBytes, StridedLayout, Strides};
pub use matrix::{Matrix, MatrixBytes, MatrixLayout};
pub use planar::{PlaneBytes, PlaneMatrices, Planes};
pub(crate) use upsampling::Yuv420p;
pub struct Bytes(pub usize);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, Hash)]
pub struct TexelLayout {
size: usize,
align: usize,
}
pub trait Layout {
fn byte_len(&self) -> usize;
}
impl dyn Layout + '_ {
#[inline]
pub fn fits_buf(&self, bytes: &crate::buf::buf) -> bool {
self.byte_len() <= bytes.as_bytes().len()
}
#[inline]
pub fn fits_atomic_buf(&self, bytes: &crate::buf::atomic_buf) -> bool {
self.byte_len() <= bytes.len()
}
#[inline]
pub fn fits_cell_buf(&self, bytes: &crate::buf::cell_buf) -> bool {
self.byte_len() <= bytes.len()
}
}
pub trait Decay<T>: Layout {
fn decay(from: T) -> Self;
}
impl<T: Layout> Decay<T> for Bytes {
fn decay(from: T) -> Bytes {
Bytes(from.byte_len())
}
}
pub trait Mend<From> {
type Into: Layout;
fn mend(self, from: &From) -> Self::Into;
}
pub trait TryMend<From> {
type Into: Layout;
type Err;
fn try_mend(self, from: &From) -> Result<Self::Into, Self::Err>;
}
pub trait Take: Layout {
fn take(&mut self) -> Self;
}
pub trait SliceLayout: Layout {
type Sample;
fn sample(&self) -> Texel<Self::Sample>;
fn len(&self) -> usize {
self.byte_len() / self.sample().size()
}
fn as_index(&self) -> TexelRange<Self::Sample> {
self.sample()
.to_range(0..self.len())
.expect("A layout should fit into memory")
}
}
impl<T> dyn SliceLayout<Sample = T> {}
pub trait Raster<Pixel>: Layout + Sized {
fn dimensions(&self) -> Coord;
fn get(from: ImageRef<&Self>, at: Coord) -> Option<Pixel>;
}
pub trait RasterMut<Pixel>: Raster<Pixel> {
fn put(into: ImageMut<&mut Self>, at: Coord, val: Pixel);
fn shade(mut image: ImageMut<&mut Self>, mut f: impl FnMut(u32, u32, &mut Pixel)) {
let Coord(bx, by) = image.layout().dimensions();
for y in 0..by {
for x in 0..bx {
let mut pixel = Self::get(image.as_ref().as_deref(), Coord(x, y)).unwrap();
f(x, y, &mut pixel);
Self::put(image.as_mut().as_deref_mut(), Coord(x, y), pixel);
}
}
}
}
pub trait PlaneOf<L: ?Sized> {
type Plane: Layout;
fn get_plane(self, layout: &L) -> Option<Self::Plane>;
}
pub trait Relocate: Layout {
fn byte_offset(&self) -> usize;
fn relocate(&mut self, offset: AlignedOffset);
fn relocate_to_byte(&mut self, offset: usize) -> bool {
if let Some(aligned_offset) = AlignedOffset::new(offset) {
self.relocate(aligned_offset);
true
} else {
false
}
}
fn byte_range(&self) -> core::ops::Range<usize> {
let start = self.byte_offset();
let end = self.byte_len();
debug_assert!(
start <= end,
"The length calculation of this layout is buggy"
);
start..end.min(start)
}
fn texel_range(&self) -> TexelRange<Self::Sample>
where
Self: SliceLayout + Sized,
{
TexelRange::from_byte_range(self.sample(), self.byte_offset()..self.byte_len())
.expect("A layout should fit into memory")
}
}
impl dyn Relocate {}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct AlignedOffset(usize);
impl AlignedOffset {
const ALIGN: usize = core::mem::align_of::<MaxAligned>();
pub fn new(offset: usize) -> Option<Self> {
if offset % Self::ALIGN == 0 && offset <= isize::MAX as usize {
Some(AlignedOffset(offset))
} else {
None
}
}
pub fn get(self) -> usize {
self.0
}
#[must_use]
pub fn next_up(self, bytes: usize) -> Option<Self> {
let range_start = self.0.checked_add(bytes)?;
let new_offset = range_start.checked_next_multiple_of(Self::ALIGN)?;
if new_offset > isize::MAX as usize {
return None;
}
AlignedOffset::new(new_offset)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) struct DynLayout {
pub(crate) repr: LayoutRepr,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub(crate) enum LayoutRepr {
Matrix(MatrixBytes),
Yuv420p(Yuv420p),
}
#[derive(Debug, Default, PartialEq, Eq, Hash)]
pub struct MismatchedPixelError {
_private: (),
}
impl Bytes {
pub fn from_layout(layout: impl Layout) -> Self {
Bytes(layout.byte_len())
}
}
impl TexelLayout {
pub fn from_pixel<P: AsTexel>() -> Self {
let pix = P::texel();
TexelLayout {
size: pix.size(),
align: pix.align(),
}
}
pub const MAX_SIZE: Self = {
TexelLayout {
size: isize::MAX as usize,
align: 1,
}
};
pub fn with_layout(layout: alloc::Layout) -> Option<Self> {
if layout.align() > MaxAligned::texel().align() {
return None;
}
if layout.size() % layout.align() != 0 {
return None;
}
Some(TexelLayout {
size: layout.size(),
align: layout.align(),
})
}
pub fn layout(self) -> alloc::Layout {
alloc::Layout::from_size_align(self.size, self.align).expect("Valid layout")
}
#[must_use = "This does not modify `self`."]
pub fn packed(self, align: usize) -> TexelLayout {
assert!(align.is_power_of_two());
let align = self.align.min(align);
TexelLayout { align, ..self }
}
#[must_use = "This does not modify `self`."]
pub fn infimum(self, other: Self) -> TexelLayout {
TexelLayout {
size: self.size.min(other.size),
align: self.align.min(other.align),
}
}
pub const fn size(self) -> usize {
self.size
}
pub const fn align(self) -> usize {
self.size
}
pub const fn superset_of(&self, other: TexelLayout) -> bool {
self.size >= other.size && self.align >= other.align
}
}
impl<T> From<Texel<T>> for TexelLayout {
fn from(texel: Texel<T>) -> Self {
TexelLayout {
size: texel.size(),
align: texel.align(),
}
}
}
impl DynLayout {
pub fn byte_len(&self) -> usize {
match self.repr {
LayoutRepr::Matrix(matrix) => matrix.byte_len(),
LayoutRepr::Yuv420p(matrix) => matrix.byte_len(),
}
}
}
impl Layout for Bytes {
fn byte_len(&self) -> usize {
self.0
}
}
impl<'lt, T: Layout + ?Sized> Layout for &'lt T {
fn byte_len(&self) -> usize {
(**self).byte_len()
}
}
impl<'lt, T: Layout + ?Sized> Layout for &'lt mut T {
fn byte_len(&self) -> usize {
(**self).byte_len()
}
}
impl Take for Bytes {
fn take(&mut self) -> Self {
Bytes(core::mem::take(&mut self.0))
}
}
impl Layout for DynLayout {
fn byte_len(&self) -> usize {
DynLayout::byte_len(self)
}
}
impl<T> SliceLayout for &'_ T
where
T: SliceLayout,
{
type Sample = T::Sample;
fn sample(&self) -> Texel<Self::Sample> {
(**self).sample()
}
}
impl<T> SliceLayout for &'_ mut T
where
T: SliceLayout,
{
type Sample = T::Sample;
fn sample(&self) -> Texel<Self::Sample> {
(**self).sample()
}
}
impl<L: Layout + ?Sized> Layout for Box<L> {
fn byte_len(&self) -> usize {
(**self).byte_len()
}
}
impl<L: Layout> Decay<L> for Box<L> {
fn decay(from: L) -> Box<L> {
Box::new(from)
}
}
impl cmp::PartialOrd for TexelLayout {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
if self.size == other.size && self.align == other.align {
Some(cmp::Ordering::Equal)
} else if self.size <= other.size && self.align <= other.align {
Some(cmp::Ordering::Less)
} else if self.size >= other.size && self.align >= other.align {
Some(cmp::Ordering::Greater)
} else {
None
}
}
}
macro_rules! bytes_from_layout {
($layout:path) => {
impl From<$layout> for Bytes {
fn from(layout: $layout) -> Self {
Bytes::from_layout(layout)
}
}
};
(<$($bound:ident),*> $layout:ident) => {
impl<$($bound),*> From<$layout <$($bound),*>> for Bytes {
fn from(layout: $layout <$($bound),*>) -> Self {
Bytes::from_layout(layout)
}
}
};
}
bytes_from_layout!(DynLayout);
bytes_from_layout!(MatrixBytes);
bytes_from_layout!(<P> Matrix);
impl From<MatrixBytes> for DynLayout {
fn from(matrix: MatrixBytes) -> Self {
DynLayout {
repr: LayoutRepr::Matrix(matrix),
}
}
}
impl From<Yuv420p> for DynLayout {
fn from(matrix: Yuv420p) -> Self {
DynLayout {
repr: LayoutRepr::Yuv420p(matrix),
}
}
}
impl<P, L> PlaneOf<&'_ L> for P
where
P: PlaneOf<L>,
{
type Plane = <P as PlaneOf<L>>::Plane;
fn get_plane(self, layout: &&L) -> Option<Self::Plane> {
<P as PlaneOf<L>>::get_plane(self, *layout)
}
}
impl<P, L> PlaneOf<&'_ mut L> for P
where
P: PlaneOf<L>,
{
type Plane = <P as PlaneOf<L>>::Plane;
fn get_plane(self, layout: &&mut L) -> Option<Self::Plane> {
<P as PlaneOf<L>>::get_plane(self, *layout)
}
}