retrofire_core/util/
buf.rs

1//! Two-dimensional buffers, with owned and borrowed variants.
2//!
3//! Useful for storing pixel data of any kind, among other things.
4
5use alloc::{vec, vec::Vec};
6use core::{
7    fmt::{self, Debug, Formatter},
8    iter,
9    ops::{Deref, DerefMut},
10};
11
12use super::Dims;
13
14use inner::Inner;
15
16//
17// Traits
18//
19
20/// A trait for types that can provide a view of their data as a [`Slice2`].
21pub trait AsSlice2<T> {
22    /// Returns a borrowed `Slice2` view of `Self`.
23    fn as_slice2(&self) -> Slice2<'_, T>;
24}
25
26/// A trait for types that can provide a mutable view of their data
27/// as a [`MutSlice2`].
28pub trait AsMutSlice2<T> {
29    /// Returns a mutably borrowed `MutSlice2` view of `Self`.
30    fn as_mut_slice2(&mut self) -> MutSlice2<'_, T>;
31}
32
33//
34// Types
35//
36
37/// A rectangular 2D buffer that owns its elements, backed by a `Vec`.
38///
39/// Unlike `Vec`, however, `Buf2` cannot be resized after construction
40/// without explicitly copying the contents to a new, larger buffer.
41///
42/// `Buf2` stores its elements contiguously, in standard row-major order,
43/// such that the coordinate pair (x, y) maps to index `buf.width() * y + x`
44/// in the backing vector.
45///
46/// # Examples
47/// ```
48/// # use retrofire_core::util::buf::Buf2;
49/// # use retrofire_core::math::point::pt2;
50/// // Elements initialized with `Default::default()`
51/// let mut buf = Buf2::new((4, 4));
52/// // Indexing with a 2D point (x, y) yields element at row y, column x:
53/// buf[pt2(2, 1)] = 123;
54/// // Indexing with an usize i yields row with index i as a slice:
55/// assert_eq!(buf[1], [0, 0, 123, 0]);
56/// // Thus you can also do this, row first, column second:
57/// assert_eq!(buf[1][2], 123)
58/// ```
59#[derive(Clone, Eq, PartialEq)]
60#[repr(transparent)]
61pub struct Buf2<T>(Inner<T, Vec<T>>);
62
63/// An immutable rectangular view to a region of a [`Buf2`], another `Slice2`,
64/// or in general any `&[T]` slice of memory. A two-dimensional analog to `&[T]`.
65///
66/// A `Slice2` may be non-contiguous:
67/// ```text
68/// +------stride-----+
69/// |    ____w____    |
70/// |   |r0_______|   |
71/// |   |r1_______| h |
72/// |   |r2_______|   |
73/// +-----------------+
74/// ```
75/// TODO More documentation
76#[derive(Copy, Clone, Eq, PartialEq)]
77#[repr(transparent)]
78pub struct Slice2<'a, T>(Inner<T, &'a [T]>);
79
80/// A mutable rectangular view to a region of a `Buf2`, a `Slice2`,
81/// or in general any `&[T]` slice of memory.
82#[repr(transparent)]
83pub struct MutSlice2<'a, T>(Inner<T, &'a mut [T]>);
84
85//
86// Inherent impls
87//
88
89impl<T> Buf2<T> {
90    /// Returns a buffer of size `w` × `h`, with elements initialized
91    /// with values yielded by `init`.
92    ///
93    /// The elements are initialized in row-major order. Does not allocate
94    /// or consume items from `init` if `w` = 0 or `h` = 0.
95    ///
96    /// # Examples
97    /// ```
98    /// use retrofire_core::util::buf::Buf2;
99    ///
100    /// let buf = Buf2::new_from((3, 3), 1..);
101    ///
102    /// assert_eq!(buf.dims(), (3, 3));
103    /// assert_eq!(buf.data(), [1, 2, 3,
104    ///                         4, 5, 6,
105    ///                         7, 8, 9]);
106    /// ```
107    ///
108    /// # Panics
109    /// * If `w * h > isize::MAX`, or
110    /// * if `init` has fewer than `w * h` elements.
111    pub fn new_from<I>((w, h): Dims, init: I) -> Self
112    where
113        I: IntoIterator<Item = T>,
114    {
115        let ww = isize::try_from(w).ok();
116        let hh = isize::try_from(h).ok();
117        let len = ww.and_then(|w| hh.and_then(|h| w.checked_mul(h)));
118        let Some(len) = len else {
119            panic!(
120                "w * h cannot exceed isize::MAX ({w} * {h} > {})",
121                isize::MAX
122            );
123        };
124        let data: Vec<_> = init.into_iter().take(len as usize).collect();
125        assert_eq!(
126            data.len(),
127            len as usize,
128            "insufficient items in iterator ({} < {len}",
129            data.len()
130        );
131        Self(Inner::new((w, h), w, data))
132    }
133
134    /// Returns a buffer of size `w` × `h`, with every element initialized to
135    /// `T::default()`.
136    ///
137    /// Does not allocate if `w` = 0 or `h` = 0.
138    ///
139    /// # Examples
140    /// ```
141    /// use retrofire_core::util::buf::Buf2;
142    ///
143    /// let buf: Buf2<i32> = Buf2::new((3, 3));
144    ///
145    /// assert_eq!(buf.dims(), (3, 3));
146    /// assert_eq!(buf.data(), [0, 0, 0,
147    ///                         0, 0, 0,
148    ///                         0, 0, 0]);
149    /// ```
150    ///
151    /// # Panics
152    /// If `w * h > isize::MAX`.
153    pub fn new((w, h): Dims) -> Self
154    where
155        T: Default + Clone,
156    {
157        let data = vec![T::default(); (w * h) as usize];
158        Self(Inner::new((w, h), w, data))
159    }
160
161    /// Returns a buffer of size `w` × `h`, initialized by repeatedly calling
162    /// the given function.
163    ///
164    /// For each element, `init_fn(x, y)` is invoked, where `x` is the column
165    /// index and `y` the row index of the element being initialized. The
166    /// elements are initialized in row-major order.
167    ///
168    /// Does not allocate or call `init_fn` if `w` = 0 or `h` = 0.
169    ///
170    /// # Examples
171    /// ```
172    /// use retrofire_core::util::buf::Buf2;
173    ///
174    /// let buf = Buf2::new_with((3, 3), |x, y| 10 * y + x);
175    /// assert_eq!(buf.data(), [ 0,  1, 2,
176    ///                         10, 11, 12,
177    ///                         20, 21, 22]);
178    /// ```
179    ///
180    /// # Panics
181    /// If `w * h > isize::MAX`.
182    pub fn new_with<F>((w, h): Dims, mut init_fn: F) -> Self
183    where
184        F: FnMut(u32, u32) -> T,
185    {
186        let (mut x, mut y) = (0, 0);
187        Self::new_from(
188            (w, h),
189            iter::from_fn(|| {
190                let res = init_fn(x, y);
191                x += 1;
192                if x == w {
193                    (x, y) = (0, y + 1);
194                }
195                Some(res)
196            }),
197        )
198    }
199
200    /// Returns a view of the backing data of `self`.
201    pub fn data(&self) -> &[T] {
202        self.0.data()
203    }
204
205    /// Returns a mutable view of the backing data of `self`.
206    pub fn data_mut(&mut self) -> &mut [T] {
207        self.0.data_mut()
208    }
209
210    /// Reinterprets `self` as a buffer of different dimensions but same area.
211    ///
212    /// # Panics
213    /// If `nw` * `nh` != `cw` * `ch` for the new dimensions (`nw`, `nh`)
214    /// and current dimensions (`cw`, `ch`).
215    pub fn reshape(&mut self, dims: Dims) {
216        self.0.reshape(dims);
217    }
218}
219
220impl<'a, T> Slice2<'a, T> {
221    /// Returns a new `Slice2` view to `data` with the given dimensions
222    /// and stride.
223    ///
224    /// # Examples
225    /// ```
226    /// # use retrofire_core::util::buf::Slice2;
227    /// let data = &[0, 1, 2, 3, 4, 5, 6];
228    /// let slice = Slice2::new((2, 2), 3, data);
229    /// assert_eq!(&slice[0], &[0, 1]);
230    /// assert_eq!(&slice[1], &[3, 4]);
231    /// ```
232    /// Above, `slice` represents a 2×2 rectangle with stride 3, such that
233    /// the first row maps to `data[0..2]` and the second to `data[3..5]`:
234    /// ```text
235    ///  slice[0]    slice[1]
236    ///     |           |
237    /// ,---´---.   ,---´---.
238    /// +---+---+---+---+---+---+---+
239    /// | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
240    /// +---+---+---+---+---+---+---+
241    /// ```
242    /// Internally, this is implemented as the borrow `&data[0..5]`.
243    /// Semantically, however, `slice` does not contain `data[2]` as
244    /// an element, and attempting to access it eg. with `slice[0][2]`
245    /// will panic, as expected.
246    ///
247    /// # Panics
248    /// if `stride < width` or if the slice would overflow `data`.
249    ///
250    pub fn new(dims: Dims, stride: u32, data: &'a [T]) -> Self {
251        Self(Inner::new(dims, stride, data))
252    }
253}
254
255impl<'a, T> MutSlice2<'a, T> {
256    /// Returns a new `MutSlice2` view to `data` with dimensions `w` and `h`
257    /// and stride `stride`.
258    ///
259    /// See [`Slice2::new`] for more information.
260    pub fn new(dims: Dims, stride: u32, data: &'a mut [T]) -> Self {
261        Self(Inner::new(dims, stride, data))
262    }
263}
264
265//
266// Local trait impls
267//
268
269impl<T> AsSlice2<T> for Buf2<T> {
270    #[inline]
271    fn as_slice2(&self) -> Slice2<'_, T> {
272        self.0.as_slice2()
273    }
274}
275impl<T> AsSlice2<T> for &Buf2<T> {
276    #[inline]
277    fn as_slice2(&self) -> Slice2<'_, T> {
278        self.0.as_slice2()
279    }
280}
281impl<T> AsSlice2<T> for Slice2<'_, T> {
282    #[inline]
283    fn as_slice2(&self) -> Slice2<'_, T> {
284        self.0.as_slice2()
285    }
286}
287impl<T> AsSlice2<T> for MutSlice2<'_, T> {
288    #[inline]
289    fn as_slice2(&self) -> Slice2<'_, T> {
290        self.0.as_slice2()
291    }
292}
293
294impl<T> AsMutSlice2<T> for Buf2<T> {
295    #[inline]
296    fn as_mut_slice2(&mut self) -> MutSlice2<'_, T> {
297        self.0.as_mut_slice2()
298    }
299}
300impl<T> AsMutSlice2<T> for &mut Buf2<T> {
301    #[inline]
302    fn as_mut_slice2(&mut self) -> MutSlice2<'_, T> {
303        self.0.as_mut_slice2()
304    }
305}
306impl<T> AsMutSlice2<T> for MutSlice2<'_, T> {
307    #[inline]
308    fn as_mut_slice2(&mut self) -> MutSlice2<'_, T> {
309        self.0.as_mut_slice2()
310    }
311}
312
313//
314// Foreign trait impls
315//
316
317impl<T> Debug for Buf2<T> {
318    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
319        self.0.debug_fmt(f, "Buf2")
320    }
321}
322impl<T> Debug for Slice2<'_, T> {
323    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
324        self.0.debug_fmt(f, "Slice2")
325    }
326}
327impl<T> Debug for MutSlice2<'_, T> {
328    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
329        self.0.debug_fmt(f, "MutSlice2")
330    }
331}
332
333impl<T> Deref for Buf2<T> {
334    type Target = Inner<T, Vec<T>>;
335    fn deref(&self) -> &Self::Target {
336        &self.0
337    }
338}
339impl<'a, T> Deref for Slice2<'a, T> {
340    type Target = Inner<T, &'a [T]>;
341    fn deref(&self) -> &Self::Target {
342        &self.0
343    }
344}
345impl<'a, T> Deref for MutSlice2<'a, T> {
346    type Target = Inner<T, &'a mut [T]>;
347    fn deref(&self) -> &Self::Target {
348        &self.0
349    }
350}
351
352impl<T> DerefMut for Buf2<T> {
353    fn deref_mut(&mut self) -> &mut Self::Target {
354        &mut self.0
355    }
356}
357impl<'a, T> DerefMut for MutSlice2<'a, T> {
358    fn deref_mut(&mut self) -> &mut Self::Target {
359        &mut self.0
360    }
361}
362
363pub mod inner {
364    use core::{
365        fmt::Formatter,
366        iter::zip,
367        marker::PhantomData,
368        ops::{Deref, DerefMut, Index, IndexMut, Range},
369    };
370
371    use crate::{
372        math::point::Point2u,
373        util::{Dims, rect::Rect},
374    };
375
376    use super::{AsSlice2, MutSlice2, Slice2};
377
378    /// A helper type that abstracts over owned and borrowed buffers.
379    ///
380    /// The types `Buf2`, `Slice2`, and `MutSlice2` deref to `Inner`.
381    #[derive(Copy, Clone, Eq, PartialEq)]
382    pub struct Inner<T, D> {
383        dims: Dims,
384        stride: u32,
385        data: D,
386        _pd: PhantomData<T>,
387    }
388
389    impl<T, D> Inner<T, D> {
390        /// Returns the width of `self`.
391        #[inline]
392        pub fn width(&self) -> u32 {
393            self.dims.0
394        }
395        /// Returns the height of `self`.
396        #[inline]
397        pub fn height(&self) -> u32 {
398            self.dims.1
399        }
400        /// Returns the width and height of `self`.
401        #[inline]
402        pub fn dims(&self) -> Dims {
403            self.dims
404        }
405        /// Returns the stride of `self`.
406        #[inline]
407        pub fn stride(&self) -> u32 {
408            self.stride
409        }
410        /// Returns whether the rows of `self` are stored as one contiguous
411        /// slice, without gaps between rows.
412        ///
413        /// `Buf2` instances are always contiguous. A `Slice2` or `MutSlice2`
414        /// instance is contiguous if its width equals its stride, if its
415        /// height is 1, or if it is empty.
416        pub fn is_contiguous(&self) -> bool {
417            let (w, h) = self.dims;
418            self.stride == w || h <= 1 || w == 0
419        }
420        /// Returns whether `self` contains no elements.
421        pub fn is_empty(&self) -> bool {
422            self.dims.0 == 0 || self.dims.1 == 0
423        }
424
425        /// Returns the linear index corresponding to the coordinates,
426        /// even if out of bounds.
427        #[inline]
428        fn to_index(&self, x: u32, y: u32) -> usize {
429            (y * self.stride + x) as usize
430        }
431
432        /// Returns the linear index corresponding to the coordinates,
433        /// or panics if either x or y is out of bounds.
434        #[inline]
435        fn to_index_strict(&self, x: u32, y: u32) -> usize {
436            self.to_index_checked(x, y).unwrap_or_else(|| {
437                let (w, h) = self.dims;
438                panic!(
439                    "position (x={x}, y={y}) out of bounds (0..{w}, 0..{h})",
440                )
441            })
442        }
443        /// Returns the linear index corresponding to the coordinates,
444        /// or `None` if x or y is out of bounds.
445        #[inline]
446        fn to_index_checked(&self, x: u32, y: u32) -> Option<usize> {
447            let (w, h) = self.dims;
448            (x < w && y < h).then(|| self.to_index(x, y))
449        }
450
451        /// Returns the dimensions and linear range corresponding to the rect.
452        fn resolve_bounds(&self, rect: &Rect<u32>) -> (Dims, Range<usize>) {
453            let (w, h) = self.dims;
454
455            let l = rect.left.unwrap_or(0);
456            let t = rect.top.unwrap_or(0);
457            let r = rect.right.unwrap_or(w);
458            let b = rect.bottom.unwrap_or(h);
459
460            // Assert that left <= right <= width and top <= bottom <= height.
461            // Note that this permits left == width or top == height, but only
462            // when left == right or top == bottom, that is, when the range is
463            // empty. This matches the way slice indexing works.
464            assert!(l <= r, "range left ({l}) > right ({r})");
465            assert!(t <= b, "range top ({l}) > bottom ({r})");
466            assert!(r <= w, "range right ({r}) > width ({w})");
467            assert!(b <= h, "range bottom ({b}) > height ({h})");
468
469            // (l, t) is now guaranteed to be in bounds
470            let start = self.to_index(l, t);
471            // Slice end is the end of the last row
472            let end = if b == t {
473                self.to_index(r, t)
474            } else {
475                // b != 0 because b >= t && b != t
476                self.to_index(r, b - 1)
477            };
478            ((r - l, b - t), start..end)
479        }
480
481        /// A helper for implementing `Debug`.
482        pub(super) fn debug_fmt(
483            &self,
484            f: &mut Formatter,
485            name: &str,
486        ) -> core::fmt::Result {
487            f.debug_struct(name)
488                .field("dims", &self.dims)
489                .field("stride", &self.stride)
490                .finish()
491        }
492
493        pub(super) fn reshape(&mut self, dims: Dims) {
494            assert!(self.is_contiguous());
495            assert_eq!(dims.0 * dims.1, self.dims.0 * self.dims.1);
496            self.dims = dims;
497        }
498    }
499
500    impl<T, D: Deref<Target = [T]>> Inner<T, D> {
501        /// # Panics
502        /// if `stride < w` or if the slice would overflow `data`.
503        #[rustfmt::skip]
504        pub(super) fn new(dims @ (w, h): Dims, stride: u32, data: D) -> Self {
505            assert!(w <= stride, "width ({w}) > stride ({stride})");
506
507            let len = data.len();
508            assert!(
509                h <= 1 || stride as usize <= len,
510                "stride ({stride}) > data length ({len})"
511            );
512            assert!(h as usize <= len, "height ({h}) > data length ({len})");
513            if h > 0 {
514                let size = (h - 1) * stride + w;
515                assert!(
516                    size as usize <= len,
517                    "required size ({size}) > data length ({len})"
518                );
519            }
520            Self { dims, stride, data, _pd: PhantomData }
521        }
522
523        /// Returns the data of `self` as a linear slice.
524        pub(super) fn data(&self) -> &[T] {
525            &self.data
526        }
527
528        /// Borrows `self` as a `Slice2`.
529        #[inline]
530        pub fn as_slice2(&self) -> Slice2<'_, T> {
531            let Self { dims, stride, ref data, _pd } = *self;
532            Slice2(Inner { dims, stride, data, _pd })
533        }
534
535        /// Returns a borrowed rectangular slice of `self`.
536        ///
537        /// # Panics
538        /// If any part of `rect` is outside the bounds of `self`.
539        pub fn slice(&self, rect: impl Into<Rect>) -> Slice2<'_, T> {
540            let (dims, rg) = self.resolve_bounds(&rect.into());
541            Slice2::new(dims, self.stride, &self.data[rg])
542        }
543
544        /// Returns a reference to the element at `pos`,
545        /// or `None` if `pos` is out of bounds.
546        pub fn get(&self, pos: impl Into<Point2u>) -> Option<&T> {
547            let [x, y] = pos.into().0;
548            self.to_index_checked(x, y).map(|i| &self.data[i])
549        }
550
551        /// Returns an iterator over the rows of `self` as `&[T]` slices.
552        ///
553        /// The length of each slice equals [`self.width()`](Self::width).
554        pub fn rows(&self) -> impl Iterator<Item = &[T]> {
555            self.data
556                .chunks(self.stride as usize)
557                .map(|row| &row[..self.dims.0 as usize])
558        }
559
560        /// Returns an iterator over the elements of `self` in row-major order.
561        ///
562        /// First returns the elements on row 0 from left to right, followed by
563        /// the elements on row 1, and so on.
564        pub fn iter(&self) -> impl Iterator<Item = &'_ T> {
565            self.rows().flatten()
566        }
567    }
568
569    impl<T, D: DerefMut<Target = [T]>> Inner<T, D> {
570        /// Returns a mutably borrowed rectangular slice of `self`.
571        #[inline]
572        pub fn as_mut_slice2(&mut self) -> MutSlice2<'_, T> {
573            #[rustfmt::skip]
574            let Self { dims, stride, ref mut data, _pd, } = *self;
575            MutSlice2(Inner { dims, stride, data, _pd })
576        }
577
578        /// Returns the data of `self` as a single mutable slice.
579        pub(super) fn data_mut(&mut self) -> &mut [T] {
580            &mut self.data
581        }
582
583        /// Returns an iterator over the rows of this buffer as `&mut [T]`.
584        ///
585        /// The length of each slice equals [`self.width()`](Self::width).
586        pub fn rows_mut(&mut self) -> impl Iterator<Item = &mut [T]> {
587            self.data
588                .chunks_mut(self.stride as usize)
589                .map(|row| &mut row[..self.dims.0 as usize])
590        }
591
592        /// Returns a mutable iterator over all the elements of `self`,
593        /// yielded in row-major order.
594        pub fn iter_mut(&mut self) -> impl Iterator<Item = &'_ mut T> {
595            self.rows_mut().flatten()
596        }
597
598        /// Fills `self` with clones of the value.
599        pub fn fill(&mut self, val: T)
600        where
601            T: Clone,
602        {
603            if self.is_contiguous() {
604                self.data.fill(val);
605            } else {
606                self.rows_mut()
607                    .for_each(|row| row.fill(val.clone()));
608            }
609        }
610        /// Fills `self` by calling a function for each element.
611        ///
612        /// Calls `f(x, y)` for every element, where  `x` and `y` are the column
613        /// and row indices of the element. Proceeds in row-major order.
614        pub fn fill_with<F>(&mut self, mut fill_fn: F)
615        where
616            F: FnMut(u32, u32) -> T,
617        {
618            for (row, y) in zip(self.rows_mut(), 0..) {
619                for (item, x) in zip(row, 0..) {
620                    *item = fill_fn(x, y);
621                }
622            }
623        }
624
625        /// Copies each element in `other` to the same position in `self`.
626        ///
627        /// This operation is often called "blitting".
628        ///
629        /// # Panics
630        /// if the dimensions of `self` and `other` do not match.
631        #[doc(alias = "blit")]
632        pub fn copy_from(&mut self, other: impl AsSlice2<T>)
633        where
634            T: Copy,
635        {
636            let other = other.as_slice2();
637
638            assert_eq!(
639                self.dims, other.dims,
640                "dimension mismatch (self: {:?}, other: {:?})",
641                self.dims, other.dims
642            );
643            for (dest, src) in self.rows_mut().zip(other.rows()) {
644                dest.copy_from_slice(src);
645            }
646        }
647
648        /// Returns a mutable reference to the element at `pos`,
649        /// or `None` if `pos` is out of bounds.
650        pub fn get_mut(&mut self, pos: impl Into<Point2u>) -> Option<&mut T> {
651            let [x, y] = pos.into().0;
652            self.to_index_checked(x, y)
653                .map(|i| &mut self.data[i])
654        }
655
656        /// Returns a mutably borrowed rectangular slice of `self`.
657        ///
658        /// # Panics
659        /// If any part of `rect` is outside the bounds of `self`.
660        pub fn slice_mut(&mut self, rect: impl Into<Rect>) -> MutSlice2<'_, T> {
661            let (dims, rg) = self.resolve_bounds(&rect.into());
662            MutSlice2(Inner::new(dims, self.stride, &mut self.data[rg]))
663        }
664    }
665
666    impl<T, D: Deref<Target = [T]>> Index<usize> for Inner<T, D> {
667        type Output = [T];
668
669        /// Returns a reference to the row at index `i`.
670        ///
671        /// The returned slice has length `self.width()`.
672        ///
673        /// # Panics
674        /// If `row >= self.height()`.
675        #[inline]
676        fn index(&self, i: usize) -> &[T] {
677            let idx = self.to_index_strict(0, i as u32);
678            let w = self.dims.0 as usize;
679            &self.data[idx..][..w]
680        }
681    }
682
683    impl<T, D> IndexMut<usize> for Inner<T, D>
684    where
685        Self: Index<usize, Output = [T]>,
686        D: DerefMut<Target = [T]>,
687    {
688        /// Returns a mutable reference to the row at index `i`.
689        ///
690        /// The returned slice has length `self.width()`.
691        ///
692        /// # Panics
693        /// If `row >= self.height()`.
694        #[inline]
695        fn index_mut(&mut self, row: usize) -> &mut [T] {
696            let idx = self.to_index_strict(0, row as u32);
697            let w = self.dims.0 as usize;
698            &mut self.data[idx..][..w]
699        }
700    }
701
702    impl<T, D, Pos> Index<Pos> for Inner<T, D>
703    where
704        D: Deref<Target = [T]>,
705        Pos: Into<Point2u>,
706    {
707        type Output = T;
708
709        /// Returns a reference to the element at position `pos`.
710        ///
711        /// # Panics
712        /// If `pos` is out of bounds.
713        #[inline]
714        fn index(&self, pos: Pos) -> &T {
715            let [x, y] = pos.into().0;
716            &self.data[self.to_index_strict(x, y)]
717        }
718    }
719
720    impl<T, D, Pos> IndexMut<Pos> for Inner<T, D>
721    where
722        D: DerefMut<Target = [T]>,
723        Pos: Into<Point2u>,
724    {
725        /// Returns a mutable reference to the element at position `pos`.
726        ///
727        /// # Panics
728        /// If `pos` is out of bounds.
729        #[inline]
730        fn index_mut(&mut self, pos: Pos) -> &mut T {
731            let [x, y] = pos.into().0;
732            let idx = self.to_index_strict(x, y);
733            &mut self.data[idx]
734        }
735    }
736}
737
738#[cfg(test)]
739mod tests {
740    use crate::math::pt2;
741
742    use super::*;
743
744    #[test]
745    fn buf_new_from() {
746        let buf = Buf2::new_from((3, 2), 1..);
747        assert_eq!(buf.data(), &[1, 2, 3, 4, 5, 6]);
748    }
749
750    #[test]
751    fn buf_new() {
752        let buf: Buf2<i32> = Buf2::new((3, 2));
753        assert_eq!(buf.data(), &[0, 0, 0, 0, 0, 0]);
754    }
755
756    #[test]
757    fn buf_new_with() {
758        let buf = Buf2::new_with((3, 2), |x, y| x + y);
759        assert_eq!(buf.data(), &[0, 1, 2, 1, 2, 3]);
760    }
761
762    #[test]
763    fn buf_extents() {
764        let buf: Buf2<()> = Buf2::new((4, 5));
765        assert_eq!(buf.width(), 4);
766        assert_eq!(buf.height(), 5);
767        assert_eq!(buf.stride(), 4);
768    }
769
770    #[test]
771    fn buf_index_and_get() {
772        let buf = Buf2::new_with((4, 5), |x, y| x * 10 + y);
773
774        assert_eq!(buf[2usize], [2, 12, 22, 32]);
775
776        assert_eq!(buf[[0, 0]], 0);
777        assert_eq!(buf[[1, 0]], 10);
778        assert_eq!(buf[[3, 4]], 34);
779
780        assert_eq!(buf.get([2, 3]), Some(&23));
781        assert_eq!(buf.get([4, 4]), None);
782        assert_eq!(buf.get([3, 5]), None);
783    }
784
785    #[test]
786    fn buf_index_mut_and_get_mut() {
787        let mut buf = Buf2::new_with((4, 5), |x, y| x * 10 + y);
788
789        buf[2usize][1] = 123;
790        assert_eq!(buf[2usize], [2, 123, 22, 32]);
791
792        buf[[2, 3]] = 234;
793        assert_eq!(buf[[2, 3]], 234);
794
795        *buf.get_mut([3, 4]).unwrap() = 345;
796        assert_eq!(buf.get_mut([3, 4]), Some(&mut 345));
797        assert_eq!(buf.get_mut([4, 4]), None);
798        assert_eq!(buf.get_mut([3, 5]), None);
799    }
800
801    #[test]
802    #[should_panic = "position (x=4, y=0) out of bounds (0..4, 0..5)"]
803    fn buf_index_x_out_of_bounds_should_panic() {
804        let buf = Buf2::new((4, 5));
805        let _: i32 = buf[[4, 0]];
806    }
807
808    #[test]
809    #[should_panic = "position (x=0, y=4) out of bounds (0..5, 0..4)"]
810    fn buf_index_y_out_of_bounds_should_panic() {
811        let buf = Buf2::new((5, 4));
812        let _: i32 = buf[[0, 4]];
813    }
814
815    #[test]
816    #[should_panic = "position (x=0, y=5) out of bounds (0..4, 0..5)"]
817    fn buf_index_row_out_of_bounds_should_panic() {
818        let buf = Buf2::new((4, 5));
819        let _: &[i32] = &buf[5usize];
820    }
821
822    #[test]
823    fn buf_slice_range_full() {
824        let buf: Buf2<()> = Buf2::new((4, 5));
825
826        let slice = buf.slice(..);
827        assert_eq!(slice.width(), 4);
828        assert_eq!(slice.height(), 5);
829        assert_eq!(slice.stride(), 4);
830
831        let slice = buf.slice((.., ..));
832        assert_eq!(slice.width(), 4);
833        assert_eq!(slice.height(), 5);
834        assert_eq!(slice.stride(), 4);
835    }
836
837    #[test]
838    fn buf_slice_range_inclusive() {
839        let buf: Buf2<()> = Buf2::new((4, 5));
840        let slice = buf.slice((1..=3, 0..=3));
841        assert_eq!(slice.width(), 3);
842        assert_eq!(slice.height(), 4);
843        assert_eq!(slice.stride(), 4);
844    }
845
846    #[test]
847    fn buf_slice_range_to() {
848        let buf: Buf2<()> = Buf2::new((4, 5));
849
850        let slice = buf.slice((..2, ..4));
851        assert_eq!(slice.width(), 2);
852        assert_eq!(slice.height(), 4);
853        assert_eq!(slice.stride(), 4);
854    }
855
856    #[test]
857    fn buf_slice_range_from() {
858        let buf: Buf2<()> = Buf2::new((4, 5));
859
860        let slice = buf.slice((3.., 2..));
861        assert_eq!(slice.width(), 1);
862        assert_eq!(slice.height(), 3);
863        assert_eq!(slice.stride(), 4);
864    }
865
866    #[test]
867    fn buf_slice_empty_range() {
868        let buf: Buf2<()> = Buf2::new((4, 5));
869
870        let empty = buf.slice(pt2(1, 1)..pt2(1, 3));
871        assert_eq!(empty.width(), 0);
872        assert_eq!(empty.height(), 2);
873        assert_eq!(empty.stride(), 4);
874
875        let empty = buf.slice(pt2(1, 1)..pt2(3, 1));
876        assert_eq!(empty.width(), 2);
877        assert_eq!(empty.height(), 0);
878        assert_eq!(empty.stride(), 4);
879    }
880
881    #[test]
882    #[should_panic = "range right (5) > width (4)"]
883    fn buf_slice_x_out_of_bounds_should_panic() {
884        let buf: Buf2<()> = Buf2::new((4, 5));
885        buf.slice((0..5, 1..3));
886    }
887
888    #[test]
889    #[should_panic = "range bottom (6) > height (5)"]
890    fn buf_slice_y_out_of_bounds_should_panic() {
891        let buf: Buf2<()> = Buf2::new((4, 5));
892        buf.slice((1..3, 0..6));
893    }
894
895    #[test]
896    #[should_panic = "width (4) > stride (3)"]
897    fn slice_stride_less_than_width_should_panic() {
898        let _ = Slice2::new((4, 4), 3, &[0; 16]);
899    }
900
901    #[test]
902    #[should_panic = "required size (19) > data length (16)"]
903    fn slice_larger_than_data_should_panic() {
904        let _ = Slice2::new((4, 4), 5, &[0; 16]);
905    }
906
907    #[test]
908    fn slice_extents() {
909        let buf: Buf2<()> = Buf2::new((10, 10));
910
911        let slice = buf.slice((1..4, 2..8));
912        assert_eq!(slice.width(), 3);
913        assert_eq!(slice.height(), 6);
914        assert_eq!(slice.stride(), 10);
915        assert_eq!(slice.data().len(), 5 * 10 + 3);
916    }
917
918    #[test]
919    fn slice_contiguity() {
920        let buf: Buf2<()> = Buf2::new((10, 10));
921        // Buf2 is always contiguous
922        assert!(buf.is_contiguous());
923
924        // Empty slice is contiguous
925        assert!(buf.slice((2..2, 2..8)).is_contiguous());
926        assert!(buf.slice((2..8, 2..2)).is_contiguous());
927        // One-row slice is contiguous
928        assert!(buf.slice((2..8, 2..3)).is_contiguous());
929        // Slice spanning whole width of buf is contiguous
930        assert!(buf.slice((0..10, 2..8)).is_contiguous());
931        assert!(buf.slice((.., 2..8)).is_contiguous());
932
933        // Slice not spanning the width of buf is not contiguous
934        assert!(!buf.slice((2..=2, 1..9)).is_contiguous());
935        assert!(!buf.slice((2..4, 0..9)).is_contiguous());
936        assert!(!buf.slice((2..4, 1..10)).is_contiguous());
937    }
938
939    #[test]
940    #[rustfmt::skip]
941    fn slice_fill() {
942        let mut buf = Buf2::new((5, 4));
943        let mut slice = buf.slice_mut((2.., 1..3));
944
945        slice.fill(1);
946
947        assert_eq!(
948            buf.data(),
949            &[0, 0, 0, 0, 0,
950              0, 0, 1, 1, 1,
951              0, 0, 1, 1, 1,
952              0, 0, 0, 0, 0]
953        );
954    }
955
956    #[test]
957    #[rustfmt::skip]
958    fn slice_fill_with() {
959        let mut buf = Buf2::new((5, 4));
960        let mut slice = buf.slice_mut((2.., 1..3));
961
962        slice.fill_with(|x, y| x + y);
963
964        assert_eq!(
965            buf.data(),
966            &[0, 0, 0, 0, 0,
967              0, 0, 0, 1, 2,
968              0, 0, 1, 2, 3,
969              0, 0, 0, 0, 0]
970        );
971    }
972
973    #[test]
974    #[rustfmt::skip]
975    fn slice_copy_from() {
976        let mut dest = Buf2::new((5, 4));
977        let src = Buf2::new_with((3, 3), |x, y| x + y);
978
979        dest.slice_mut((1..4, 1..)).copy_from(src);
980
981        assert_eq!(
982            dest.data(),
983            &[0, 0, 0, 0, 0,
984              0, 0, 1, 2, 0,
985              0, 1, 2, 3, 0,
986              0, 2, 3, 4, 0]
987        );
988    }
989
990    #[test]
991    fn slice_index() {
992        let buf = Buf2::new_with((5, 4), |x, y| x * 10 + y);
993        let slice = buf.slice((2.., 1..3));
994
995        assert_eq!(slice[[0, 0]], 21);
996        assert_eq!(slice[[1, 0]], 31);
997        assert_eq!(slice[[2, 1]], 42);
998
999        assert_eq!(slice.get([2, 1]), Some(&42));
1000        assert_eq!(slice.get([2, 2]), None);
1001    }
1002
1003    #[test]
1004    fn slice_index_mut() {
1005        let mut buf = Buf2::new_with((5, 5), |x, y| x * 10 + y);
1006        let mut slice = buf.slice_mut((2.., 1..3));
1007
1008        slice[[2, 1]] = 123;
1009        assert_eq!(slice[[2, 1]], 123);
1010
1011        assert_eq!(slice.get_mut([2, 1]), Some(&mut 123));
1012        assert_eq!(slice.get([2, 2]), None);
1013
1014        buf[[2, 2]] = 321;
1015        let slice = buf.slice((1.., 2..));
1016        assert_eq!(slice[[1, 0]], 321);
1017    }
1018
1019    #[test]
1020    fn slice_rows() {
1021        let buf = Buf2::new_with((5, 4), |x, y| x * 10 + y);
1022        let slice = buf.slice((2..4, 1..));
1023
1024        let mut rows = slice.rows();
1025        assert_eq!(rows.next(), Some(&[21, 31][..]));
1026        assert_eq!(rows.next(), Some(&[22, 32][..]));
1027        assert_eq!(rows.next(), Some(&[23, 33][..]));
1028        assert_eq!(rows.next(), None);
1029    }
1030
1031    #[test]
1032    fn slice_rows_mut() {
1033        let mut buf = Buf2::new_with((5, 4), |x, y| x * 10 + y);
1034        let mut slice = buf.slice_mut((2..4, 1..));
1035
1036        let mut rows = slice.rows_mut();
1037        assert_eq!(rows.next(), Some(&mut [21, 31][..]));
1038        assert_eq!(rows.next(), Some(&mut [22, 32][..]));
1039        assert_eq!(rows.next(), Some(&mut [23, 33][..]));
1040        assert_eq!(rows.next(), None);
1041    }
1042
1043    #[test]
1044    fn buf_ref_as_slice() {
1045        fn foo<T: AsSlice2<u32>>(buf: T) -> u32 {
1046            buf.as_slice2().width()
1047        }
1048        let buf = Buf2::new((2, 2));
1049        let w = foo(&buf);
1050        assert_eq!(w, buf.width());
1051    }
1052
1053    #[test]
1054    fn buf_ref_as_slice_mut() {
1055        fn foo<T: AsMutSlice2<u32>>(mut buf: T) {
1056            buf.as_mut_slice2()[[1, 1]] = 42;
1057        }
1058        let mut buf = Buf2::new((2, 2));
1059        foo(&mut buf);
1060        assert_eq!(buf[[1, 1]], 42);
1061    }
1062}