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