use crate::buf::{atomic_buf, AtomicBuffer, AtomicSliceRef};
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};
#[derive(Clone)]
pub struct AtomicImage<Layout = Bytes> {
inner: RawImage<AtomicBuffer, Layout>,
}
#[derive(Clone, PartialEq, Eq)]
pub struct AtomicImageRef<'buf, Layout = &'buf Bytes> {
inner: RawImage<&'buf atomic_buf, Layout>,
}
impl<L: Layout> AtomicImage<L> {
pub fn new(layout: L) -> Self {
RawImage::<AtomicBuffer, 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, AtomicBuffer::from(buffer)).into()
}
pub fn try_with_layout<M>(self, layout: M) -> Result<AtomicImage<M>, Self>
where
M: Layout,
{
self.inner
.try_reinterpret(layout)
.map(Into::into)
.map_err(Into::into)
}
pub fn checked_decay<M>(self) -> Option<AtomicImage<M>>
where
M: Decay<L>,
M: Layout,
{
Some(self.inner.checked_decay()?.into())
}
pub fn take(&mut self) -> AtomicImage<L>
where
L: Take,
{
self.inner.take().into()
}
pub fn mend<Item>(self, mend: Item) -> AtomicImage<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<AtomicImage<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> AtomicImage<L> {
pub fn fits(&self, layout: &impl Layout) -> bool {
self.inner.fits(layout)
}
pub fn ptr_eq(&self, other: &Self) -> bool {
AtomicBuffer::ptr_eq(self.inner.get(), other.inner.get())
}
pub fn compare(&self) -> impl core::cmp::Eq + core::cmp::PartialEq + '_
where
L: core::cmp::Eq,
{
(self.inner.layout(), self.inner.get())
}
pub fn as_capacity_atomic_buf(&self) -> &atomic_buf {
self.inner.as_capacity_atomic_buf()
}
pub fn get_mut(&mut self) -> Option<&mut atomic_buf> {
self.inner.get_mut().get_mut()
}
pub fn make_mut(&mut self) -> &mut atomic_buf {
self.inner.get_mut().make_mut()
}
pub fn as_texels<P>(&self, texel: Texel<P>) -> AtomicSliceRef<'_, P>
where
L: Layout,
{
self.as_ref().into_texels(texel)
}
pub fn as_slice(&self) -> AtomicSliceRef<'_, 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) -> AtomicImageRef<'_, &'_ L> {
self.inner.as_deref().into()
}
pub fn checked_to_ref<M: Layout>(&self, layout: M) -> Option<AtomicImageRef<'_, M>> {
self.as_ref().checked_with_layout(layout)
}
}
impl<'data, L> AtomicImageRef<'data, L> {
pub fn layout(&self) -> &L {
self.inner.layout()
}
pub fn as_ref(&self) -> AtomicImageRef<'_, &'_ L> {
self.inner.as_deref().into()
}
pub fn fits(&self, other: &impl Layout) -> bool {
<dyn Layout>::fits_atomic_buf(other, self.inner.as_capacity_atomic_buf())
}
pub fn checked_with_layout<M>(self, layout: M) -> Option<AtomicImageRef<'data, M>>
where
M: Layout,
{
Some(self.inner.try_reinterpret(layout).ok()?.into())
}
pub fn checked_decay<M>(self) -> Option<AtomicImageRef<'data, M>>
where
M: Decay<L>,
M: Layout,
{
Some(self.inner.checked_decay()?.into())
}
pub fn as_slice(&self) -> AtomicSliceRef<'_, L::Sample>
where
L: SliceLayout,
{
self.as_texels(self.inner.layout().sample())
}
pub fn as_texels<P>(&self, pixel: Texel<P>) -> AtomicSliceRef<'_, P>
where
L: Layout,
{
let byte_len = self.inner.layout().byte_len();
let buf = self.inner.as_capacity_atomic_buf();
buf.as_texels(pixel).truncate_bytes(byte_len)
}
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];
U8.load_atomic_slice(buffer.as_texels(U8).truncate_bytes(len), &mut target);
target
}
pub fn into_slice(self) -> AtomicSliceRef<'data, L::Sample>
where
L: SliceLayout,
{
let sample = self.inner.layout().sample();
self.into_texels(sample)
}
pub fn into_texels<P>(self, pixel: Texel<P>) -> AtomicSliceRef<'data, P>
where
L: Layout,
{
let (buffer, layout) = self.inner.into_parts();
let byte_len = layout.byte_len();
buffer.as_texels(pixel).truncate_bytes(byte_len)
}
pub fn split_layout(&mut self) -> AtomicImageRef<'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), atomic_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<[AtomicImageRef<'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 = atomic_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<AtomicBuffer, L>> for AtomicImage<L> {
fn from(image: RawImage<AtomicBuffer, L>) -> Self {
AtomicImage { inner: image }
}
}
impl<'lt, L> From<RawImage<&'lt atomic_buf, L>> for AtomicImageRef<'lt, L> {
fn from(image: RawImage<&'lt atomic_buf, L>) -> Self {
AtomicImageRef { inner: image }
}
}