diff --git a/canvas/Cargo.toml b/canvas/Cargo.toml index baffd6c..d4fa69b 100644 --- a/canvas/Cargo.toml +++ b/canvas/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/image-rs/canvas" categories = ["multimedia::images"] [dependencies] -image-texel = { path = "../texel", version = "0.3.0" } +image-texel = { path = "../texel", version = "0.4.0" } bytemuck = "1.1" [dev-dependencies] diff --git a/texel/Cargo.toml b/texel/Cargo.toml index 7866d59..5268a17 100644 --- a/texel/Cargo.toml +++ b/texel/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "image-texel" -version = "0.3.1" +version = "0.4.0" edition = "2021" -rust-version = "1.77" +rust-version = "1.84" description = "A texel type and allocated buffers suitable for image data." authors = ["Aurelia Molzer "] diff --git a/texel/Changes.md b/texel/Changes.md index 70232e1..1dd26b5 100644 --- a/texel/Changes.md +++ b/texel/Changes.md @@ -1,3 +1,14 @@ +# v0.4.0 + +- Add `AtomicImage`, `CellImage` and several supporting types and interfaces. + These replicate large parts of the `Image` and `ImageMut` types but allow for + operations on a shared buffer, wrapping `Arc` and `Rc` respectively. +- Added `PlaneOf` trait, a relationship between a layout, and index, and a + subcomponent of the layout. All image reference types implement a form of + `into_planes` that splits them apart by those components. +- Added a `Relocate` trait for layouts that can be move to another location + in a buffer. + ## v0.3.1 - Fix compilation on non-explicit targets, where the maximum alignment will diff --git a/texel/src/buf.rs b/texel/src/buf.rs index 9408c25..a0b44d0 100644 --- a/texel/src/buf.rs +++ b/texel/src/buf.rs @@ -332,6 +332,11 @@ impl AtomicBuffer { } } + /// Query if two buffers share the same memory region. + pub fn ptr_eq(&self, other: &Self) -> bool { + Arc::ptr_eq(&self.inner, &other.inner) + } + /// Retrieve the byte capacity of the allocated storage. pub fn capacity(&self) -> usize { core::mem::size_of_val(&*self.inner) @@ -1014,6 +1019,14 @@ impl cmp::PartialEq<[u8]> for cell_buf { impl cmp::Eq for cell_buf {} +impl cmp::PartialEq for CellBuffer { + fn eq(&self, other: &Self) -> bool { + **self == **other + } +} + +impl cmp::Eq for CellBuffer {} + impl TexelMappingBuffer for &'_ cell_buf { /// Internally mapping function when the mapping can be done forwards. fn map_forward( @@ -1197,6 +1210,14 @@ impl cmp::PartialEq<[u8]> for atomic_buf { impl cmp::Eq for atomic_buf {} +impl cmp::PartialEq for AtomicBuffer { + fn eq(&self, other: &Self) -> bool { + **self == **other + } +} + +impl cmp::Eq for AtomicBuffer {} + impl TexelMappingBuffer for &'_ atomic_buf { /// Internally mapping function when the mapping can be done forwards. fn map_forward( diff --git a/texel/src/image/atomic.rs b/texel/src/image/atomic.rs index d15dd6f..0e94b5d 100644 --- a/texel/src/image/atomic.rs +++ b/texel/src/image/atomic.rs @@ -9,7 +9,20 @@ use crate::{Texel, TexelBuffer}; /// A container of allocated bytes, parameterized over the layout. /// +/// This is a synchronized, shared equivalent to [`Image`][`crate::image::Image`]. That is the +/// buffer of bytes of this container is shared between clones of this value and potentially +/// between threads. In particular the same buffer may be owned and viewed with different layouts +/// and modified concurrently. The guarantee, however, is merely that concurrent modification is +/// free of undefined data races. There is no locking, implied synchronization, or ordering +/// guarantees between edits except when you can modify disjoint parts of the buffer. +/// /// ## Differences to owned Image +/// +/// Comparing values of this type is possible, but requires calling the method [`Self::compare`] to +/// create a comparator. This is because comparing is inherently racing against modifications made +/// on other threads. While the implementation prevents any unsound *data races* there is no +/// specific meaning to any of its outcomes unless the caller ensure synchronization in some other +/// manner. #[derive(Clone)] pub struct AtomicImage { inner: RawImage, @@ -18,7 +31,8 @@ pub struct AtomicImage { /// A partial view of an atomic image. /// /// Note that this requires its underlying buffer to be highly aligned! For that reason it is not -/// possible to take a reference at an arbitrary number of bytes. +/// possible to take a reference at an arbitrary number of bytes. Values of this type are created +/// by calling [`AtomicImage::as_ref`] or [`AtomicImage::checked_to_ref`]. #[derive(Clone, PartialEq, Eq)] pub struct AtomicImageRef<'buf, Layout = &'buf Bytes> { inner: RawImage<&'buf atomic_buf, Layout>, @@ -156,6 +170,26 @@ impl AtomicImage { self.inner.fits(layout) } + /// Check if two images refer to the same buffer. + pub fn ptr_eq(&self, other: &Self) -> bool { + AtomicBuffer::ptr_eq(self.inner.get(), other.inner.get()) + } + + /// Create a comparator to another image. + /// + /// Note that comparing is inherently racing against modifications made on other threads. While + /// the implementation prevents any unsound *data races* there is no specific meaning to any of + /// its outcomes unless the caller ensure synchronization in some other manner. + /// + /// You can also compare the allocation with [`Self::ptr_eq`] or ignore the layout and compare + /// buffer contents with [`Self::as_capacity_atomic_buf`]. + pub fn compare(&self) -> impl core::cmp::Eq + core::cmp::PartialEq + '_ + where + L: core::cmp::Eq, + { + (self.inner.layout(), self.inner.get()) + } + /// Get a reference to the aligned unstructured bytes of the image. /// /// Note that this may return more bytes than required for the specific layout for various diff --git a/texel/src/image/cell.rs b/texel/src/image/cell.rs index ae6dc77..0c50d76 100644 --- a/texel/src/image/cell.rs +++ b/texel/src/image/cell.rs @@ -10,11 +10,10 @@ use core::cell::Cell; /// A container of allocated bytes, parameterized over the layout. /// -/// ## Differences to owned Image -/// -/// The implementations for [`PartialEq`] and [`Eq`] are not provided. In many containers and -/// contexts these two traits are required to rule out absence of interior mutability. -#[derive(Clone)] +/// This is a unsynchronized, shared equivalent to [`Image`][`crate::image::Image`]. That is the +/// buffer of bytes of this container is shared between clones of this value but can not be sent +/// between threads. In particular the same buffer may be owned and viewed with different layouts. +#[derive(Clone, PartialEq, Eq)] pub struct CellImage { inner: RawImage, } @@ -22,7 +21,8 @@ pub struct CellImage { /// A partial view of an atomic image. /// /// Note that this requires its underlying buffer to be highly aligned! For that reason it is not -/// possible to take a reference at an arbitrary number of bytes. +/// possible to take a reference at an arbitrary number of bytes. Values of this type are created +/// by calling [`CellImage::as_ref`] or [`CellImage::checked_to_ref`]. #[derive(Clone, PartialEq, Eq)] pub struct CellImageRef<'buf, Layout = &'buf Bytes> { inner: RawImage<&'buf cell_buf, Layout>, @@ -160,6 +160,11 @@ impl CellImage { self.inner.fits(layout) } + /// Check if two images refer to the same buffer. + pub fn ptr_eq(&self, other: &Self) -> bool { + CellBuffer::ptr_eq(self.inner.get(), other.inner.get()) + } + /// Get a reference to the aligned unstructured bytes of the image. /// /// Note that this may return more bytes than required for the specific layout for various diff --git a/texel/src/image/raw.rs b/texel/src/image/raw.rs index 3805b75..7c6ac61 100644 --- a/texel/src/image/raw.rs +++ b/texel/src/image/raw.rs @@ -320,6 +320,11 @@ impl RawImage { texel.cast_buf(self.as_buf()) } + /// Get mutable reference to the buffer. + pub(crate) fn get(&self) -> &B { + &self.buffer + } + /// Get a mutable reference to the buffer. It is inadvisible to modify the buffer in a way that /// it can no longer hold the layout. pub(crate) fn get_mut(&mut self) -> &mut B {