use crate::buf::{cell_buf, CellBuffer};
use crate::image::{raw::RawImage, IntoPlanesError};
use crate::layout::{Bytes, Decay, Layout, Mend, PlaneOf, Relocate, SliceLayout, Take, TryMend};
use crate::texel::{constants::U8, MAX_ALIGN};
use crate::{Texel, TexelBuffer};
use core::cell::Cell;
#[derive(Clone, PartialEq, Eq)]
pub struct CellImage<Layout = Bytes> {
inner: RawImage<CellBuffer, Layout>,
}
#[derive(Clone, PartialEq, Eq)]
pub struct CellImageRef<'buf, Layout = &'buf Bytes> {
inner: RawImage<&'buf cell_buf, Layout>,
}
impl<L: Layout> CellImage<L> {
pub fn new(layout: L) -> Self {
RawImage::<CellBuffer, L>::new(layout).into()
}
pub fn with_bytes(layout: L, bytes: &[u8]) -> Self {
RawImage::with_contents(bytes, layout).into()
}
pub fn with_buffer<T>(layout: L, bytes: TexelBuffer<T>) -> Self {
let (buffer, layout) = RawImage::from_buffer(Bytes(0), bytes.into_inner())
.with_layout(layout)
.into_parts();
RawImage::from_buffer(layout, CellBuffer::from(buffer)).into()
}
pub fn try_with_layout<M>(self, layout: M) -> Result<CellImage<M>, Self>
where
M: Layout,
{
self.inner
.try_reinterpret(layout)
.map(Into::into)
.map_err(Into::into)
}
pub fn checked_decay<M>(self) -> Option<CellImage<M>>
where
M: Decay<L>,
M: Layout,
{
Some(self.inner.checked_decay()?.into())
}
pub fn take(&mut self) -> CellImage<L>
where
L: Take,
{
self.inner.take().into()
}
pub fn mend<Item>(self, mend: Item) -> CellImage<Item::Into>
where
Item: Mend<L>,
L: Take,
{
let new_layout = mend.mend(self.inner.layout());
self.inner.mogrify_layout(|_| new_layout).into()
}
pub fn try_mend<Item>(&mut self, mend: Item) -> Result<CellImage<Item::Into>, Item::Err>
where
Item: TryMend<L>,
L: Take,
{
let new_layout = mend.try_mend(self.inner.layout())?;
Ok(self.inner.take().mogrify_layout(|_| new_layout).into())
}
}
impl<L> CellImage<L> {
pub fn fits(&self, layout: &impl Layout) -> bool {
self.inner.fits(layout)
}
pub fn ptr_eq(&self, other: &Self) -> bool {
CellBuffer::ptr_eq(self.inner.get(), other.inner.get())
}
pub fn as_capacity_cell_buf(&self) -> &cell_buf {
self.inner.as_capacity_cell_buf()
}
pub fn get_mut(&mut self) -> Option<&mut cell_buf> {
self.inner.get_mut().get_mut()
}
pub fn make_mut(&mut self) -> &mut cell_buf {
self.inner.get_mut().make_mut()
}
pub fn as_texels<P>(&self, texel: Texel<P>) -> &'_ Cell<[P]>
where
L: Layout,
{
self.as_ref().into_texels(texel)
}
pub fn as_slice(&self) -> &'_ Cell<[L::Sample]>
where
L: SliceLayout,
{
self.as_ref().into_slice()
}
pub fn layout(&self) -> &L {
self.inner.layout()
}
pub fn layout_mut_unguarded(&mut self) -> &mut L {
self.inner.layout_mut_unguarded()
}
pub fn as_ref(&self) -> CellImageRef<'_, &'_ L> {
self.inner.as_deref().into()
}
pub fn checked_to_ref<M: Layout>(&self, layout: M) -> Option<CellImageRef<'_, M>> {
self.as_ref().checked_with_layout(layout)
}
}
impl<'data, L> CellImageRef<'data, L> {
pub fn layout(&self) -> &L {
self.inner.layout()
}
pub fn as_ref(&self) -> CellImageRef<'_, &'_ L> {
self.inner.as_deref().into()
}
pub fn fits(&self, other: &impl Layout) -> bool {
self.inner.fits(other)
}
pub fn checked_with_layout<M>(self, layout: M) -> Option<CellImageRef<'data, M>>
where
M: Layout,
{
Some(self.inner.try_reinterpret(layout).ok()?.into())
}
pub fn checked_decay<M>(self) -> Option<CellImageRef<'data, M>>
where
M: Decay<L>,
M: Layout,
{
Some(self.inner.checked_decay()?.into())
}
pub fn as_slice(&self) -> &'_ Cell<[L::Sample]>
where
L: SliceLayout,
{
self.as_texels(self.inner.layout().sample())
}
pub fn as_texels<P>(&self, pixel: Texel<P>) -> &'_ Cell<[P]>
where
L: Layout,
{
self.inner.as_cell_buf().as_texels(pixel)
}
pub fn into_bytes(self) -> alloc::vec::Vec<u8>
where
L: Layout,
{
let (buffer, layout) = self.inner.into_parts();
let len = layout.byte_len();
let mut target = alloc::vec![0; len];
let source = buffer.truncate(len).as_texels(U8);
U8.cell_memory_copy(
source.as_slice_of_cells(),
Cell::from_mut(&mut target[..]).as_slice_of_cells(),
);
target
}
pub fn into_slice(self) -> &'data Cell<[L::Sample]>
where
L: SliceLayout,
{
let sample = self.inner.layout().sample();
self.into_texels(sample)
}
pub fn into_texels<P>(self, pixel: Texel<P>) -> &'data Cell<[P]>
where
L: Layout,
{
let (buffer, layout) = self.inner.into_parts();
let byte_len = layout.byte_len();
buffer.truncate(byte_len).as_texels(pixel)
}
pub fn split_layout(&mut self) -> CellImageRef<'data, Bytes>
where
L: Layout,
{
let size = self.inner.layout().byte_len();
let round_up = size.next_multiple_of(MAX_ALIGN);
let buffer = self.inner.get_mut();
if round_up > buffer.len() {
return RawImage::from_buffer(Bytes(0), cell_buf::new(&[])).into();
}
let (initial, next) = buffer.split_at(round_up);
*buffer = initial;
RawImage::from_buffer(Bytes(next.len()), next).into()
}
pub fn into_planes<const N: usize, D>(
self,
descriptors: [D; N],
) -> Result<[CellImageRef<'data, D::Plane>; N], IntoPlanesError>
where
D: PlaneOf<L>,
D::Plane: Relocate,
{
let layout = self.layout();
let mut planes = descriptors.map(|d| {
let plane = <D as PlaneOf<L>>::get_plane(d, layout);
let empty_buf = cell_buf::new(&[]);
(plane, empty_buf)
});
let (mut buffer, _) = self.inner.into_parts();
for plane in &mut planes {
let Some(layout) = &mut plane.0 else {
continue;
};
let skip_by = layout.byte_offset();
if skip_by % MAX_ALIGN != 0 {
plane.0 = None;
continue;
}
if buffer.len() < skip_by {
plane.0 = None;
continue;
}
layout.relocate(Default::default());
let len = layout.byte_len().div_ceil(MAX_ALIGN) * MAX_ALIGN;
if buffer.len() - skip_by < len {
plane.0 = None;
continue;
}
let (_pre, tail) = buffer.split_at(skip_by);
let (img_buf, _post) = tail.split_at(len);
plane.1 = img_buf;
buffer = tail;
}
let planes = IntoPlanesError::from_array(planes)?;
Ok(planes.map(|(layout, buffer)| RawImage::from_buffer(layout, buffer).into()))
}
}
impl<L> From<RawImage<CellBuffer, L>> for CellImage<L> {
fn from(image: RawImage<CellBuffer, L>) -> Self {
CellImage { inner: image }
}
}
impl<'lt, L> From<RawImage<&'lt cell_buf, L>> for CellImageRef<'lt, L> {
fn from(image: RawImage<&'lt cell_buf, L>) -> Self {
CellImageRef { inner: image }
}
}