use core::{fmt, ops};
use crate::buf::{buf, Buffer, Cog};
use crate::layout::{
Bytes, Decay, DynLayout, Layout, Mend, Raster, RasterMut, SliceLayout, Take, TryMend,
};
use crate::{BufferReuseError, Texel, TexelBuffer};
pub use crate::stride::{StridedBufferMut, StridedBufferRef};
#[derive(Clone, PartialEq, Eq)]
pub struct Image<Layout = Bytes> {
inner: RawImage<Buffer, Layout>,
}
#[derive(Clone, PartialEq, Eq)]
pub(crate) struct CopyOnGrow<'buf, Layout = Bytes> {
inner: RawImage<Cog<'buf>, 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>,
}
#[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)
}
}
#[derive(Default, Clone, PartialEq, Eq)]
pub(crate) struct RawImage<Buf, Layout> {
buffer: Buf,
layout: Layout,
}
pub(crate) trait BufferLike: ops::Deref<Target = buf> {
fn into_owned(self) -> Buffer;
fn take(&mut self) -> Self;
}
pub(crate) trait BufferMut: BufferLike + ops::DerefMut {}
pub(crate) trait Growable: BufferLike {
fn grow_to(&mut self, _: usize);
}
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::with_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 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.reinterpret_unguarded(|_| 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()
.reinterpret_unguarded(|_| 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_texels<P>(&self, pixel: Texel<P>) -> &[P] {
self.inner.buffer.as_texels(pixel)
}
pub fn as_mut_texels<P>(&mut self, pixel: Texel<P>) -> &mut [P] {
self.inner.buffer.as_mut_texels(pixel)
}
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.borrow().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.borrow_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_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.borrow().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,
{
let layout = M::decay(self.inner.layout);
let image = RawImage {
layout,
buffer: self.inner.buffer,
};
if image.fits(&image.layout) {
Some(image.into())
} else {
None
}
}
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] {
self.inner.buffer.as_texels(pixel)
}
pub fn into_slice(self) -> &'data [L::Sample]
where
L: SliceLayout,
{
self.inner.buffer.as_texels(self.inner.layout.sample())
}
pub fn get_texel<P>(&self, coord: Coord) -> Option<P>
where
L: Raster<P>,
{
L::get(self.as_ref(), coord)
}
}
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.borrow().into()
}
pub fn as_mut(&mut self) -> ImageMut<'_, &'_ mut L> {
self.inner.borrow_mut().into()
}
pub fn into_ref(self) -> ImageRef<'data, L> {
RawImage {
layout: self.inner.layout,
buffer: &*self.inner.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,
{
let layout = M::decay(self.inner.layout);
let image = RawImage {
layout,
buffer: self.inner.buffer,
};
if image.fits(&image.layout) {
Some(image.into())
} else {
None
}
}
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] {
self.inner.buffer.as_texels(pixel)
}
pub fn as_mut_texels<P>(&mut self, pixel: Texel<P>) -> &mut [P] {
self.inner.buffer.as_mut_texels(pixel)
}
pub fn into_slice(self) -> &'data [L::Sample]
where
L: SliceLayout,
{
self.inner.buffer.as_texels(self.inner.layout.sample())
}
pub fn into_mut_slice(self) -> &'data mut [L::Sample]
where
L: SliceLayout,
{
self.inner.buffer.as_mut_texels(self.inner.layout.sample())
}
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<'data, 'l, L: Layout> ImageRef<'data, &'l L> {
pub(crate) fn as_deref(self) -> ImageRef<'data, &'l L::Target>
where
L: core::ops::Deref,
L::Target: Layout,
{
self.inner.reinterpret_unguarded(|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: core::ops::DerefMut,
L::Target: Layout,
{
self.inner.reinterpret_unguarded(|l| &mut **l).into()
}
}
impl<B: Growable, L> RawImage<B, L> {
pub(crate) fn grow(&mut self, layout: &impl Layout) {
Growable::grow_to(&mut self.buffer, layout.byte_len());
}
pub(crate) fn decay<Other>(mut self) -> RawImage<B, Other>
where
Other: Decay<L>,
{
let layout = Other::decay(self.layout);
Growable::grow_to(&mut self.buffer, layout.byte_len());
RawImage {
buffer: self.buffer,
layout,
}
}
pub(crate) fn into_dynamic(self) -> RawImage<B, DynLayout>
where
DynLayout: Decay<L>,
{
self.decay()
}
pub(crate) fn with_layout<Other: Layout>(mut self, layout: Other) -> RawImage<B, Other> {
Growable::grow_to(&mut self.buffer, layout.byte_len());
RawImage {
buffer: self.buffer,
layout,
}
}
pub(crate) fn as_reinterpreted<Other>(&mut self, other: Other) -> RawImage<&'_ mut buf, Other>
where
B: BufferMut,
Other: Layout,
{
self.grow(&other);
RawImage {
buffer: &mut self.buffer,
layout: other,
}
}
pub(crate) fn mutate_layout<T>(&mut self, f: impl FnOnce(&mut L) -> T) -> T
where
L: Layout,
{
let t = f(&mut self.layout);
self.buffer.grow_to(self.layout.byte_len());
t
}
}
impl<B: BufferLike, L> RawImage<B, L> {
pub(crate) fn as_capacity_bytes_mut(&mut self) -> &mut [u8]
where
B: BufferMut,
{
self.buffer.as_bytes_mut()
}
pub(crate) fn into_owned(self) -> RawImage<Buffer, L> {
RawImage {
buffer: BufferLike::into_owned(self.buffer),
layout: self.layout,
}
}
}
impl<B> RawImage<B, DynLayout> {
pub(crate) fn try_from_dynamic<Other>(self, layout: Other) -> Result<RawImage<B, Other>, Self>
where
Other: Into<DynLayout> + Clone,
{
let reference = layout.clone().into();
if self.layout == reference {
Ok(RawImage {
buffer: self.buffer,
layout,
})
} else {
Err(self)
}
}
}
impl<B, L> RawImage<B, L> {
pub(crate) fn new(layout: L) -> Self
where
L: Layout,
B: From<Buffer>,
{
let bytes = layout.byte_len();
RawImage {
buffer: Buffer::new(bytes).into(),
layout,
}
}
pub(crate) fn with_contents(buffer: &[u8], layout: L) -> Self
where
L: Layout,
B: From<Buffer>,
{
let mut buffer = Buffer::from(buffer);
buffer.grow_to(layout.byte_len());
RawImage {
buffer: buffer.into(),
layout,
}
}
pub(crate) fn with_buffer(layout: L, buffer: B) -> Self
where
B: ops::Deref<Target = buf>,
L: Layout,
{
assert!(buffer.as_ref().len() <= layout.byte_len());
RawImage { buffer, layout }
}
pub(crate) fn layout(&self) -> &L {
&self.layout
}
pub(crate) fn layout_mut_unguarded(&mut self) -> &mut L {
&mut self.layout
}
pub(crate) fn as_capacity_bytes(&self) -> &[u8]
where
B: ops::Deref<Target = buf>,
{
self.buffer.as_bytes()
}
pub(crate) fn as_bytes(&self) -> &[u8]
where
B: ops::Deref<Target = buf>,
L: Layout,
{
&self.as_capacity_bytes()[..self.layout.byte_len()]
}
pub(crate) fn as_slice(&self) -> &[L::Sample]
where
B: ops::Deref<Target = buf>,
L: SliceLayout,
{
self.buffer.as_texels(self.layout.sample())
}
pub(crate) fn borrow(&self) -> RawImage<&'_ buf, &'_ L>
where
B: ops::Deref<Target = buf>,
{
RawImage {
buffer: &self.buffer,
layout: &self.layout,
}
}
pub(crate) fn borrow_mut(&mut self) -> RawImage<&'_ mut buf, &'_ mut L>
where
B: ops::DerefMut<Target = buf>,
{
RawImage {
buffer: &mut self.buffer,
layout: &mut self.layout,
}
}
pub(crate) fn fits(&self, other: &impl Layout) -> bool
where
B: ops::Deref<Target = buf>,
{
other.byte_len() <= self.as_capacity_bytes().len()
}
pub(crate) fn reinterpret_unguarded<Other: Layout>(
self,
layout: impl FnOnce(L) -> Other,
) -> RawImage<B, Other> {
RawImage {
buffer: self.buffer,
layout: layout(self.layout),
}
}
pub(crate) fn try_reinterpret<Other>(self, layout: Other) -> Result<RawImage<B, Other>, Self>
where
B: ops::Deref<Target = buf>,
Other: Layout,
{
if self.buffer.len() > layout.byte_len() {
Err(self)
} else {
Ok(RawImage {
buffer: self.buffer,
layout,
})
}
}
}
impl<B: BufferLike, L: Layout> RawImage<B, L> {
pub(crate) fn as_bytes_mut(&mut self) -> &mut [u8]
where
B: BufferMut,
{
let len = self.layout.byte_len();
&mut self.as_capacity_bytes_mut()[..len]
}
pub(crate) fn try_reuse(&mut self, layout: L) -> Result<(), BufferReuseError> {
if self.as_capacity_bytes().len() >= layout.byte_len() {
self.layout = layout;
Ok(())
} else {
Err(BufferReuseError {
capacity: self.as_capacity_bytes().len(),
requested: Some(layout.byte_len()),
})
}
}
pub(crate) fn mutate_inplace<T>(&mut self, f: impl FnOnce(&mut L) -> T) -> T
where
L: Layout,
{
let t = f(&mut self.layout);
assert!(
self.layout.byte_len() <= self.buffer.len(),
"Modification required buffer allocation, was not in-place"
);
t
}
pub(crate) fn take(&mut self) -> Self
where
L: Take,
{
let buffer = self.buffer.take();
let layout = self.mutate_inplace(Take::take);
RawImage::with_buffer(layout, buffer)
}
}
impl<B: BufferLike, L: SliceLayout> RawImage<B, L> {
pub(crate) fn from_buffer(buffer: TexelBuffer<L::Sample>, layout: L) -> Self
where
B: From<Buffer>,
{
let buffer = buffer.into_inner();
assert!(buffer.len() >= layout.byte_len());
Self {
buffer: buffer.into(),
layout,
}
}
pub(crate) fn as_mut_slice(&mut self) -> &mut [L::Sample]
where
B: BufferMut,
{
self.buffer.as_mut_texels(self.layout.sample())
}
pub(crate) fn into_buffer(self) -> TexelBuffer<L::Sample> {
let sample = self.layout.sample();
let count = self.as_slice().len();
let buffer = self.buffer.into_owned();
let mut rec = TexelBuffer::from_buffer(buffer, sample);
rec.resize(count);
rec
}
}
impl<'lt, L: Layout + Clone> From<Image<&'lt L>> for Image<L> {
fn from(image: Image<&'lt L>) -> Self {
let layout: L = (*image.layout()).clone();
RawImage::with_buffer(layout, image.inner.buffer).into()
}
}
impl<'lt, L: Layout + Clone> From<Image<&'lt mut L>> for Image<L> {
fn from(image: Image<&'lt mut L>) -> Self {
let layout: L = (*image.layout()).clone();
RawImage::with_buffer(layout, image.inner.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 layout: L = (*image.layout()).clone();
RawImage::with_buffer(layout, image.inner.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 layout: L = (*image.layout()).clone();
RawImage::with_buffer(layout, image.inner.buffer).into()
}
}
impl<'lt, L: Layout + Clone> From<ImageMut<'lt, &'_ L>> for ImageMut<'lt, L> {
fn from(image: ImageMut<'lt, &'_ L>) -> Self {
let layout: L = (*image.layout()).clone();
RawImage::with_buffer(layout, image.inner.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 layout: L = (*image.layout()).clone();
RawImage::with_buffer(layout, image.inner.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 BufferLike for Cog<'_> {
fn into_owned(self) -> Buffer {
Cog::into_owned(self)
}
fn take(&mut self) -> Self {
core::mem::replace(self, Cog::Owned(Default::default()))
}
}
impl BufferLike for Buffer {
fn into_owned(self) -> Self {
self
}
fn take(&mut self) -> Self {
core::mem::take(self)
}
}
impl BufferLike for &'_ mut buf {
fn into_owned(self) -> Buffer {
Buffer::from(self.as_bytes())
}
fn take(&mut self) -> Self {
core::mem::take(self)
}
}
impl Growable for Cog<'_> {
fn grow_to(&mut self, bytes: usize) {
Cog::grow_to(self, bytes);
}
}
impl Growable for Buffer {
fn grow_to(&mut self, bytes: usize) {
Buffer::grow_to(self, bytes);
}
}
impl BufferMut for Cog<'_> {}
impl BufferMut for Buffer {}
impl BufferMut for &'_ mut buf {}
impl<Layout: Clone> Clone for RawImage<Cog<'_>, Layout> {
fn clone(&self) -> Self {
use alloc::borrow::ToOwned;
RawImage {
buffer: Cog::Owned(self.buffer.to_owned()),
layout: self.layout.clone(),
}
}
}
impl<Layout: Default> Default for Image<Layout> {
fn default() -> Self {
Image {
inner: RawImage {
buffer: Buffer::default(),
layout: Layout::default(),
},
}
}
}
impl<Layout: Default> Default for CopyOnGrow<'_, Layout> {
fn default() -> Self {
CopyOnGrow {
inner: RawImage {
buffer: Cog::Owned(Buffer::default()),
layout: Layout::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()
}
}