Skip to main content

image_texel/
buf.rs

1// Distributed under The MIT License (MIT)
2//
3// Copyright (c) 2019 The `image-rs` developers
4use core::{borrow, cell, cmp, mem, ops, sync::atomic};
5
6use alloc::borrow::ToOwned;
7use alloc::rc::Rc;
8use alloc::sync::Arc;
9use alloc::vec::Vec;
10
11use crate::rec::TexelBuffer;
12use crate::texel::{constants::MAX, AtomicPart, MaxAligned, MaxAtomic, MaxCell, Texel, MAX_ALIGN};
13
14/// Allocates and manages raw bytes.
15///
16/// Provides a utility to allocate a slice of bytes aligned to the maximally required alignment.
17/// Since the elements are much larger than single bytes the inner storage will **not** have exact
18/// sizes as one would be used from by using a `Vec` as an allocator. This is instead more close to
19/// a `RawVec` and most operations have the same drawback as `Vec::reserve_exact` in not actually
20/// being exact.
21///
22/// Since exact length and capacity semantics are hard to guarantee for most operations, no effort
23/// is made to uphold them. Instead. keeping track of the exact, wanted logical length of the
24/// requested byte slice is the obligation of the user *under all circumstances*. As a consequence,
25/// there are also no operations which explicitely uncouple length and capacity. All operations
26/// simply work on best effort of making some number of bytes available.
27#[derive(Clone, Default)]
28pub struct Buffer {
29    /// The backing memory.
30    inner: Vec<MaxAligned>,
31}
32
33/// Allocates and manages atomically shared bytes.
34///
35/// Provides a utility to allocate a slice of bytes aligned to the maximally required alignment.
36/// Since the elements are much larger than single bytes the inner storage will **not** have exact
37/// sizes as one would be used from by using a `Vec` as an allocator. This is instead more close to
38/// a `RawVec` and most operations have the same drawback as `Vec::reserve_exact` in not actually
39/// being exact.
40///
41/// Since exact length and capacity semantics are hard to guarantee for most operations, no effort
42/// is made to uphold them. Instead. keeping track of the exact, wanted logical length of the
43/// requested byte slice is the obligation of the user *under all circumstances*. As a consequence,
44/// there are also no operations which explicitely uncouple length and capacity. All operations
45/// simply work on best effort of making some number of bytes available.
46#[derive(Clone, Default)]
47pub struct AtomicBuffer {
48    /// The backing memory.
49    inner: Arc<[MaxAtomic]>,
50}
51
52/// Allocates and manages unsynchronized shared bytes.
53///
54/// Provides a utility to allocate a slice of bytes aligned to the maximally required alignment.
55/// Since the elements are much larger than single bytes the inner storage will **not** have exact
56/// sizes as one would be used from by using a `Vec` as an allocator. This is instead more close to
57/// a `RawVec` and most operations have the same drawback as `Vec::reserve_exact` in not actually
58/// being exact.
59///
60/// Since exact length and capacity semantics are hard to guarantee for most operations, no effort
61/// is made to uphold them. Instead. keeping track of the exact, wanted logical length of the
62/// requested byte slice is the obligation of the user *under all circumstances*. As a consequence,
63/// there are also no operations which explicitely uncouple length and capacity. All operations
64/// simply work on best effort of making some number of bytes available.
65#[derive(Clone, Default)]
66pub struct CellBuffer {
67    /// The backing memory, aligned by allocating it with the proper type.
68    inner: Rc<[MaxCell]>,
69}
70
71/// An aligned slice of memory.
72///
73/// This is a wrapper around a byte slice that additionally requires the slice to be highly
74/// aligned.
75///
76/// See `pixel.rs` for the only constructors.
77#[repr(transparent)]
78#[allow(non_camel_case_types)]
79pub struct buf([u8]);
80
81/// An aligned slice of atomic memory.
82///
83/// In contrast to other types, this can not be slice at arbitrary byte ends since we must
84/// still utilize potentially full atomic instructions for the underlying interaction! Until we get
85/// custom metadata, we have our own 'reference type' here with [`AtomicSliceRef`]. The slice
86/// reference always extends over a slice of the underlying [`MaxAtomic`] type and only stores
87/// offsets into this.
88///
89/// This type is relatively useless in the public interface, this makes interfaces slightly less
90/// convenient but it is internal to the library anyways.
91///
92/// Note: Contrary to `buf`, this type __can not__ be sliced at arbitrary locations. Use the
93/// conversion to `atomic_ref` for this.
94#[repr(transparent)]
95#[allow(non_camel_case_types)]
96pub struct atomic_buf(pub(crate) [AtomicPart]);
97
98/// An aligned slice of shared-access memory.
99///
100/// This is a wrapper around a cell of a byte slice that additionally requires the slice to be
101/// highly aligned.
102///
103/// See `pixel.rs` for the only constructors.
104#[repr(transparent)]
105#[allow(non_camel_case_types)]
106pub struct cell_buf(cell::Cell<[u8]>);
107
108/// A logical reference to a byte slice from some atomic memory.
109///
110/// The analogue of this is `&[P]` or `&[Cell<P>]` respectively. This is a wrapper around a slice
111/// of the underlying atomics. However, note we promise soundness but _not_ absence of tears in the
112/// logical data type if the data straddles different underlying atomic representation types. We
113/// simply can not promise this. Of course, an external synchronization might be used enforce this
114/// additional guarantee.
115///
116/// For consistency with slices, casting of this type is done via an instance of [`Texel`].
117///
118/// TODO: We could probably make this type smaller. We store the underlying aligned buffer region
119/// but that memory extent can be recreated from an *unaligned* pointer and a length to our actual
120/// data. (Due to alignment and size of [`MaxAligned`] being the same, just downwards align the
121/// pointer for the base and extend to the next alignment boundary upwards). This requires us to
122/// use raw pointers so that the original provenance is retained. Also we must avoid offering
123/// methods that would refer to the `buf` attribute's memory outside that minimal region.
124pub struct AtomicSliceRef<'lt, P = u8> {
125    /// This must be aligned to `MAX_ALIGN`. We could relax it to `AtomicPart` but that would be
126    /// dependent on system configuration. Since this invisible state is nevertheless hugely
127    /// important for the region considered aliased, let's avoid exposing that varying behavior as
128    /// much as possible. Crate-internal operations may use the more granular unit internally.
129    pub(crate) buf: &'lt atomic_buf,
130    /// The underlying logical texel type this is bound to.
131    pub(crate) texel: Texel<P>,
132    /// The first byte referred to by this slice.
133    ///
134    /// Not using `core::ops::Range` since we want to be Copy!
135    pub(crate) start: usize,
136    /// The past-the-end byte referred to by this slice.
137    pub(crate) end: usize,
138}
139
140/// A logical reference to a typed element from some atomic memory.
141///
142/// The analogue of this is `&P` or `&Cell<P>` respectively. Note we promise soundness but _not_
143/// absence of tears in the logical data type if the data straddles different underlying atomic
144/// representation types. We simply can not promise this. Of course, an external synchronization
145/// might be used enforce this additional guarantee.
146pub struct AtomicRef<'lt, P = u8> {
147    pub(crate) buf: &'lt atomic_buf,
148    /// The underlying logical texel type this is bound to.
149    pub(crate) texel: Texel<P>,
150    /// The first byte referred to by this slice.
151    pub(crate) start: usize,
152}
153
154impl Buffer {
155    const ELEMENT: MaxAligned = MaxAligned([0; MAX_ALIGN]);
156
157    pub fn as_buf(&self) -> &buf {
158        buf::new(self.inner.as_slice())
159    }
160
161    pub fn as_buf_mut(&mut self) -> &mut buf {
162        buf::new_mut(self.inner.as_mut_slice())
163    }
164
165    /// Allocate a new `Buf` with a number of bytes.
166    ///
167    /// Panics if the length is too long to find a properly aligned subregion.
168    pub fn new(length: usize) -> Self {
169        let alloc_len = Self::alloc_len(length);
170        let inner = alloc::vec![Self::ELEMENT; alloc_len];
171
172        Buffer { inner }
173    }
174
175    /// Retrieve the byte capacity of the allocated storage.
176    pub fn capacity(&self) -> usize {
177        self.inner.capacity() * mem::size_of::<MaxAligned>()
178    }
179
180    /// Ensure to contain a minimum number of bytes.
181    ///
182    /// Only allocates when the new required size is larger than the previous one. Note that this
183    /// does not ensure that the new length is exactly the byte count, it may be longer. If the
184    /// current length is already large enough then this will not do anything.
185    pub fn grow_to(&mut self, bytes: usize) {
186        let new_len = Self::alloc_len(bytes);
187        if self.inner.len() < new_len {
188            self.inner.resize(new_len, Self::ELEMENT);
189        }
190    }
191
192    /// Reallocate to fit as closely as possible.
193    ///
194    /// The size after resizing may still be larger than requested.
195    pub fn resize_to(&mut self, bytes: usize) {
196        let new_len = Self::alloc_len(bytes);
197        self.inner.resize(new_len, Self::ELEMENT);
198        self.inner.shrink_to_fit()
199    }
200
201    /// Calculates the number of elements to have a byte buffer of requested length.
202    fn alloc_len(length: usize) -> usize {
203        const CHUNK_SIZE: usize = mem::size_of::<MaxAligned>();
204        assert!(CHUNK_SIZE > 1);
205
206        // We allocated enough chunks for at least the length. This can never overflow.
207        length / CHUNK_SIZE + usize::from(length % CHUNK_SIZE != 0)
208    }
209}
210
211impl CellBuffer {
212    const ELEMENT: MaxCell = MaxCell::zero();
213
214    /// Allocate a new [`CellBuffer`] with a number of bytes.
215    ///
216    /// Panics if the length is too long to find a properly aligned subregion.
217    pub fn new(length: usize) -> Self {
218        let alloc_len = Buffer::alloc_len(length);
219        let inner: Vec<_> = (0..alloc_len).map(|_| Self::ELEMENT).collect();
220
221        CellBuffer {
222            inner: inner.into(),
223        }
224    }
225
226    /// Share an existing buffer.
227    ///
228    /// The library will try, to an extent, to avoid an allocation here. However, it can only do so
229    /// if the capacity of the underlying buffer is the same as the logical length of the shared
230    /// buffer. Ultimately we rely on the standard libraries guarantees for constructing a
231    /// reference counted allocation from an owned vector.
232    pub fn with_buffer(buffer: Buffer) -> Self {
233        let inner: Vec<_> = buffer.inner.into_iter().map(MaxCell::new).collect();
234
235        CellBuffer {
236            inner: inner.into(),
237        }
238    }
239
240    /// Query if two buffers share the same memory region.
241    pub fn ptr_eq(&self, other: &Self) -> bool {
242        Rc::ptr_eq(&self.inner, &other.inner)
243    }
244
245    /// Retrieve the byte capacity of the allocated storage.
246    pub fn capacity(&self) -> usize {
247        core::mem::size_of_val(&*self.inner)
248    }
249
250    /// Get this buffer if there are now copies.
251    ///
252    /// ```
253    /// use image_texel::texels::{AtomicBuffer, U8};
254    ///
255    /// let mut buffer = AtomicBuffer::new(4);
256    /// assert!(buffer.get_mut().is_some());
257    /// let alias = buffer.clone();
258    /// assert!(buffer.get_mut().is_none());
259    /// ```
260    pub fn get_mut(&mut self) -> Option<&mut cell_buf> {
261        Rc::get_mut(&mut self.inner).map(cell_buf::from_slice_mut)
262    }
263
264    /// Ensure this buffer is its own copy.
265    ///
266    /// ```
267    /// use image_texel::texels::{AtomicBuffer, U8};
268    ///
269    /// let mut buffer = AtomicBuffer::new(4);
270    /// let mut alias = buffer.clone();
271    ///
272    /// U8.store_atomic(buffer.as_texels(U8).index_one(0), 1);
273    /// let unshared = buffer.make_mut().as_buf_mut();
274    /// let alias = alias.get_mut().expect("Just unaliased");
275    ///
276    /// unshared.as_mut_texels(U8)[0] = 2;
277    /// assert_eq!(alias.as_buf_mut().as_mut_texels(U8)[0], 1);
278    /// ```
279    pub fn make_mut(&mut self) -> &mut cell_buf {
280        if Rc::get_mut(&mut self.inner).is_none() {
281            *self = self.to_owned().into();
282        }
283
284        Rc::get_mut(&mut self.inner)
285            .map(cell_buf::from_slice_mut)
286            .expect("we just made a mutable copy")
287    }
288
289    /// Copy the data into an owned buffer.
290    pub fn to_owned(&self) -> Buffer {
291        let inner = self.inner.iter().map(|cell| cell.get()).collect();
292
293        Buffer { inner }
294    }
295
296    /// Create an independent copy of the buffer, with a new length.
297    ///
298    /// The prefix contents of the new buffer will be the same as the current buffer. The new
299    /// buffer will _never_ share memory with the current buffer.
300    pub fn to_resized(&self, bytes: usize) -> Self {
301        let mut working_copy = self.to_owned();
302        working_copy.resize_to(bytes);
303        Self::with_buffer(working_copy)
304    }
305}
306
307impl AtomicBuffer {
308    const ELEMENT: MaxAtomic = MaxAtomic::zero();
309
310    /// Allocate a new [`AtomicBuffer`] with a number of bytes.
311    ///
312    /// Panics if the length is too long to find a properly aligned subregion.
313    pub fn new(length: usize) -> Self {
314        let alloc_len = Buffer::alloc_len(length);
315        let inner: Vec<_> = (0..alloc_len).map(|_| Self::ELEMENT).collect();
316
317        AtomicBuffer {
318            inner: inner.into(),
319        }
320    }
321
322    /// Share an existing buffer.
323    ///
324    /// The library will try, to an extent, to avoid an allocation here. However, it can only do so
325    /// if the capacity of the underlying buffer is the same as the logical length of the shared
326    /// buffer. Ultimately we rely on the standard libraries guarantees for constructing a
327    /// reference counted allocation from an owned vector.
328    pub fn with_buffer(buffer: Buffer) -> Self {
329        let inner: Vec<_> = buffer.inner.into_iter().map(MaxAtomic::new).collect();
330
331        AtomicBuffer {
332            inner: inner.into(),
333        }
334    }
335
336    /// Query if two buffers share the same memory region.
337    pub fn ptr_eq(&self, other: &Self) -> bool {
338        Arc::ptr_eq(&self.inner, &other.inner)
339    }
340
341    /// Retrieve the byte capacity of the allocated storage.
342    pub fn capacity(&self) -> usize {
343        core::mem::size_of_val(&*self.inner)
344    }
345
346    /// Get this buffer if there are now copies.
347    ///
348    /// ```
349    /// use image_texel::texels::{AtomicBuffer, U8};
350    ///
351    /// let mut buffer = AtomicBuffer::new(4);
352    /// assert!(buffer.get_mut().is_some());
353    /// let alias = buffer.clone();
354    /// assert!(buffer.get_mut().is_none());
355    /// ```
356    pub fn get_mut(&mut self) -> Option<&mut atomic_buf> {
357        Arc::get_mut(&mut self.inner).map(atomic_buf::from_slice_mut)
358    }
359
360    /// Ensure this buffer is its own copy.
361    ///
362    /// ```
363    /// use image_texel::texels::{AtomicBuffer, U8};
364    ///
365    /// let mut buffer = AtomicBuffer::new(4);
366    /// let mut alias = buffer.clone();
367    ///
368    /// U8.store_atomic(buffer.as_texels(U8).index_one(0), 1);
369    /// let unshared = buffer.make_mut().as_buf_mut();
370    /// let alias = alias.get_mut().expect("Just unaliased");
371    ///
372    /// unshared.as_mut_texels(U8)[0] = 2;
373    /// assert_eq!(alias.as_buf_mut().as_mut_texels(U8)[0], 1);
374    /// ```
375    pub fn make_mut(&mut self) -> &mut atomic_buf {
376        if Arc::get_mut(&mut self.inner).is_none() {
377            *self = self.to_owned().into();
378        }
379
380        Arc::get_mut(&mut self.inner)
381            .map(atomic_buf::from_slice_mut)
382            .expect("we just made a mutable copy")
383    }
384
385    /// Copy the data into an owned buffer.
386    ///
387    /// The load will always be relaxed. If more guarantees are required, insert your owned memory
388    /// barrier instructions before or after the access or otherwise synchronize the call to this
389    /// function.
390    pub fn to_owned(&self) -> Buffer {
391        let inner = self
392            .inner
393            .iter()
394            .map(|cell| cell.load(atomic::Ordering::Relaxed))
395            .collect();
396
397        Buffer { inner }
398    }
399
400    /// Create an independent copy of the buffer, with a new length.
401    ///
402    /// The prefix contents of the new buffer will be the same as the current buffer. The new
403    /// buffer will _never_ share memory with the current buffer.
404    pub fn to_resized(&self, bytes: usize) -> Self {
405        let mut working_copy = self.to_owned();
406        working_copy.resize_to(bytes);
407        Self::with_buffer(working_copy)
408    }
409}
410
411impl buf {
412    /// Wraps an aligned buffer into `buf`.
413    ///
414    /// This method will never panic, as the alignment of the data is guaranteed.
415    pub fn new<T>(data: &T) -> &Self
416    where
417        T: AsRef<[MaxAligned]> + ?Sized,
418    {
419        let bytes = MAX.to_bytes(data.as_ref());
420        Self::from_bytes(bytes).unwrap()
421    }
422
423    /// Wraps an aligned mutable buffer into `buf`.
424    ///
425    /// This method will never panic, as the alignment of the data is guaranteed.
426    pub fn new_mut<T>(data: &mut T) -> &mut Self
427    where
428        T: AsMut<[MaxAligned]> + ?Sized,
429    {
430        let bytes = MAX.to_mut_bytes(data.as_mut());
431        Self::from_bytes_mut(bytes).unwrap()
432    }
433
434    /// Reduce the number of bytes covered by this buffer slice.
435    #[must_use = "Does not mutate self"]
436    #[track_caller]
437    pub fn truncate(&self, at: usize) -> &Self {
438        Self::from_bytes(&self.as_bytes()[..at]).unwrap()
439    }
440
441    /// Reduce the number of bytes covered by this mutable buffer slice.
442    #[must_use = "Does not mutate self"]
443    #[track_caller]
444    pub fn truncate_mut(&mut self, at: usize) -> &mut Self {
445        Self::from_bytes_mut(&mut self.as_bytes_mut()[..at]).unwrap()
446    }
447
448    pub fn as_bytes(&self) -> &[u8] {
449        &self.0
450    }
451
452    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
453        &mut self.0
454    }
455
456    /// Split at an aligned byte offset.
457    #[track_caller]
458    pub fn split_at(&self, at: usize) -> (&Self, &Self) {
459        assert!(at % MAX_ALIGN == 0);
460        let (a, b) = self.0.split_at(at);
461        let a = MAX.try_to_slice(a).expect("was previously aligned");
462        let b = MAX.try_to_slice(b).expect("asserted to be aligned");
463        (Self::new(a), Self::new(b))
464    }
465
466    /// Remove everything past the given point, return the tail we removed.
467    pub(crate) fn take_at_mut<'a>(this: &mut &'a mut Self, at: usize) -> &'a mut Self {
468        let (pre, post) = buf::split_at_mut(core::mem::take(this), at);
469        *this = pre;
470        post
471    }
472
473    /// Mutably split at an aligned byte offset.
474    pub fn split_at_mut(&mut self, at: usize) -> (&mut Self, &mut Self) {
475        assert!(at % MAX_ALIGN == 0);
476        let (a, b) = self.0.split_at_mut(at);
477        let a = MAX.try_to_slice_mut(a).expect("was previously aligned");
478        let b = MAX.try_to_slice_mut(b).expect("asserted to be aligned");
479        (Self::new_mut(a), Self::new_mut(b))
480    }
481
482    /// Reinterpret the buffer for the specific texel type.
483    ///
484    /// The alignment of `P` is already checked to be smaller than `MAX_ALIGN` through the
485    /// constructor of `Texel`. The slice will have the maximum length possible but may leave
486    /// unused bytes in the end.
487    pub fn as_texels<P>(&self, pixel: Texel<P>) -> &[P] {
488        pixel.cast_buf(self)
489    }
490
491    /// Reinterpret the buffer mutable for the specific texel type.
492    ///
493    /// The alignment of `P` is already checked to be smaller than `MAX_ALIGN` through the
494    /// constructor of `Texel`.
495    // FIXME: decide to use naming scheme of `as_bytes_mut` or `as_mut_slice`.
496    pub fn as_mut_texels<P>(&mut self, pixel: Texel<P>) -> &mut [P] {
497        pixel.cast_mut_buf(self)
498    }
499
500    /// Apply a mapping function to some elements.
501    ///
502    /// The indices `src` and `dest` are indices as if the slice were interpreted as `[P]` or `[Q]`
503    /// respectively.
504    ///
505    /// The types may differ which allows the use of this function to prepare a reinterpretation
506    /// cast of a typed buffer. This function chooses the order of function applications such that
507    /// values are not overwritten before they are used, i.e. the function arguments are exactly
508    /// the previously visible values. This is even less trivial than for copy if the parameter
509    /// types differ in size.
510    ///
511    /// # Panics
512    ///
513    /// This function panics if `src` or the implied range of `dest` are out of bounds.
514    pub fn map_within<P, Q>(
515        &mut self,
516        src: impl ops::RangeBounds<usize>,
517        dest: usize,
518        f: impl Fn(P) -> Q,
519        p: Texel<P>,
520        q: Texel<Q>,
521    ) {
522        TexelMappingBuffer::map_within(self, src, dest, f, p, q)
523    }
524}
525
526impl TexelMappingBuffer for buf {
527    /// Internally mapping function when the mapping can be done forwards.
528    fn map_forward<P, Q>(
529        &mut self,
530        src: usize,
531        dest: usize,
532        len: usize,
533        f: impl Fn(P) -> Q,
534        p: Texel<P>,
535        q: Texel<Q>,
536    ) {
537        for idx in 0..len {
538            let source_idx = idx + src;
539            let target_idx = idx + dest;
540            let source = p.copy_val(&self.as_texels(p)[source_idx]);
541            let target = f(source);
542            self.as_mut_texels(q)[target_idx] = target;
543        }
544    }
545
546    /// Internally mapping function when the mapping can be done backwards.
547    fn map_backward<P, Q>(
548        &mut self,
549        src: usize,
550        dest: usize,
551        len: usize,
552        f: impl Fn(P) -> Q,
553        p: Texel<P>,
554        q: Texel<Q>,
555    ) {
556        for idx in (0..len).rev() {
557            let source_idx = idx + src;
558            let target_idx = idx + dest;
559            let source = p.copy_val(&self.as_texels(p)[source_idx]);
560            let target = f(source);
561            self.as_mut_texels(q)[target_idx] = target;
562        }
563    }
564
565    fn texel_len<P>(&self, texel: Texel<P>) -> usize {
566        self.as_texels(texel).len()
567    }
568}
569
570/// A buffer in which we can copy, apply a transform, and write back.
571trait TexelMappingBuffer {
572    fn map_forward<P, Q>(
573        &mut self,
574        src: usize,
575        dest: usize,
576        len: usize,
577        f: impl Fn(P) -> Q,
578        p: Texel<P>,
579        q: Texel<Q>,
580    );
581
582    fn map_backward<P, Q>(
583        &mut self,
584        src: usize,
585        dest: usize,
586        len: usize,
587        f: impl Fn(P) -> Q,
588        p: Texel<P>,
589        q: Texel<Q>,
590    );
591
592    fn texel_len<P>(&self, texel: Texel<P>) -> usize;
593
594    fn map_within<P, Q>(
595        &mut self,
596        src: impl ops::RangeBounds<usize>,
597        dest: usize,
598        f: impl Fn(P) -> Q,
599        p: Texel<P>,
600        q: Texel<Q>,
601    ) {
602        // By symmetry, a write sequence that map `src` to `dest` without clobbering any values
603        // that need to be read later can be applied in reverse to map `dest` to `src` instead.
604        // Indeed, one explicit formulation of the clobber condition is: for all writes, the bytes
605        // of a write do not overlap with the bytes of any later read. It follows that for all reads
606        // the bytes of the read do not overlap with the bytes of any earlier write. Swapping reads
607        // and writes and the sequence thus performs a dualisation.
608        //
609        // W.l.o.g. we concern ourselves only with `size_of::<P>() >= size_of::<Q>()`. Name the
610        // byte regions (half open intervals) of the sequences of elements (p)_n, (q)_n and name
611        // the indices in the respective indexing space of elements (pi)_n and (qi)_n, let N be the
612        // number of elements to map.
613        //
614        // Let I be the set of indices such that `inf p_I < inf q_I`. We can map p_I to q_I without
615        // clobbering by scheduling the indices I from highest to lowest. Let i be an index from I
616        // during that sequence, and j any other index not yet scheduled.
617        //
618        // Example:
619        //
620        // ```
621        // |2   | 1  |3   |
622        //     |2 |1 |3 |
623        // ```
624        //
625        // If 0 < j < i then j is in I as well, as implied by |P| >= |Q|. It is simply
626        //  inf p_j = inf p_i - |P|(i-j) <= inf p_i - |Q|(i-j) < inf q_i - |Q|(i-j) = inf q_j
627        // By definition, inf q_i > inf p_i >= sup p_j and thus the ranges of the write does not
628        // overlap those later reads.
629        //
630        // If however i < j then j can not be in I, thus inf q_j <= inf p_j. Since we also have
631        // from the relation j < i; sup q_i <= inf q_j, the write to q_i can not overlap p_j.
632        //
633        // Then, we sechdule the remaining indices in forwards direction. To actually perform this
634        // scheduling, we must find (as we now know range) I.
635        //  inf p_n = |P|*pi_n = |P|(p_start + n)
636        //  inf q_n = |Q|*qi_n = |Q|(q_start + n)
637        //
638        //  inf p_n        < inf q_n       <=>
639        //  |P|(p_start+n) < |Q|(q_start+n)<=>
640        //  |Q|q_start     > |P|p_start + (|P| - |Q|)n<=>
641        //  |Q|q_start - |P|p_start > (|P| - |Q|)n
642        //
643        // if (|P| - |Q|) != 0 then
644        //  n < (|Q|q_start - |P|p_start)/(|P| - |Q|)<=>
645        //  n < ceil((|Q|q_start - |P|p_start)/(|P| - |Q|))
646
647        // Returns the
648        fn backwards_past_the_end(start_byte_diff: isize, size_diff: isize) -> Option<usize> {
649            assert!(size_diff >= 0);
650            if size_diff == 0 {
651                if start_byte_diff > 0 {
652                    Some(0)
653                } else {
654                    None
655                }
656            } else if start_byte_diff < 0 {
657                Some(0)
658            } else {
659                let floor = start_byte_diff / size_diff;
660                let ceil = (floor as usize) + usize::from(start_byte_diff % size_diff != 0);
661                Some(ceil)
662            }
663        }
664
665        let p_start = match src.start_bound() {
666            ops::Bound::Included(&bound) => bound,
667            ops::Bound::Excluded(&bound) => bound
668                .checked_add(1)
669                .expect("Range does not specify a valid bound start"),
670            ops::Bound::Unbounded => 0,
671        };
672
673        let p_end = match src.end_bound() {
674            ops::Bound::Excluded(&bound) => bound,
675            ops::Bound::Included(&bound) => bound
676                .checked_add(1)
677                .expect("Range does not specify a valid bound end"),
678            ops::Bound::Unbounded => self.texel_len(p),
679        };
680
681        let len = p_end.checked_sub(p_start).expect("Bound violates order");
682
683        let q_start = dest;
684
685        let _ = self
686            .texel_len(p)
687            .checked_sub(p_start)
688            .and_then(|slice| slice.checked_sub(len))
689            .expect("Source out of bounds");
690
691        let _ = self
692            .texel_len(q)
693            .checked_sub(q_start)
694            .and_then(|slice| slice.checked_sub(len))
695            .expect("Destination out of bounds");
696
697        // Due to both being Texels.
698        assert!(p.size() as isize > 0);
699        assert!(q.size() as isize > 0);
700
701        if p.size() >= q.size() {
702            let start_diff = (q.size() * q_start).wrapping_sub(p.size() * p_start) as isize;
703            let size_diff = p.size() as isize - q.size() as isize;
704
705            let backwards_end = backwards_past_the_end(start_diff, size_diff)
706                .unwrap_or(len)
707                .min(len);
708
709            self.map_backward(p_start, q_start, backwards_end, &f, p, q);
710            self.map_forward(
711                p_start + backwards_end,
712                q_start + backwards_end,
713                len - backwards_end,
714                &f,
715                p,
716                q,
717            );
718        } else {
719            let start_diff = (p.size() * p_start).wrapping_sub(q.size() * q_start) as isize;
720            let size_diff = q.size() as isize - p.size() as isize;
721
722            let backwards_end = backwards_past_the_end(start_diff, size_diff)
723                .unwrap_or(len)
724                .min(len);
725
726            self.map_backward(
727                p_start + backwards_end,
728                q_start + backwards_end,
729                len - backwards_end,
730                &f,
731                p,
732                q,
733            );
734            self.map_forward(p_start, q_start, backwards_end, &f, p, q);
735        }
736    }
737}
738
739impl From<&'_ [u8]> for Buffer {
740    fn from(content: &'_ [u8]) -> Self {
741        // TODO: can this be optimized to avoid initialization before copy?
742        let mut buffer = Buffer::new(content.len());
743        buffer[..content.len()].copy_from_slice(content);
744        buffer
745    }
746}
747
748impl From<&'_ [u8]> for AtomicBuffer {
749    fn from(values: &'_ [u8]) -> Self {
750        let chunks = values.chunks_exact(MAX_ALIGN);
751        let remainder = chunks.remainder();
752
753        let capacity = Buffer::alloc_len(values.len());
754        let mut buffer = Vec::with_capacity(capacity);
755
756        buffer.extend(chunks.map(|arr| {
757            let mut data = MaxAligned([0; MAX_ALIGN]);
758            data.0.copy_from_slice(arr);
759            MaxAtomic::new(data)
760        }));
761
762        if !remainder.is_empty() {
763            let mut data = MaxAligned([0; MAX_ALIGN]);
764            data.0[..remainder.len()].copy_from_slice(remainder);
765            buffer.push(MaxAtomic::new(data));
766        }
767
768        AtomicBuffer {
769            inner: buffer.into(),
770        }
771    }
772}
773
774impl From<Buffer> for AtomicBuffer {
775    fn from(values: Buffer) -> Self {
776        // TODO: can this be optimized to avoid the byte-for-byte allocation-copy?
777        Self::from(values.as_bytes())
778    }
779}
780
781impl From<&'_ [u8]> for CellBuffer {
782    fn from(values: &'_ [u8]) -> Self {
783        let chunks = values.chunks_exact(MAX_ALIGN);
784        let remainder = chunks.remainder();
785
786        let capacity = Buffer::alloc_len(values.len());
787        let mut buffer = Vec::with_capacity(capacity);
788
789        buffer.extend(chunks.map(|arr| {
790            let mut data = [0; MAX_ALIGN];
791            data.copy_from_slice(arr);
792            MaxCell(cell::Cell::new(data))
793        }));
794
795        if !remainder.is_empty() {
796            let mut data = [0; MAX_ALIGN];
797            data[..remainder.len()].copy_from_slice(remainder);
798            buffer.push(MaxCell(cell::Cell::new(data)));
799        }
800
801        CellBuffer {
802            inner: buffer.into(),
803        }
804    }
805}
806
807impl From<Buffer> for CellBuffer {
808    fn from(values: Buffer) -> Self {
809        // TODO: can this be optimized to avoid the byte-for-byte allocation-copy?
810        Self::from(values.as_bytes())
811    }
812}
813
814impl From<&'_ buf> for Buffer {
815    fn from(content: &'_ buf) -> Self {
816        content.to_owned()
817    }
818}
819
820impl Default for &'_ buf {
821    fn default() -> Self {
822        buf::new(&mut [])
823    }
824}
825
826impl Default for &'_ mut buf {
827    fn default() -> Self {
828        buf::new_mut(&mut [])
829    }
830}
831
832impl borrow::Borrow<buf> for Buffer {
833    fn borrow(&self) -> &buf {
834        &**self
835    }
836}
837
838impl borrow::BorrowMut<buf> for Buffer {
839    fn borrow_mut(&mut self) -> &mut buf {
840        &mut **self
841    }
842}
843
844impl alloc::borrow::ToOwned for buf {
845    type Owned = Buffer;
846    fn to_owned(&self) -> Buffer {
847        let mut buffer = Buffer::new(self.len());
848        buffer.as_bytes_mut().copy_from_slice(self);
849        buffer
850    }
851}
852
853impl ops::Deref for Buffer {
854    type Target = buf;
855
856    fn deref(&self) -> &buf {
857        self.as_buf()
858    }
859}
860
861impl ops::DerefMut for Buffer {
862    fn deref_mut(&mut self) -> &mut buf {
863        self.as_buf_mut()
864    }
865}
866
867impl ops::Deref for AtomicBuffer {
868    type Target = atomic_buf;
869
870    fn deref(&self) -> &atomic_buf {
871        atomic_buf::from_slice(&self.inner)
872    }
873}
874
875impl ops::Deref for CellBuffer {
876    type Target = cell_buf;
877
878    fn deref(&self) -> &cell_buf {
879        cell_buf::from_slice(&self.inner)
880    }
881}
882
883impl ops::Deref for buf {
884    type Target = [u8];
885
886    fn deref(&self) -> &[u8] {
887        self.as_bytes()
888    }
889}
890
891impl ops::DerefMut for buf {
892    fn deref_mut(&mut self) -> &mut [u8] {
893        self.as_bytes_mut()
894    }
895}
896
897impl cmp::PartialEq for buf {
898    fn eq(&self, other: &buf) -> bool {
899        self.as_bytes() == other.as_bytes()
900    }
901}
902
903impl cmp::Eq for buf {}
904
905impl cmp::PartialEq for Buffer {
906    fn eq(&self, other: &Buffer) -> bool {
907        self.as_bytes() == other.as_bytes()
908    }
909}
910
911impl cmp::Eq for Buffer {}
912
913impl ops::Index<ops::RangeTo<usize>> for buf {
914    type Output = buf;
915
916    fn index(&self, idx: ops::RangeTo<usize>) -> &buf {
917        self.truncate(idx.end)
918    }
919}
920
921impl ops::IndexMut<ops::RangeTo<usize>> for buf {
922    fn index_mut(&mut self, idx: ops::RangeTo<usize>) -> &mut buf {
923        self.truncate_mut(idx.end)
924    }
925}
926
927impl cell_buf {
928    /// Wraps an aligned buffer into `buf`.
929    ///
930    /// This method will never panic, as the alignment of the data is guaranteed.
931    pub fn new<T>(data: &T) -> &Self
932    where
933        T: AsRef<[MaxCell]> + ?Sized,
934    {
935        cell_buf::from_slice(data.as_ref())
936    }
937
938    /// Get the length of available memory in bytes.
939    pub fn len(&self) -> usize {
940        self.0.as_slice_of_cells().len()
941    }
942
943    /// Reduce the number of bytes covered by this slice.
944    #[must_use = "Does not mutate self"]
945    #[track_caller]
946    pub fn truncate(&self, at: usize) -> &Self {
947        // We promise this does not panic since the buffer is in fact aligned.
948        Self::from_bytes(&self.0.as_slice_of_cells()[..at]).unwrap()
949    }
950
951    /// Split into two aligned buffers.
952    ///
953    /// # Panics
954    ///
955    /// This panics if the byte offset given by `at` is not aligned according to max alignment or
956    /// if the index is out-of-bounds.
957    #[track_caller]
958    pub fn split_at(&self, at: usize) -> (&Self, &Self) {
959        assert!(at % MAX_ALIGN == 0);
960        let (a, b) = self.0.as_slice_of_cells().split_at(at);
961        let a = Self::from_bytes(a).expect("was previously aligned");
962        let b = Self::from_bytes(b).expect("asserted to be aligned");
963        (a, b)
964    }
965
966    /// Reinterpret the buffer for the specific texel type.
967    ///
968    /// The alignment of `P` is already checked to be smaller than `MAX_ALIGN` through the
969    /// constructor of `Texel`. The slice will have the maximum length possible but may leave
970    /// unused bytes in the end.
971    pub fn as_texels<P>(&self, texel: Texel<P>) -> &cell::Cell<[P]> {
972        let slice = self.0.as_slice_of_cells();
973        texel
974            .try_to_cell(slice)
975            .expect("A cell_buf is always aligned")
976    }
977
978    /// Apply a mapping function to some elements.
979    ///
980    /// The indices `src` and `dest` are indices as if the slice were interpreted as `[P]` or `[Q]`
981    /// respectively.
982    ///
983    /// The types may differ which allows the use of this function to prepare a reinterpretation
984    /// cast of a typed buffer. This function chooses the order of function applications such that
985    /// values are not overwritten before they are used, i.e. the function arguments are exactly
986    /// the previously visible values. This is even less trivial than for copy if the parameter
987    /// types differ in size.
988    ///
989    /// # Panics
990    ///
991    /// This function panics if `src` or the implied range of `dest` are out of bounds.
992    pub fn map_within<P, Q>(
993        &self,
994        src: impl ops::RangeBounds<usize>,
995        dest: usize,
996        f: impl Fn(P) -> Q,
997        p: Texel<P>,
998        q: Texel<Q>,
999    ) {
1000        let mut that = self;
1001        TexelMappingBuffer::map_within(&mut that, src, dest, f, p, q)
1002    }
1003}
1004
1005impl cmp::PartialEq for cell_buf {
1006    fn eq(&self, other: &Self) -> bool {
1007        // Doing this comparison discards alignment information that is probably checked for in the
1008        // kernel of memcmp. If the compiler inlines it, it may be able to remove that. Or not.
1009        // Should not matter too much but if it does in your benchmarks (be sure to do multiple
1010        // platforms and check with assembly throughput) then let me know.
1011        crate::texels::U8.cell_memory_eq(self.0.as_slice_of_cells(), other.0.as_slice_of_cells())
1012    }
1013}
1014
1015impl cmp::PartialEq<[u8]> for cell_buf {
1016    fn eq(&self, other: &[u8]) -> bool {
1017        crate::texels::U8.cell_bytes_eq(self.0.as_slice_of_cells(), other)
1018    }
1019}
1020
1021impl cmp::PartialEq<cell_buf> for [u8] {
1022    fn eq(&self, other: &cell_buf) -> bool {
1023        crate::texels::U8.cell_bytes_eq(other.0.as_slice_of_cells(), self)
1024    }
1025}
1026
1027impl cmp::Eq for cell_buf {}
1028
1029impl cmp::PartialEq for CellBuffer {
1030    fn eq(&self, other: &Self) -> bool {
1031        **self == **other
1032    }
1033}
1034
1035impl cmp::Eq for CellBuffer {}
1036
1037impl TexelMappingBuffer for &'_ cell_buf {
1038    /// Internally mapping function when the mapping can be done forwards.
1039    fn map_forward<P, Q>(
1040        &mut self,
1041        src: usize,
1042        dest: usize,
1043        len: usize,
1044        f: impl Fn(P) -> Q,
1045        p: Texel<P>,
1046        q: Texel<Q>,
1047    ) {
1048        let src_buffer = self.as_texels(p).as_slice_of_cells();
1049        let target_buffer = self.as_texels(q).as_slice_of_cells();
1050
1051        for idx in 0..len {
1052            let source_idx = idx + src;
1053            let target_idx = idx + dest;
1054            let source = p.copy_cell(&src_buffer[source_idx]);
1055            let target = f(source);
1056            target_buffer[target_idx].set(target);
1057        }
1058    }
1059
1060    /// Internally mapping function when the mapping can be done backwards.
1061    fn map_backward<P, Q>(
1062        &mut self,
1063        src: usize,
1064        dest: usize,
1065        len: usize,
1066        f: impl Fn(P) -> Q,
1067        p: Texel<P>,
1068        q: Texel<Q>,
1069    ) {
1070        let src_buffer = self.as_texels(p).as_slice_of_cells();
1071        let target_buffer = self.as_texels(q).as_slice_of_cells();
1072
1073        for idx in (0..len).rev() {
1074            let source_idx = idx + src;
1075            let target_idx = idx + dest;
1076            let source = p.copy_cell(&src_buffer[source_idx]);
1077            let target = f(source);
1078            target_buffer[target_idx].set(target);
1079        }
1080    }
1081
1082    fn texel_len<P>(&self, texel: Texel<P>) -> usize {
1083        self.as_texels(texel).as_slice_of_cells().len()
1084    }
1085}
1086
1087impl atomic_buf {
1088    /// Wraps an aligned buffer into `buf`.
1089    ///
1090    /// This method will never panic, as the alignment of the data is guaranteed.
1091    pub fn new<T>(data: &T) -> &Self
1092    where
1093        T: AsRef<[MaxAtomic]> + ?Sized,
1094    {
1095        atomic_buf::from_slice(data.as_ref())
1096    }
1097
1098    /// Get the length of available memory in bytes.
1099    pub fn len(&self) -> usize {
1100        core::mem::size_of_val(self)
1101    }
1102
1103    pub fn as_buf_mut(&mut self) -> &mut buf {
1104        buf::from_bytes_mut(atomic_buf::part_mut_slice(&mut self.0)).unwrap()
1105    }
1106
1107    /// Split into two aligned buffers.
1108    ///
1109    /// # Panics
1110    ///
1111    /// This panics if the byte offset given by `at` is not aligned according to max alignment or
1112    /// if the index is out-of-bounds.
1113    #[track_caller]
1114    pub fn split_at(&self, at: usize) -> (&Self, &Self) {
1115        use crate::texels::U8;
1116
1117        assert!(at % MAX_ALIGN == 0);
1118        let slice = self.as_texels(U8);
1119        let (a, b) = slice.split_at(at);
1120        let left = atomic_buf::from_bytes(a).expect("was previously aligned");
1121        let right = atomic_buf::from_bytes(b).expect("was previously aligned");
1122
1123        (left, right)
1124    }
1125
1126    /// Reinterpret the buffer for the specific texel type.
1127    ///
1128    /// The alignment of `P` is already checked to be smaller than `MAX_ALIGN` through the
1129    /// constructor of `Texel`. The slice will have the maximum length possible but may leave
1130    /// unused bytes in the end.
1131    pub fn as_texels<P>(&self, texel: Texel<P>) -> AtomicSliceRef<P> {
1132        use crate::texels::U8;
1133
1134        let buffer = AtomicSliceRef {
1135            buf: self,
1136            start: 0,
1137            end: core::mem::size_of_val(self),
1138            texel: U8,
1139        };
1140
1141        texel
1142            .try_to_atomic(buffer)
1143            .expect("An atomic_buf is always aligned")
1144    }
1145
1146    /// Index into this buffer at a generalized, potentially skewed, typed index.
1147    ///
1148    /// # Panics
1149    ///
1150    /// This method panics if the index is out-of-range.
1151    pub fn index<T>(&self, index: TexelRange<T>) -> AtomicSliceRef<'_, T> {
1152        let scale = index.texel.align();
1153
1154        AtomicSliceRef {
1155            buf: self,
1156            start: scale * index.start_per_align,
1157            end: scale * index.end_per_align,
1158            texel: index.texel,
1159        }
1160    }
1161
1162    /// Apply a mapping function to some elements.
1163    ///
1164    /// The indices `src` and `dest` are indices as if the slice were interpreted as `[P]` or `[Q]`
1165    /// respectively.
1166    ///
1167    /// The types may differ which allows the use of this function to prepare a reinterpretation
1168    /// cast of a typed buffer. This function chooses the order of function applications such that
1169    /// values are not overwritten before they are used, i.e. the function arguments are exactly
1170    /// the previously visible values. This is even less trivial than for copy if the parameter
1171    /// types differ in size.
1172    ///
1173    /// # Panics
1174    ///
1175    /// This function panics if `src` or the implied range of `dest` are out of bounds.
1176    pub fn map_within<P, Q>(
1177        &self,
1178        src: impl ops::RangeBounds<usize>,
1179        dest: usize,
1180        f: impl Fn(P) -> Q,
1181        p: Texel<P>,
1182        q: Texel<Q>,
1183    ) {
1184        let mut that = self;
1185        TexelMappingBuffer::map_within(&mut that, src, dest, f, p, q)
1186    }
1187}
1188
1189impl cmp::PartialEq for atomic_buf {
1190    fn eq(&self, other: &Self) -> bool {
1191        if self.len() != other.len() {
1192            return false;
1193        }
1194
1195        // If they have the same length, they cover the same memory. Do not iterate.
1196        if (self as *const atomic_buf).addr() == (other as *const atomic_buf).addr() {
1197            return true;
1198        }
1199
1200        // We can iterate these slices in `AtomicPart` at a time. Note that this is not as complex
1201        // as the `cell_buf` case since it can not cover a partial unit. That complexity only comes
1202        // with `AtomicSliceRef`.
1203        let lhs = self.0.iter();
1204        let rhs = other.0.iter();
1205
1206        lhs.zip(rhs)
1207            .all(|(a, b)| a.load(atomic::Ordering::Relaxed) == b.load(atomic::Ordering::Relaxed))
1208    }
1209}
1210
1211impl cmp::PartialEq<[u8]> for atomic_buf {
1212    fn eq(&self, other: &[u8]) -> bool {
1213        if self.len() != other.len() {
1214            return false;
1215        }
1216
1217        // We can iterate these slices in `AtomicPart` at a time. Note that this is not as complex
1218        // as the `cell_buf` case since it can not cover a partial unit. That complexity only comes
1219        // with `AtomicSliceRef`.
1220        let lhs = self.0.iter();
1221        let rhs = other.chunks_exact(mem::size_of::<AtomicPart>());
1222
1223        lhs.zip(rhs)
1224            // Let the compiler deal with the potentially unaligned load. However it may run better
1225            // if we also had an aligned other buffer as a (semi-common) special case? Note how the
1226            // value loaded from the atomic varies by platform but all integers have that
1227            // `to_ne_bytes´ method and we iterate the slice by that type's size chunks. Should get
1228            // optimized away as a compile time constant but we could switch to `array_chunks` in
1229            // due time.
1230            .all(|(a, b)| a.load(atomic::Ordering::Relaxed).to_ne_bytes() == *b)
1231    }
1232}
1233
1234impl cmp::Eq for atomic_buf {}
1235
1236impl cmp::PartialEq for AtomicBuffer {
1237    fn eq(&self, other: &Self) -> bool {
1238        **self == **other
1239    }
1240}
1241
1242impl cmp::Eq for AtomicBuffer {}
1243
1244impl TexelMappingBuffer for &'_ atomic_buf {
1245    /// Internally mapping function when the mapping can be done forwards.
1246    fn map_forward<P, Q>(
1247        &mut self,
1248        src: usize,
1249        dest: usize,
1250        len: usize,
1251        f: impl Fn(P) -> Q,
1252        p: Texel<P>,
1253        q: Texel<Q>,
1254    ) {
1255        let src_buffer = self.as_texels(p);
1256        let target_buffer = self.as_texels(q);
1257
1258        // FIXME: isn't it particularly inefficient to load values one-by-one? But we offer that
1259        // primitive. A stack buffer for a statically sized burst of values would be better though.
1260
1261        for idx in 0..len {
1262            let source_idx = idx + src;
1263            let target_idx = idx + dest;
1264            let source = p.load_atomic(src_buffer.index_one(source_idx));
1265            let target = f(source);
1266            q.store_atomic(target_buffer.index_one(target_idx), target);
1267        }
1268    }
1269
1270    /// Internally mapping function when the mapping can be done backwards.
1271    fn map_backward<P, Q>(
1272        &mut self,
1273        src: usize,
1274        dest: usize,
1275        len: usize,
1276        f: impl Fn(P) -> Q,
1277        p: Texel<P>,
1278        q: Texel<Q>,
1279    ) {
1280        let src_buffer = self.as_texels(p);
1281        let target_buffer = self.as_texels(q);
1282
1283        for idx in (0..len).rev() {
1284            let source_idx = idx + src;
1285            let target_idx = idx + dest;
1286            let source = p.load_atomic(src_buffer.index_one(source_idx));
1287            let target = f(source);
1288            q.store_atomic(target_buffer.index_one(target_idx), target);
1289        }
1290    }
1291
1292    fn texel_len<P>(&self, texel: Texel<P>) -> usize {
1293        self.as_texels(texel).len()
1294    }
1295}
1296
1297impl<'lt, P> AtomicSliceRef<'lt, P> {
1298    /// Grab a single element.
1299    ///
1300    /// Not `get` since it does not return a reference, and we can not use the standard SliceIndex
1301    /// trait anyways. Also we do not implement the assertion outside of debug for now, it is also
1302    /// not used for unsafe code.
1303    #[track_caller]
1304    pub fn index_one(self, idx: usize) -> AtomicRef<'lt, P> {
1305        assert!(idx < self.len());
1306
1307        AtomicRef {
1308            buf: self.buf,
1309            start: self.start + idx * self.texel.size(),
1310            texel: self.texel,
1311        }
1312    }
1313
1314    /// Get a subslice with the specified tuple of bounds.
1315    ///
1316    /// Returns `None` if the bounds are out-of-range or if the bounds are otherwise invalid.
1317    pub fn get_bounds(self, bounds: (ops::Bound<usize>, ops::Bound<usize>)) -> Option<Self> {
1318        let (start, end) = bounds;
1319        let len = self.len();
1320
1321        let start = match start {
1322            ops::Bound::Included(start) => start,
1323            ops::Bound::Excluded(start) => start.checked_add(1)?,
1324            ops::Bound::Unbounded => 0,
1325        };
1326
1327        let end = match end {
1328            ops::Bound::Included(end) => end.checked_add(1)?,
1329            ops::Bound::Excluded(end) => end,
1330            ops::Bound::Unbounded => len,
1331        };
1332
1333        if start > end || end > len {
1334            None
1335        } else {
1336            Some(AtomicSliceRef {
1337                buf: self.buf,
1338                start: self.start + start * self.texel.size(),
1339                end: self.start + end * self.texel.size(),
1340                texel: self.texel,
1341            })
1342        }
1343    }
1344
1345    /// See [`Self::get_bounds`] but generic over the bound type.
1346    pub fn get(self, bounds: impl core::ops::RangeBounds<usize>) -> Option<Self> {
1347        let start = bounds.start_bound().cloned();
1348        let end = bounds.end_bound().cloned();
1349        self.get_bounds((start, end))
1350    }
1351
1352    /// See [`Self::get_bounds`] and panics appropriately.
1353    #[track_caller]
1354    pub fn index(self, bounds: impl core::ops::RangeBounds<usize>) -> Self {
1355        #[cold]
1356        fn panic_on_bounds() -> ! {
1357            panic!("Bounds are out of range");
1358        }
1359
1360        match self.get(bounds) {
1361            Some(some) => some,
1362            None => panic_on_bounds(),
1363        }
1364    }
1365
1366    /// Fill this slice with data from a shared read buffer.
1367    #[track_caller]
1368    pub fn read_from_slice(&self, data: &[P]) {
1369        self.texel.store_atomic_slice(*self, data);
1370    }
1371
1372    /// Read from this slice with data from a shared read buffer.
1373    ///
1374    /// Note that this reads every single unit as if relaxed.
1375    #[track_caller]
1376    pub fn write_to_slice(&self, data: &mut [P]) {
1377        self.texel.load_atomic_slice(*self, data);
1378    }
1379
1380    /// Read all values into a newly allocated vector.
1381    pub fn to_vec(&self) -> Vec<P> {
1382        // FIXME: avoid zero-initializing. Might need a bit more unsafe code that extends a vector
1383        // of Texel<P> from that atomic.
1384        let mut fresh: Vec<P> = (0..self.len()).map(|_| self.texel.zeroed()).collect();
1385        self.write_to_slice(&mut fresh);
1386        fresh
1387    }
1388
1389    /// Read all values into a newly allocated texel buffer.
1390    pub fn to_texel_buffer(&self) -> TexelBuffer<P> {
1391        // FIXME: avoid zero-initializing. Might need a bit more unsafe code that extends a vector
1392        // of Texel<P> from that atomic.
1393        let mut fresh = TexelBuffer::new_for_texel(self.texel, self.len());
1394        self.write_to_slice(&mut fresh);
1395        fresh
1396    }
1397
1398    #[track_caller]
1399    pub fn split_at(self, at: usize) -> (Self, Self) {
1400        let left = self.index(..at);
1401        let right = self.index(at..);
1402        (left, right)
1403    }
1404
1405    /// Reduce the number of bytes covered by this slice.
1406    #[must_use = "Does not mutate self"]
1407    #[track_caller]
1408    pub fn truncate_bytes(self, at: usize) -> Self {
1409        let len = (self.end - self.start).min(at);
1410        AtomicSliceRef {
1411            end: self.start + len,
1412            ..self
1413        }
1414    }
1415
1416    pub(crate) fn as_ptr_range(self) -> core::ops::Range<*mut P> {
1417        let base = self.buf.0.as_ptr_range();
1418        ((base.start as *mut u8).wrapping_add(self.start) as *mut P)
1419            ..((base.start as *mut u8).wrapping_add(self.end) as *mut P)
1420    }
1421
1422    /// Equivalent of [`core::slice::from_ref`] but we have no mutable analogue.
1423    pub(crate) fn from_ref(value: AtomicRef<'lt, P>) -> Self {
1424        AtomicSliceRef {
1425            buf: value.buf,
1426            start: value.start,
1427            end: value.start + value.texel.size(),
1428            texel: value.texel,
1429        }
1430    }
1431
1432    /// Get the number of elements referenced by this slice.
1433    pub fn len(&self) -> usize {
1434        self.end.saturating_sub(self.start) / self.texel.size()
1435    }
1436}
1437
1438impl<P> Clone for AtomicSliceRef<'_, P> {
1439    fn clone(&self) -> Self {
1440        AtomicSliceRef { ..*self }
1441    }
1442}
1443
1444impl<P> Copy for AtomicSliceRef<'_, P> {}
1445
1446impl<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
1474impl<P> Clone for AtomicRef<'_, P> {
1475    fn clone(&self) -> Self {
1476        AtomicRef { ..*self }
1477    }
1478}
1479
1480impl<P> Copy for AtomicRef<'_, P> {}
1481
1482/// A range representation that casts bytes to a specific texel type.
1483///
1484/// Note this type also has the invariant that the identified range fits into memory for the given
1485/// texel type.
1486#[derive(Debug)]
1487pub struct TexelRange<T> {
1488    texel: Texel<T>,
1489    start_per_align: usize,
1490    end_per_align: usize,
1491}
1492
1493impl<T> Clone for TexelRange<T> {
1494    fn clone(&self) -> Self {
1495        *self
1496    }
1497}
1498
1499impl<T> Copy for TexelRange<T> {}
1500
1501impl<T> TexelRange<T> {
1502    /// Create a new range from a texel type and a range (in units of `T`).
1503    pub fn new(texel: Texel<T>, range: ops::Range<usize>) -> Option<Self> {
1504        let end_byte = range
1505            .end
1506            .checked_mul(texel.size())
1507            .filter(|&n| n <= isize::MAX as usize)?;
1508        let start_byte = (range.start.min(range.end))
1509            .checked_mul(texel.size())
1510            .filter(|&n| n <= isize::MAX as usize)?;
1511
1512        debug_assert!(
1513            end_byte % texel.align() == 0,
1514            "Texel must be valid for its type layout"
1515        );
1516
1517        debug_assert!(
1518            start_byte % texel.align() == 0,
1519            "Texel must be valid for its type layout"
1520        );
1521
1522        Some(TexelRange {
1523            texel,
1524            start_per_align: start_byte / texel.align(),
1525            end_per_align: end_byte / texel.align(),
1526        })
1527    }
1528
1529    /// Construct from a range of bytes.
1530    ///
1531    /// The range must be aligned to the type `T` and the length of the range must be a multiple of
1532    /// the size. However, in contrast to [`Self::new`] it may be skewed with regards to the size
1533    /// of the type. For instance, a slice `[u8; 3]` may begin one byte into the underlying buffer.
1534    ///
1535    /// Note that a range with its end before the start is interpreted as an empty range and only
1536    /// has to fulfill the alignment requirement for its start byte.
1537    ///
1538    /// # Examples
1539    ///
1540    /// ```
1541    /// use image_texel::texels::{U16, TexelRange};
1542    ///
1543    /// assert!(TexelRange::from_byte_range(U16, 0..4).is_some());
1544    /// // Misaligned.
1545    /// assert!(TexelRange::from_byte_range(U16, 1..5).is_none());
1546    /// // Okay.
1547    /// assert!(TexelRange::from_byte_range(U16.array::<4>(), 2..10).is_some());
1548    /// // Okay but empty.
1549    /// assert!(TexelRange::from_byte_range(U16.array::<4>(), 2..0).is_some());
1550    /// ```
1551    pub fn from_byte_range(texel: Texel<T>, range: ops::Range<usize>) -> Option<Self> {
1552        let start_byte = range.start;
1553        let end_byte = range.end.max(start_byte);
1554
1555        if start_byte % texel.align() != 0
1556            || end_byte % texel.align() != 0
1557            || (end_byte - start_byte) % texel.size() != 0
1558        {
1559            return None;
1560        }
1561
1562        Some(TexelRange {
1563            texel,
1564            start_per_align: start_byte / texel.align(),
1565            end_per_align: end_byte / texel.align(),
1566        })
1567    }
1568
1569    /// Intrinsically, all ranges represent an aligned range of bytes.
1570    fn aligned_byte_range(self) -> ops::Range<usize> {
1571        let scale = self.texel.align();
1572        scale * self.start_per_align..scale * self.end_per_align
1573    }
1574}
1575
1576impl<T> core::ops::Index<TexelRange<T>> for buf {
1577    type Output = [T];
1578
1579    fn index(&self, index: TexelRange<T>) -> &Self::Output {
1580        let bytes = &self.0[index.aligned_byte_range()];
1581        let slice = index.texel.try_to_slice(bytes);
1582        // We just multiplied the indices by the alignment..
1583        slice.expect("byte indices validly aligned")
1584    }
1585}
1586
1587impl<T> core::ops::IndexMut<TexelRange<T>> for buf {
1588    fn index_mut(&mut self, index: TexelRange<T>) -> &mut Self::Output {
1589        let bytes = &mut self.0[index.aligned_byte_range()];
1590        let slice = index.texel.try_to_slice_mut(bytes);
1591        // We just multiplied the indices by the alignment..
1592        slice.expect("byte indices validly aligned")
1593    }
1594}
1595
1596impl<T> core::ops::Index<TexelRange<T>> for cell_buf {
1597    type Output = [cell::Cell<T>];
1598
1599    fn index(&self, index: TexelRange<T>) -> &Self::Output {
1600        let bytes = &self.0.as_slice_of_cells()[index.aligned_byte_range()];
1601        let slice = index.texel.try_to_cell(bytes);
1602        // We just multiplied the indices by the alignment..
1603        slice
1604            .expect("byte indices validly aligned")
1605            .as_slice_of_cells()
1606    }
1607}
1608
1609impl Default for &'_ cell_buf {
1610    fn default() -> Self {
1611        cell_buf::new(&mut [])
1612    }
1613}
1614
1615impl Default for &'_ atomic_buf {
1616    fn default() -> Self {
1617        atomic_buf::new(&mut [])
1618    }
1619}
1620
1621#[cfg(test)]
1622mod tests {
1623    use super::*;
1624    use crate::texels::{MAX, U16, U32, U8};
1625
1626    // When it's all over.
1627    struct AlignMeUp<N>([MaxAligned; 0], N);
1628
1629    #[test]
1630    fn single_max_element() {
1631        let mut buffer = Buffer::new(mem::size_of::<MaxAligned>());
1632        let slice = buffer.as_mut_texels(MAX);
1633        assert!(slice.len() == 1);
1634    }
1635
1636    #[test]
1637    fn growing() {
1638        let mut buffer = Buffer::new(0);
1639        assert_eq!(buffer.capacity(), 0);
1640        buffer.grow_to(mem::size_of::<MaxAligned>());
1641        let capacity = buffer.capacity();
1642        assert!(buffer.capacity() > 0);
1643        buffer.grow_to(capacity);
1644        assert_eq!(buffer.capacity(), capacity);
1645        buffer.grow_to(0);
1646        assert_eq!(buffer.capacity(), capacity);
1647        buffer.grow_to(capacity + 1);
1648        assert!(buffer.capacity() > capacity);
1649    }
1650
1651    #[test]
1652    fn reinterpret() {
1653        let mut buffer = Buffer::new(mem::size_of::<u32>());
1654        assert!(buffer.as_mut_texels(U32).len() >= 1);
1655        buffer
1656            .as_mut_texels(U16)
1657            .iter_mut()
1658            .for_each(|p| *p = 0x0f0f);
1659        buffer
1660            .as_texels(U32)
1661            .iter()
1662            .for_each(|p| assert_eq!(*p, 0x0f0f0f0f));
1663        buffer
1664            .as_texels(U8)
1665            .iter()
1666            .for_each(|p| assert_eq!(*p, 0x0f));
1667
1668        buffer
1669            .as_mut_texels(U8)
1670            .iter_mut()
1671            .enumerate()
1672            .for_each(|(idx, p)| *p = idx as u8);
1673        assert_eq!(u32::from_be(buffer.as_texels(U32)[0]), 0x00010203);
1674    }
1675
1676    #[test]
1677    fn mapping_great_to_small() {
1678        const LEN: usize = 10;
1679        let mut buffer = Buffer::new(LEN * mem::size_of::<u32>());
1680        buffer
1681            .as_mut_texels(U32)
1682            .iter_mut()
1683            .enumerate()
1684            .for_each(|(idx, p)| *p = idx as u32);
1685
1686        // Map those numbers in-place.
1687        buffer.map_within(..LEN, 0, |n: u32| n as u8, U32, U8);
1688        buffer.map_within(..LEN, 0, |n: u8| n as u32, U8, U32);
1689
1690        // Back to where we started.
1691        assert_eq!(
1692            buffer.as_texels(U32)[..LEN].to_vec(),
1693            (0..LEN as u32).collect::<Vec<_>>()
1694        );
1695
1696        // This should work even if we don't map to index 0.
1697        buffer.map_within(0..LEN, 3 * LEN, |n: u32| n as u8, U32, U8);
1698        buffer.map_within(3 * LEN..4 * LEN, 0, |n: u8| n as u32, U8, U32);
1699
1700        assert_eq!(
1701            buffer.as_texels(U32)[..LEN].to_vec(),
1702            (0..LEN as u32).collect::<Vec<_>>()
1703        );
1704    }
1705
1706    #[test]
1707    fn cell_buffer() {
1708        let data = [0, 0, 255, 0, 255, 0, 255, 0, 0];
1709        let buffer = CellBuffer::from(&data[..]);
1710        // Gets rounded up to the next alignment.
1711        assert_eq!(buffer.capacity(), Buffer::alloc_len(data.len()) * MAX_ALIGN);
1712
1713        let alternative = CellBuffer::with_buffer(buffer.to_owned());
1714        assert_eq!(buffer.capacity(), alternative.capacity());
1715
1716        let contents: &cell_buf = &*buffer;
1717        let slice: &[cell::Cell<u8>] = contents.as_texels(U8).as_slice_of_cells();
1718        assert!(cell_buf::from_bytes(slice).is_some());
1719    }
1720
1721    #[test]
1722    fn atomic_buffer() {
1723        let data = [0, 0, 255, 0, 255, 0, 255, 0, 0];
1724        let buffer = AtomicBuffer::from(&data[..]);
1725        // Gets rounded up to the next alignment.
1726        assert_eq!(buffer.capacity(), Buffer::alloc_len(data.len()) * MAX_ALIGN);
1727
1728        let alternative = CellBuffer::with_buffer(buffer.to_owned());
1729        assert_eq!(buffer.capacity(), alternative.capacity());
1730
1731        let contents: &atomic_buf = &*buffer;
1732        let slice: AtomicSliceRef<u8> = contents.as_texels(U8);
1733        assert!(atomic_buf::from_bytes(slice).is_some());
1734    }
1735
1736    #[test]
1737    fn mapping_cells() {
1738        const LEN: usize = 10;
1739        // Look, we can actually map over this buffer while it is *not* mutable.
1740        let buffer = CellBuffer::new(LEN * mem::size_of::<u32>());
1741        // And receive all the results in this shared copy of our buffer.
1742        let output_tap = buffer.clone();
1743        assert!(buffer.ptr_eq(&output_tap));
1744
1745        buffer
1746            .as_texels(U32)
1747            .as_slice_of_cells()
1748            .iter()
1749            .enumerate()
1750            .for_each(|(idx, p)| p.set(idx as u32));
1751
1752        // Map those numbers in-place.
1753        buffer.map_within(..LEN, 0, |n: u32| n as u8, U32, U8);
1754        buffer.map_within(..LEN, 0, |n: u8| n as u32, U8, U32);
1755
1756        // Back to where we started.
1757        assert_eq!(
1758            output_tap.as_texels(U32).as_slice_of_cells()[..LEN]
1759                .iter()
1760                .map(cell::Cell::get)
1761                .collect::<Vec<_>>(),
1762            (0..LEN as u32).collect::<Vec<_>>()
1763        );
1764
1765        // This should work even if we don't map to index 0.
1766        buffer.map_within(0..LEN, 3 * LEN, |n: u32| n as u8, U32, U8);
1767        buffer.map_within(3 * LEN..4 * LEN, 0, |n: u8| n as u32, U8, U32);
1768
1769        assert_eq!(
1770            output_tap.as_texels(U32).as_slice_of_cells()[..LEN]
1771                .iter()
1772                .map(cell::Cell::get)
1773                .collect::<Vec<_>>(),
1774            (0..LEN as u32).collect::<Vec<_>>()
1775        );
1776    }
1777
1778    #[test]
1779    fn mapping_atomics() {
1780        const LEN: usize = 10;
1781        let mut initial_state = Buffer::new(LEN * mem::size_of::<u32>());
1782
1783        initial_state
1784            .as_mut_texels(U32)
1785            .iter_mut()
1786            .enumerate()
1787            .for_each(|(idx, p)| *p = idx as u32);
1788
1789        // Look, we can actually map over this buffer while it is *not* mutable.
1790        let buffer = AtomicBuffer::with_buffer(initial_state);
1791        // And receive all the results in this shared copy of our buffer.
1792        let output_tap = buffer.clone();
1793
1794        // Map those numbers in-place.
1795        buffer.map_within(..LEN, 0, |n: u32| n as u8, U32, U8);
1796        buffer.map_within(..LEN, 0, |n: u8| n as u32, U8, U32);
1797
1798        // Back to where we started.
1799        assert_eq!(
1800            output_tap.to_owned().as_texels(U32)[..LEN].to_vec(),
1801            (0..LEN as u32).collect::<Vec<_>>()
1802        );
1803
1804        // This should work even if we don't map to index 0.
1805        buffer.map_within(0..LEN, 3 * LEN, |n: u32| n as u8, U32, U8);
1806        buffer.map_within(3 * LEN..4 * LEN, 0, |n: u8| n as u32, U8, U32);
1807
1808        assert_eq!(
1809            output_tap.to_owned().as_texels(U32)[..LEN].to_vec(),
1810            (0..LEN as u32).collect::<Vec<_>>()
1811        );
1812    }
1813
1814    #[test]
1815    fn cell_construction() {
1816        let data = [const { MaxCell::zero() }; 10];
1817        let _empty = cell_buf::new(&data[..0]);
1818        let cell = cell_buf::new(&data);
1819
1820        let (first, tail) = cell.split_at(MAX_ALIGN);
1821        let another_first = cell_buf::new(&data[..1]);
1822
1823        let data: Vec<_> = (0u8..).take(MAX_ALIGN).collect();
1824        U8.store_cell_slice(first.as_texels(U8).as_slice_of_cells(), &data);
1825        let mut alternative: Vec<_> = (1u8..).take(MAX_ALIGN).collect();
1826        U8.load_cell_slice(
1827            another_first.as_texels(U8).as_slice_of_cells(),
1828            &mut alternative,
1829        );
1830
1831        // These two alias, so the read must have worked. Alternative must now be changed.
1832        assert_eq!(data, alternative);
1833
1834        U8.load_cell_slice(
1835            tail.truncate(MAX_ALIGN).as_texels(U8).as_slice_of_cells(),
1836            &mut alternative,
1837        );
1838        assert_ne!(data, alternative);
1839    }
1840
1841    #[test]
1842    #[should_panic]
1843    fn cell_unaligned_split() {
1844        let data = [const { MaxCell::zero() }; 10];
1845        // 1 is not an aligned index.
1846        cell_buf::new(&data).split_at(1);
1847    }
1848
1849    #[test]
1850    #[should_panic]
1851    fn cell_oob_split() {
1852        let data = [const { MaxCell::zero() }; 1];
1853        // this is out of bounds.
1854        cell_buf::new(&data).split_at(MAX_ALIGN + 1);
1855    }
1856
1857    #[test]
1858    fn cell_empty() {
1859        let empty = cell_buf::new(&[]);
1860        assert_eq!(empty.len(), 0);
1861    }
1862
1863    #[test]
1864    fn cell_from_bytes() {
1865        const SIZE: usize = 16;
1866
1867        let data = [0u8; SIZE].map(cell::Cell::new);
1868        let data: AlignMeUp<[_; SIZE]> = AlignMeUp([], data);
1869
1870        let empty = cell_buf::from_bytes(&data.1[..]).expect("this was properly aligned");
1871        assert_eq!(empty.len(), SIZE);
1872    }
1873
1874    #[test]
1875    fn cell_unaligned_from_bytes() {
1876        let data = [const { MaxCell::zero() }; 1];
1877        let unaligned = &cell_buf::new(&data).as_texels(U8).as_slice_of_cells()[1..];
1878        assert!(cell_buf::from_bytes(unaligned).is_none());
1879    }
1880
1881    #[test]
1882    fn cell_from_mut_bytes() {
1883        const SIZE: usize = 16;
1884        let mut data: AlignMeUp<[_; SIZE]> = AlignMeUp([], [0u8; SIZE]);
1885
1886        let empty = cell_buf::from_bytes_mut(&mut data.1[..]).expect("this was properly aligned");
1887        assert_eq!(empty.len(), SIZE);
1888    }
1889
1890    #[test]
1891    fn cell_unaligned_from_mut_bytes() {
1892        const SIZE: usize = 16;
1893        let mut data: AlignMeUp<[_; SIZE]> = AlignMeUp([], [0; SIZE]);
1894
1895        let unaligned = &mut data.1[1..];
1896        // Should fail since we must not be able to construct a buffer from unaligned bytes.
1897        assert!(cell_buf::from_bytes_mut(unaligned).is_none());
1898    }
1899
1900    #[test]
1901    fn cell_equality() {
1902        let data = [const { MaxCell::zero() }; 3];
1903        let lhs = cell_buf::new(&data[0..1]);
1904        let rhs = cell_buf::new(&data[1..2]);
1905
1906        let uneq = cell_buf::new(&data[2..3]);
1907        uneq.as_texels(U8).as_slice_of_cells()[0].set(1);
1908
1909        // No `Debug` hence.
1910        assert!(lhs == lhs, "Must be equal with itself");
1911        assert!(lhs == rhs, "Must be equal with same data");
1912        assert!(lhs != uneq, "Must only be equal with same data");
1913
1914        let mut buffer = [0x42; mem::size_of::<MaxCell>()];
1915        assert!(*lhs != buffer[..], "Must only be equal with its data");
1916
1917        U8.load_cell_slice(lhs.as_texels(U8).as_slice_of_cells(), &mut buffer);
1918        assert!(*lhs == buffer[..], "Must be equal with its data");
1919    }
1920
1921    #[test]
1922    fn atomic_empty() {
1923        let empty = atomic_buf::new(&[]);
1924        assert_eq!(empty.len(), 0);
1925    }
1926
1927    #[test]
1928    fn atomic_construction() {
1929        let data = [const { MaxAtomic::zero() }; 10];
1930        let cell = atomic_buf::new(&data);
1931
1932        let (first, tail) = cell.split_at(MAX_ALIGN);
1933        let another_first = atomic_buf::new(&data[..1]);
1934        assert_eq!(another_first.as_texels(U8).len(), MAX_ALIGN);
1935        assert_eq!(first.as_texels(U8).len(), MAX_ALIGN);
1936
1937        let data: Vec<_> = (0u8..).take(MAX_ALIGN).collect();
1938        first.as_texels(U8).read_from_slice(&data);
1939        let mut alternative: Vec<_> = (1u8..).take(MAX_ALIGN).collect();
1940        another_first.as_texels(U8).write_to_slice(&mut alternative);
1941
1942        // These two alias, so the read must have worked. Alternative must now be changed.
1943        assert_eq!(data, alternative);
1944
1945        // And the tail does not alias, so we reset alternative back to zero.
1946        tail.as_texels(U8)
1947            .index(..MAX_ALIGN)
1948            .write_to_slice(&mut alternative);
1949        assert_ne!(data, alternative);
1950
1951        let another_first = atomic_buf::from_bytes(first.as_texels(U8))
1952            .expect("the whole buffer is always aligned");
1953        another_first.as_texels(U8).write_to_slice(&mut alternative);
1954        assert_eq!(data, alternative);
1955    }
1956
1957    #[test]
1958    fn atomic_from_bytes() {
1959        let data = [const { MaxAtomic::zero() }; 1];
1960        let cell = atomic_buf::new(&data);
1961
1962        // Best way to get a buffer is to get it from an existing one..
1963        let data = cell.as_texels(U8);
1964        let new_buf = atomic_buf::from_bytes(data).expect("this was properly aligned");
1965        assert_eq!(new_buf.len(), MAX_ALIGN);
1966    }
1967
1968    #[test]
1969    fn atomic_unaligned_from_bytes() {
1970        let data = [const { MaxAtomic::zero() }; 1];
1971        let cell = atomic_buf::new(&data);
1972
1973        let unaligned = cell.as_texels(U8).index(1..);
1974        assert!(atomic_buf::from_bytes(unaligned).is_none());
1975    }
1976
1977    #[test]
1978    fn atomic_from_mut_bytes() {
1979        const SIZE: usize = MAX_ALIGN * 2;
1980        let mut data: AlignMeUp<[_; SIZE]> = AlignMeUp([], [0u8; SIZE]);
1981
1982        let empty = atomic_buf::from_bytes_mut(&mut data.1[..]).expect("this was properly aligned");
1983        assert_eq!(empty.len(), SIZE);
1984    }
1985
1986    #[test]
1987    fn atomic_too_small_from_mut_bytes() {
1988        const SIZE: usize = MAX_ALIGN / 2;
1989        let mut data: AlignMeUp<[_; SIZE]> = AlignMeUp([], [0; SIZE]);
1990
1991        let unaligned = &mut data.1[1..];
1992        // Should fail since we must not be able to construct a buffer out of smaller units to
1993        // avoid differing type behavior.
1994        assert!(atomic_buf::from_bytes_mut(unaligned).is_none());
1995    }
1996
1997    #[test]
1998    fn atomic_unaligned_from_mut_bytes() {
1999        const SIZE: usize = 16;
2000        let mut data: AlignMeUp<[_; SIZE]> = AlignMeUp([], [0; SIZE]);
2001
2002        let unaligned = &mut data.1[1..];
2003        // Should fail since we must not be able to construct a buffer from unaligned bytes.
2004        assert!(atomic_buf::from_bytes_mut(unaligned).is_none());
2005    }
2006
2007    #[test]
2008    fn atomic_equality() {
2009        let data = [const { MaxAtomic::zero() }; 3];
2010        let lhs = atomic_buf::new(&data[0..1]);
2011        let rhs = atomic_buf::new(&data[1..2]);
2012
2013        let uneq = atomic_buf::new(&data[2..3]);
2014        U8.store_atomic(uneq.as_texels(U8).index_one(0), 1);
2015
2016        // No `Debug` hence.
2017        assert!(lhs == lhs, "Must be equal with itself");
2018        assert!(lhs == rhs, "Must be equal with same data");
2019        assert!(lhs != uneq, "Must only be equal with same data");
2020
2021        let mut buffer = [0x42; mem::size_of::<MaxCell>()];
2022        assert!(*lhs != buffer[..], "Must only be equal with its data");
2023
2024        U8.load_atomic_slice(lhs.as_texels(U8), &mut buffer);
2025        assert!(*lhs == buffer[..], "Must be equal with its data");
2026    }
2027
2028    #[test]
2029    fn atomic_with_u8() {
2030        // Check that writing and reading works at different offsets.
2031        for offset in 0..MAX_ALIGN {
2032            let slice = [const { MaxAtomic::zero() }; 4];
2033            let atomic = atomic_buf::new(&slice[..]);
2034
2035            let mut iota = 0;
2036            let data = [(); 3 * MAX_ALIGN].map(move |_| {
2037                let n = iota;
2038                iota += 1;
2039                n
2040            });
2041
2042            let target = atomic.as_texels(U8).index(offset..).index(..3 * MAX_ALIGN);
2043            U8.store_atomic_slice(target, &data[..]);
2044
2045            let mut check = [0; 3 * MAX_ALIGN];
2046            U8.load_atomic_slice(target, &mut check[..]);
2047
2048            let cells = [const { core::cell::Cell::new(0) }; 3 * MAX_ALIGN];
2049            U8.load_atomic_to_cells(target, &cells[..]);
2050
2051            assert_eq!(data, check);
2052            assert_eq!(data, cells.map(|x| x.into_inner()));
2053
2054            let mut check = [0; 4 * MAX_ALIGN];
2055            U8.load_atomic_slice(atomic.as_texels(U8), &mut check[..]);
2056
2057            assert_eq!(data, check[offset..][..3 * MAX_ALIGN], "offset {offset}");
2058        }
2059    }
2060
2061    #[test]
2062    fn atomic_with_u16() {
2063        use crate::texels::U16;
2064
2065        // Check that writing and reading works at different offsets.
2066        for offset in 0..MAX_ALIGN / 2 {
2067            let slice = [const { MaxAtomic::zero() }; 4];
2068            let atomic = atomic_buf::new(&slice[..]);
2069
2070            let mut iota = 0;
2071            let data = [(); 3 * MAX_ALIGN / 2].map(move |_| {
2072                let n = iota;
2073                iota += 1;
2074                n
2075            });
2076
2077            let target = atomic
2078                .as_texels(U16)
2079                .index(offset..)
2080                .index(..3 * MAX_ALIGN / 2);
2081            U16.store_atomic_slice(target, &data[..]);
2082
2083            let mut check = [0; 3 * MAX_ALIGN / 2];
2084            U16.load_atomic_slice(target, &mut check[..]);
2085
2086            let cells = [const { core::cell::Cell::new(0) }; 3 * MAX_ALIGN / 2];
2087            U16.load_atomic_to_cells(target, &cells[..]);
2088
2089            assert_eq!(data, check);
2090            assert_eq!(data, cells.map(|x| x.into_inner()));
2091        }
2092    }
2093
2094    #[test]
2095    fn atomic_from_cells() {
2096        for offset in 0..4 {
2097            let data = [const { MaxAtomic::zero() }; 1];
2098            let lhs = atomic_buf::new(&data[0..1]);
2099
2100            let data = [const { MaxCell::zero() }; 1];
2101            let rhs = cell_buf::new(&data[0..1]);
2102
2103            // Create a value that checks we write to the correct bytes.
2104            let source = rhs.as_texels(U8).as_slice_of_cells();
2105            U8.store_cell_slice(&source[4..8], &[0x84; 4]);
2106            U8.store_cell_slice(&source[2..4], &[1, 2]);
2107            let source = &source[..8 - offset];
2108            // Initialize the first 8 bytes of the atomic.
2109            U8.store_atomic_from_cells(lhs.as_texels(U8).index(offset..8), source);
2110
2111            let mut buffer = [0x42; mem::size_of::<MaxCell>()];
2112            U8.load_atomic_slice(lhs.as_texels(U8), &mut buffer);
2113
2114            assert!(
2115                buffer[..offset].iter().all(|&x| x == 0),
2116                "Must still be unset",
2117            );
2118
2119            assert!(
2120                buffer[offset..][..4] == [0, 0, 1, 2],
2121                "Must contain the data",
2122            );
2123
2124            assert!(
2125                buffer[offset..8][4..].iter().all(|&x| x == 0x84),
2126                "Must be initialized by tail {:?}",
2127                &buffer[offset..][4..],
2128            );
2129        }
2130    }
2131
2132    #[test]
2133    fn atomic_to_cells() {
2134        for offset in 0..4 {
2135            let data = [const { MaxAtomic::zero() }; 1];
2136            let lhs = atomic_buf::new(&data[0..1]);
2137
2138            let data = [const { MaxCell::zero() }; 1];
2139            let rhs = cell_buf::new(&data[0..1]);
2140
2141            U8.store_atomic_slice(lhs.as_texels(U8).index(4..8), &[0x84; 4]);
2142            U8.store_atomic_slice(lhs.as_texels(U8).index(offset..).index(..4), &[0, 0, 1, 2]);
2143
2144            // Create a value that checks we write to the correct bytes.
2145            let target = rhs.as_texels(U8).as_slice_of_cells();
2146            // Initialize the first 8 bytes of the atomic.
2147            U8.load_atomic_to_cells(lhs.as_texels(U8).index(offset..8), &target[..8 - offset]);
2148
2149            let mut buffer = [0x42; mem::size_of::<MaxCell>()];
2150            U8.load_cell_slice(target, &mut buffer);
2151
2152            assert!(
2153                buffer[..4] == [0, 0, 1, 2],
2154                "Must contain the data {:?}",
2155                &buffer[..4],
2156            );
2157
2158            assert!(
2159                buffer[..8 - offset][4..].iter().all(|&x| x == 0x84),
2160                "Must be initialized by tail {:?}",
2161                &buffer[..8 - offset][4..],
2162            );
2163        }
2164    }
2165
2166    #[test]
2167    fn atomic_memory_move() {
2168        const COPY_LEN: usize = 3 * core::mem::size_of::<MaxAtomic>();
2169        const TOTAL_LEN: usize = 4 * core::mem::size_of::<MaxAtomic>();
2170
2171        for offset in 0..4 {
2172            let data = [const { MaxAtomic::zero() }; 4];
2173            let lhs = atomic_buf::new(&data[..]);
2174
2175            let data = [const { MaxAtomic::zero() }; 4];
2176            let rhs = atomic_buf::new(&data[..]);
2177
2178            U8.store_atomic_slice(lhs.as_texels(U8).index(0..4), b"helo");
2179
2180            U8.atomic_memory_move(
2181                lhs.as_texels(U8).index(offset..offset + COPY_LEN),
2182                rhs.as_texels(U8).index(0..COPY_LEN),
2183            );
2184
2185            let mut buffer = [0x42; TOTAL_LEN];
2186            U8.load_atomic_slice(rhs.as_texels(U8), &mut buffer);
2187
2188            assert_eq!(buffer[..4], b"helo\0\0\0\0"[offset..][..4]);
2189        }
2190    }
2191}