Skip to content

Commit cb74917

Browse files
committed
Polish shared buffers
This documents their purpose and in the process modifies the signature of `ptr_eq` to check if images of different layouts share an underlying buffer. Previously you'd have to discover they all can decay to `Bytes` layout and clone when they are held by reference.
1 parent 25dc1ac commit cb74917

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-2
lines changed

texel/src/buf.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,34 @@ impl<P> Clone for AtomicSliceRef<'_, P> {
14431443

14441444
impl<P> Copy for AtomicSliceRef<'_, P> {}
14451445

1446+
impl<P> AtomicRef<'_, P> {
1447+
/// Modify the value stored in the reference.
1448+
///
1449+
/// Note that this does *not* promise to be atomic in the whole value, just that it atomically
1450+
/// modifies the underlying buffer elements. The bytes of the value may be torn if another
1451+
/// write happens concurrently to the same element.
1452+
///
1453+
/// However, it is guaranteed that the contents of any other non-aliased value in the buffer is
1454+
/// not modified even if they share the same atomic unit.
1455+
pub fn store(self, value: P) {
1456+
self.texel.store_atomic(self, value);
1457+
}
1458+
1459+
/// Retrieve a value stored in the reference.
1460+
///
1461+
/// Note that this does *not* promise to be atomic in the whole value, just that it atomically
1462+
/// reads from the underlying buffer. The bytes of the value may be torn if another write
1463+
/// happens concurrently to the same element.
1464+
///
1465+
/// If no such write occurs concurrently, when all writes are ordered-before or ordered-after
1466+
/// this load then the value is correct. This needs only hold to writes accessing the bytes
1467+
/// making up _this value_. Even if another values shares atomic units with this value their
1468+
/// writes are guaranteed to never modify the bits of this value.
1469+
pub fn load(self) -> P {
1470+
self.texel.load_atomic(self)
1471+
}
1472+
}
1473+
14461474
impl<P> Clone for AtomicRef<'_, P> {
14471475
fn clone(&self) -> Self {
14481476
AtomicRef { ..*self }

texel/src/image/atomic.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,24 @@ use crate::{BufferReuseError, Texel, TexelBuffer};
2323
/// on other threads. While the implementation prevents any unsound *data races* there is no
2424
/// specific meaning to any of its outcomes unless the caller ensure synchronization in some other
2525
/// manner.
26+
///
27+
/// # Examples
28+
///
29+
/// As a type with shared ownership over the underling buffer, this type can be cloned very
30+
/// cheaply. Such duplicates refer to the same buffer, making changes in one visible to the other.
31+
///
32+
/// ```
33+
/// use image_texel::{image::AtomicImage, layout::Matrix};
34+
/// let matrix = Matrix::<u8>::width_and_height(400, 400).unwrap();
35+
/// let image: AtomicImage<_> = AtomicImage::new(matrix);
36+
///
37+
/// let another_reference = image.clone();
38+
/// assert!(AtomicImage::ptr_eq(&image, &another_reference));
39+
///
40+
/// another_reference.as_slice().index_one(0).store(0xff);
41+
/// let value = image.as_slice().index_one(0).load();
42+
/// assert_eq!(value, 0xff);
43+
/// ```
2644
#[derive(Clone)]
2745
pub struct AtomicImage<Layout = Bytes> {
2846
pub(super) inner: RawImage<AtomicBuffer, Layout>,
@@ -227,7 +245,10 @@ impl<L> AtomicImage<L> {
227245
}
228246

229247
/// Check if two images refer to the same buffer.
230-
pub fn ptr_eq(&self, other: &Self) -> bool {
248+
///
249+
/// Note that two buffers can use different layout types to describe their share of the data or
250+
/// even to refer to the same data in different ways.
251+
pub fn ptr_eq<O>(&self, other: &AtomicImage<O>) -> bool {
231252
AtomicBuffer::ptr_eq(self.inner.get(), other.inner.get())
232253
}
233254

texel/src/image/cell.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,24 @@ use core::cell::Cell;
1313
/// This is a unsynchronized, shared equivalent to [`Image`][`crate::image::Image`]. That is the
1414
/// buffer of bytes of this container is shared between clones of this value but can not be sent
1515
/// between threads. In particular the same buffer may be owned and viewed with different layouts.
16+
///
17+
/// # Examples
18+
///
19+
/// As a type with shared ownership over the underling buffer, this type can be cloned very
20+
/// cheaply. Such duplicates refer to the same buffer, making changes in one visible to the other.
21+
///
22+
/// ```
23+
/// use image_texel::{image::CellImage, layout::Matrix};
24+
/// let matrix = Matrix::<u8>::width_and_height(400, 400).unwrap();
25+
/// let image: CellImage<_> = CellImage::new(matrix);
26+
///
27+
/// let another_reference = image.clone();
28+
/// assert!(CellImage::ptr_eq(&image, &another_reference));
29+
///
30+
/// another_reference.as_slice().as_slice_of_cells()[0].set(0xff);
31+
/// let value = image.as_slice().as_slice_of_cells()[0].get();
32+
/// assert_eq!(value, 0xff);
33+
/// ```
1634
#[derive(Clone, PartialEq, Eq)]
1735
pub struct CellImage<Layout = Bytes> {
1836
pub(super) inner: RawImage<CellBuffer, Layout>,
@@ -219,7 +237,10 @@ impl<L> CellImage<L> {
219237
}
220238

221239
/// Check if two images refer to the same buffer.
222-
pub fn ptr_eq(&self, other: &Self) -> bool {
240+
///
241+
/// Note that two buffers can use different layout types to describe their share of the data or
242+
/// even to refer to the same data in different ways.
243+
pub fn ptr_eq<O>(&self, other: &CellImage<O>) -> bool {
223244
CellBuffer::ptr_eq(self.inner.get(), other.inner.get())
224245
}
225246

0 commit comments

Comments
 (0)