mod atomic;
mod cell;
mod raw;
use core::{fmt, ops};
pub(crate) use self::raw::RawImage;
use crate::buf::{buf, Buffer};
use crate::layout::{
Bytes, Decay, Layout, Mend, PlaneOf, Raster, RasterMut, Relocate, SliceLayout, Take, TryMend,
};
use crate::texel::MAX_ALIGN;
use crate::{Texel, TexelBuffer};
pub use crate::stride::{StridedBufferMut, StridedBufferRef};
pub use atomic::{AtomicImage, AtomicImageRef};
pub use cell::{CellImage, CellImageRef};
#[derive(Clone, PartialEq, Eq)]
pub struct Image<Layout = Bytes> {
inner: RawImage<Buffer, Layout>,
}
#[derive(Clone, PartialEq, Eq)]
pub struct ImageRef<'buf, Layout = &'buf Bytes> {
inner: RawImage<&'buf buf, Layout>,
}
#[derive(PartialEq, Eq)]
pub struct ImageMut<'buf, Layout = &'buf mut Bytes> {
inner: RawImage<&'buf mut buf, Layout>,
}
#[allow(dead_code)]
pub struct IntoPlanesError {
index_errors: core::num::NonZeroUsize,
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Coord(pub u32, pub u32);
impl Coord {
pub fn x(self) -> u32 {
self.0
}
pub fn y(self) -> u32 {
self.1
}
pub fn yx(self) -> (u32, u32) {
(self.1, self.0)
}
pub fn xy(self) -> (u32, u32) {
(self.0, self.1)
}
}
impl<L: Layout> Image<L> {
pub fn new(layout: L) -> Self {
RawImage::<Buffer, 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 {
RawImage::from_buffer(Bytes(0), bytes.into_inner())
.with_layout(layout)
.into()
}
pub fn as_bytes(&self) -> &[u8] {
self.inner.as_bytes()
}
pub fn as_bytes_mut(&mut self) -> &mut [u8] {
self.inner.as_bytes_mut()
}
pub fn as_buf(&self) -> &buf {
self.inner.as_buf()
}
pub fn as_mut_buf(&mut self) -> &mut buf {
self.inner.as_mut_buf()
}
pub fn ensure_layout(&mut self) {
self.inner.mutate_layout(|_| ());
}
pub fn with_layout<M>(self, layout: M) -> Image<M>
where
M: Layout,
{
self.inner.with_layout(layout).into()
}
pub fn decay<M>(self) -> Image<M>
where
M: Decay<L>,
M: Layout,
{
self.inner.decay().into()
}
pub fn take(&mut self) -> Image<L>
where
L: Take,
{
self.inner.take().into()
}
pub fn mend<Item>(self, mend: Item) -> Image<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<Image<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> Image<L> {
pub fn fits(&self, other: &impl Layout) -> bool {
self.inner.fits(other)
}
pub fn as_capacity_bytes(&self) -> &[u8] {
self.inner.as_capacity_bytes()
}
pub fn as_capacity_bytes_mut(&mut self) -> &mut [u8] {
self.inner.as_capacity_bytes_mut()
}
pub fn as_capacity_buf(&self) -> &buf {
self.inner.as_capacity_buf()
}
pub fn as_capacity_buf_mut(&mut self) -> &mut buf {
self.inner.as_capacity_buf_mut()
}
pub fn as_texels<P>(&self, pixel: Texel<P>) -> &[P]
where
L: Layout,
{
pixel.cast_buf(self.inner.as_buf())
}
pub fn as_mut_texels<P>(&mut self, pixel: Texel<P>) -> &mut [P]
where
L: Layout,
{
pixel.cast_mut_buf(self.inner.as_mut_buf())
}
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) -> ImageRef<'_, &'_ L> {
self.inner.as_deref().into()
}
pub fn try_to_ref<M: Layout>(&self, layout: M) -> Option<ImageRef<'_, M>> {
self.as_ref().with_layout(layout)
}
pub fn as_mut(&mut self) -> ImageMut<'_, &'_ mut L> {
self.inner.as_deref_mut().into()
}
pub fn to_mut<M: Layout>(&mut self, layout: M) -> ImageMut<'_, M> {
self.inner.as_reinterpreted(layout).into()
}
pub fn try_to_mut<M: Layout>(&mut self, layout: M) -> Option<ImageMut<'_, M>> {
self.as_mut().with_layout(layout)
}
pub fn get_texel<P>(&self, coord: Coord) -> Option<P>
where
L: Raster<P>,
{
L::get(self.as_ref(), coord)
}
pub fn put_texel<P>(&mut self, coord: Coord, texel: P)
where
L: RasterMut<P>,
{
L::put(self.as_mut(), coord, texel)
}
pub fn shade<P>(&mut self, f: impl FnMut(u32, u32, &mut P))
where
L: RasterMut<P>,
{
L::shade(self.as_mut(), f)
}
}
impl<L: SliceLayout> Image<L> {
pub fn from_buffer(buffer: TexelBuffer<L::Sample>, layout: L) -> Self {
assert!(buffer.byte_len() >= layout.byte_len());
RawImage::from_texel_buffer(buffer, layout).into()
}
pub fn as_slice(&self) -> &[L::Sample] {
self.inner.as_slice()
}
pub fn as_mut_slice(&mut self) -> &mut [L::Sample] {
self.inner.as_mut_slice()
}
pub fn into_buffer(self) -> TexelBuffer<L::Sample> {
self.inner.into_buffer()
}
}
impl<'data, L> ImageRef<'data, L> {
pub fn as_bytes(&self) -> &[u8]
where
L: Layout,
{
self.inner.as_bytes()
}
pub fn layout(&self) -> &L {
self.inner.layout()
}
pub fn as_ref(&self) -> ImageRef<'_, &'_ L> {
self.inner.as_deref().into()
}
pub fn fits(&self, other: &impl Layout) -> bool {
self.inner.fits(other)
}
pub fn with_layout<M>(self, layout: M) -> Option<ImageRef<'data, M>>
where
M: Layout,
{
let image = self.inner.try_reinterpret(layout).ok()?;
Some(image.into())
}
pub fn decay<M>(self) -> Option<ImageRef<'data, M>>
where
M: Decay<L>,
M: Layout,
{
Some(self.inner.checked_decay()?.into())
}
pub fn to_owned(&self) -> Image<L>
where
L: Layout + Clone,
{
Image::with_bytes(self.inner.layout().clone(), self.inner.as_bytes())
}
pub fn as_slice(&self) -> &[L::Sample]
where
L: SliceLayout,
{
self.inner.as_slice()
}
pub fn as_texels<P>(&self, pixel: Texel<P>) -> &[P]
where
L: Layout,
{
pixel.cast_buf(self.inner.as_buf())
}
pub fn into_bytes(self) -> &'data [u8]
where
L: Layout,
{
let (visible, layout) = self.inner.into_parts();
visible.truncate(layout.byte_len())
}
pub fn into_slice(self) -> &'data [L::Sample]
where
L: SliceLayout,
{
let (visible, layout) = self.inner.into_parts();
layout.sample().cast_buf(visible)
}
pub fn get_texel<P>(&self, coord: Coord) -> Option<P>
where
L: Raster<P>,
{
L::get(self.as_ref(), coord)
}
pub fn split_layout(&mut self) -> ImageRef<'data, Bytes>
where
L: Layout,
{
let size = self.inner.layout().byte_len();
let round_up = (size.wrapping_neg() & !(MAX_ALIGN - 1)).wrapping_neg();
let buffer = self.inner.get_mut();
if round_up > buffer.len() {
return RawImage::from_buffer(Bytes(0), 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<[ImageRef<'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 = 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<'data, L> ImageMut<'data, L> {
pub fn as_bytes(&self) -> &[u8]
where
L: Layout,
{
self.inner.as_bytes()
}
pub fn as_bytes_mut(&mut self) -> &mut [u8]
where
L: Layout,
{
self.inner.as_bytes_mut()
}
pub fn layout(&self) -> &L {
self.inner.layout()
}
pub fn as_ref(&self) -> ImageRef<'_, &'_ L> {
self.inner.as_deref().into()
}
pub fn as_mut(&mut self) -> ImageMut<'_, &'_ mut L> {
self.inner.as_deref_mut().into()
}
pub fn into_ref(self) -> ImageRef<'data, L> {
let (buffer, layout) = self.inner.into_parts();
RawImage::with_buffer_unchecked(layout, &*buffer).into()
}
pub fn fits(&self, other: &impl Layout) -> bool {
self.inner.fits(other)
}
pub fn with_layout<M>(self, layout: M) -> Option<ImageMut<'data, M>>
where
M: Layout,
{
let image = self.inner.try_reinterpret(layout).ok()?;
Some(image.into())
}
pub fn decay<M>(self) -> Option<ImageMut<'data, M>>
where
M: Decay<L>,
M: Layout,
{
Some(self.inner.checked_decay()?.into())
}
pub fn to_owned(&self) -> Image<L>
where
L: Layout + Clone,
{
Image::with_bytes(self.inner.layout().clone(), self.inner.as_bytes())
}
pub fn as_slice(&self) -> &[L::Sample]
where
L: SliceLayout,
{
self.inner.as_slice()
}
pub fn as_mut_slice(&mut self) -> &mut [L::Sample]
where
L: SliceLayout,
{
self.inner.as_mut_slice()
}
pub fn as_texels<P>(&self, pixel: Texel<P>) -> &[P]
where
L: Layout,
{
pixel.cast_buf(self.inner.as_buf())
}
pub fn as_mut_texels<P>(&mut self, pixel: Texel<P>) -> &mut [P]
where
L: Layout,
{
pixel.cast_mut_buf(self.inner.as_mut_buf())
}
pub fn into_slice(self) -> &'data [L::Sample]
where
L: SliceLayout,
{
let (visible, layout) = self.inner.into_parts();
layout.sample().cast_mut_buf(visible)
}
pub fn into_mut_slice(self) -> &'data mut [L::Sample]
where
L: SliceLayout,
{
let (visible, layout) = self.inner.into_parts();
layout.sample().cast_mut_buf(visible)
}
pub fn get_texel<P>(&self, coord: Coord) -> Option<P>
where
L: Raster<P>,
{
L::get(self.as_ref(), coord)
}
pub fn put_texel<P>(&mut self, coord: Coord, texel: P)
where
L: RasterMut<P>,
{
L::put(self.as_mut(), coord, texel)
}
pub fn shade<P>(&mut self, f: impl FnMut(u32, u32, &mut P))
where
L: RasterMut<P>,
{
L::shade(self.as_mut(), f)
}
pub fn split_layout(&mut self) -> ImageMut<'data, Bytes>
where
L: Layout,
{
let size = self.inner.layout().byte_len();
let round_up = (size.wrapping_neg() & !(MAX_ALIGN - 1)).wrapping_neg();
let buffer = self.inner.get_mut();
let empty = buf::new_mut(&mut []);
if round_up > buffer.len() {
return RawImage::from_buffer(Bytes(0), empty).into();
}
let (initial, next) = core::mem::replace(buffer, empty).split_at_mut(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<[ImageMut<'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 = buf::new_mut(&mut []);
(plane, empty_buf)
});
let mut remap = planes.each_mut().map(|plane| {
let offset = plane.0.as_ref().map_or(0, |p| p.byte_offset());
(offset, plane)
});
remap.sort_by_key(|&(offset, _)| offset);
let mut consumed = 0;
let (mut buffer, _) = self.inner.into_parts();
for (offset, plane) in remap {
let Some(layout) = &mut plane.0 else {
continue;
};
let Some(skip_by) = offset.checked_sub(consumed) else {
plane.0 = None;
continue;
};
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;
}
buffer = buf::take_at_mut(&mut buffer, skip_by);
consumed += skip_by;
let tail = buf::take_at_mut(&mut buffer, len);
consumed += len;
plane.1 = buffer;
buffer = tail;
}
let planes = IntoPlanesError::from_array(planes)?;
Ok(planes.map(|(layout, buffer)| RawImage::from_buffer(layout, buffer).into()))
}
}
impl IntoPlanesError {
pub(crate) fn from_array<L, Buffer, const N: usize>(
items: [(Option<L>, Buffer); N],
) -> Result<[(L, Buffer); N], Self> {
if let Some(index_errors) = {
let count = items.iter().filter(|(l, _)| l.is_none()).count();
core::num::NonZeroUsize::new(count)
} {
return Err(IntoPlanesError { index_errors });
}
Ok(items.map(|(l, b)| (l.unwrap(), b)))
}
}
impl core::fmt::Debug for IntoPlanesError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("IntoPlanesError").finish()
}
}
impl<'data, 'l, L: Layout> ImageRef<'data, &'l L> {
pub(crate) fn as_deref(self) -> ImageRef<'data, &'l L::Target>
where
L: ops::Deref,
L::Target: Layout,
{
self.inner.mogrify_layout(|l| &**l).into()
}
}
impl<'data, 'l, L: Layout> ImageMut<'data, &'l mut L> {
pub(crate) fn as_deref_mut(self) -> ImageMut<'data, &'l mut L::Target>
where
L: ops::DerefMut,
L::Target: Layout,
{
self.inner.mogrify_layout(|l| &mut **l).into()
}
}
impl<'lt, L: Layout + Clone> From<Image<&'lt L>> for Image<L> {
fn from(image: Image<&'lt L>) -> Self {
let (buffer, layout) = image.inner.into_parts();
let layout: L = layout.clone();
RawImage::from_buffer(layout, buffer).into()
}
}
impl<'lt, L: Layout + Clone> From<Image<&'lt mut L>> for Image<L> {
fn from(image: Image<&'lt mut L>) -> Self {
let (buffer, layout) = image.inner.into_parts();
let layout: L = layout.clone();
RawImage::from_buffer(layout, buffer).into()
}
}
impl<'lt, L> From<&'lt Image<L>> for ImageRef<'lt, &'lt L> {
fn from(image: &'lt Image<L>) -> Self {
image.as_ref()
}
}
impl<'lt, L> From<&'lt mut Image<L>> for ImageMut<'lt, &'lt mut L> {
fn from(image: &'lt mut Image<L>) -> Self {
image.as_mut()
}
}
impl<'lt, L: Layout + Clone> From<&'lt Image<L>> for ImageRef<'lt, L> {
fn from(image: &'lt Image<L>) -> Self {
image.as_ref().into()
}
}
impl<'lt, L: Layout + Clone> From<&'lt mut Image<L>> for ImageMut<'lt, L> {
fn from(image: &'lt mut Image<L>) -> Self {
image.as_mut().into()
}
}
impl<'lt, L: Layout + Clone> From<ImageRef<'lt, &'_ L>> for ImageRef<'lt, L> {
fn from(image: ImageRef<'lt, &'_ L>) -> Self {
let (buffer, layout) = image.inner.into_parts();
let layout: L = layout.clone();
RawImage::from_buffer(layout, buffer).into()
}
}
impl<'lt, L: Layout + Clone> From<ImageRef<'lt, &'_ mut L>> for ImageRef<'lt, L> {
fn from(image: ImageRef<'lt, &'_ mut L>) -> Self {
let (buffer, layout) = image.inner.into_parts();
let layout: L = layout.clone();
RawImage::from_buffer(layout, buffer).into()
}
}
impl<'lt, L: Layout + Clone> From<ImageMut<'lt, &'_ L>> for ImageMut<'lt, L> {
fn from(image: ImageMut<'lt, &'_ L>) -> Self {
let (buffer, layout) = image.inner.into_parts();
let layout: L = layout.clone();
RawImage::from_buffer(layout, buffer).into()
}
}
impl<'lt, L: Layout + Clone> From<ImageMut<'lt, &'_ mut L>> for ImageMut<'lt, L> {
fn from(image: ImageMut<'lt, &'_ mut L>) -> Self {
let (buffer, layout) = image.inner.into_parts();
let layout: L = layout.clone();
RawImage::from_buffer(layout, buffer).into()
}
}
impl<L> From<RawImage<Buffer, L>> for Image<L> {
fn from(image: RawImage<Buffer, L>) -> Self {
Image { inner: image }
}
}
impl<'lt, L> From<RawImage<&'lt buf, L>> for ImageRef<'lt, L> {
fn from(image: RawImage<&'lt buf, L>) -> Self {
ImageRef { inner: image }
}
}
impl<'lt, L> From<RawImage<&'lt mut buf, L>> for ImageMut<'lt, L> {
fn from(image: RawImage<&'lt mut buf, L>) -> Self {
ImageMut { inner: image }
}
}
impl<L: Layout + Default> Default for Image<L> {
fn default() -> Self {
Image {
inner: RawImage::from_buffer(L::default(), Buffer::default()),
}
}
}
impl<L> fmt::Debug for Image<L>
where
L: SliceLayout + fmt::Debug,
L::Sample: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Image")
.field("layout", self.inner.layout())
.field("content", &self.inner.as_slice())
.finish()
}
}