slice2d/
lib.rs

1//! Ergonomic array slice for 2d array manipulation.
2//!
3//! ## Example
4//!
5//! ```
6//! # use slice2d::Slice2DExt;
7//! let array = [1, 2, 3, 4, 5, 6];
8//! let slice = array.get_slice2d(3, 2).unwrap();
9//! assert_eq!(slice[2][0], 5);
10//! assert_eq!(&slice[1], &[3, 4]);
11//! ```
12#![no_std]
13use core::ops::{Index, IndexMut};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16/// A 2 dimensional slice.
17pub struct Slice2D<'t, T> {
18    stride: usize,
19    len: usize,
20    slice: &'t [T],
21}
22
23#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
24/// A mutable 2 dimensional slice.
25pub struct Slice2DMut<'t, T> {
26    stride: usize,
27    len: usize,
28    slice: &'t mut [T],
29}
30
31impl<T> Slice2D<'_, T> {
32    /// Returns a reference to a subslice.
33    pub fn get(&self, index: usize) -> Option<&[T]> {
34        let origin = index * self.stride;
35        self.slice.get(origin..origin + self.len)
36    }
37}
38
39impl<'t, T> Slice2DMut<'t, T> {
40    /// Obtain a [`Slice2D`] from a [`Slice2DMut`].
41    pub fn downgrade(&self) -> Slice2D<'_, T> {
42        Slice2D {
43            stride: self.stride,
44            len: self.len,
45            slice: self.slice,
46        }
47    }
48
49    /// Cast [`Slice2DMut`] to a new lifetime.
50    pub fn reborrow(&mut self) -> Slice2DMut<'_, T> {
51        Slice2DMut {
52            stride: self.stride,
53            len: self.len,
54            slice: self.slice,
55        }
56    }
57
58    /// Returns a reference to a subslice.
59    pub fn get(&self, index: usize) -> Option<&[T]> {
60        let origin = index * self.stride;
61        self.slice.get(origin..origin + self.len)
62    }
63
64    /// Returns a mutable reference to a subslice.
65    pub fn get_mut(&mut self, index: usize) -> Option<&mut [T]> {
66        let origin = index * self.stride;
67        self.slice.get_mut(origin..origin + self.len)
68    }
69}
70
71impl<T> Index<usize> for Slice2D<'_, T> {
72    type Output = [T];
73
74    fn index(&self, index: usize) -> &Self::Output {
75        let origin = index * self.stride;
76        &self.slice[origin..origin + self.len]
77    }
78}
79
80impl<T> Index<usize> for Slice2DMut<'_, T> {
81    type Output = [T];
82
83    fn index(&self, index: usize) -> &Self::Output {
84        let origin = index * self.stride;
85        &self.slice[origin..origin + self.len]
86    }
87}
88
89impl<T> IndexMut<usize> for Slice2DMut<'_, T> {
90    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
91        let origin = index * self.stride;
92        &mut self.slice[origin..origin + self.len]
93    }
94}
95
96impl<'t, T> Iterator for Slice2D<'t, T> {
97    type Item = &'t [T];
98
99    fn next(&mut self) -> Option<Self::Item> {
100        let result = self.slice.get(0..self.len);
101        self.slice = self.slice.get(self.stride..).unwrap_or(&[]);
102        result
103    }
104}
105
106/// Extension for creating 2 dimensional slices.
107pub trait Slice2DExt {
108    type Item;
109
110    /// Obtain a [`Slice2D`] with row length `len` and skips `stride` per row.
111    ///
112    /// Incomplete rows will be discarded.
113    fn slice2d(&self, len: usize, stride: usize) -> Slice2D<'_, Self::Item>;
114    /// Obtain a [`Slice2DMut`] with row length `len` and skips `stride` per row.
115    ///
116    /// Incomplete rows will be discarded.
117    fn slice2d_mut(&mut self, len: usize, stride: usize) -> Slice2DMut<'_, Self::Item>;
118
119    /// Obtain a [`Slice2D`] by validating dimension.
120    ///
121    /// This is equivalent to calling `slice2d(y, y)`.
122    fn get_slice2d(&self, x: usize, y: usize) -> Option<Slice2D<'_, Self::Item>>;
123    /// Obtain a [`Slice2DMut`] by validating dimension.
124    ///
125    /// This is equivalent to calling `slice2d_mut(y, y)`.
126    fn get_slice2d_mut(&mut self, x: usize, y: usize) -> Option<Slice2DMut<'_, Self::Item>>;
127}
128
129impl<T> Slice2DExt for [T] {
130    type Item = T;
131    fn slice2d(&self, len: usize, stride: usize) -> Slice2D<'_, Self::Item> {
132        Slice2D {
133            len,
134            stride,
135            slice: self,
136        }
137    }
138
139    fn slice2d_mut(&mut self, len: usize, stride: usize) -> Slice2DMut<'_, Self::Item> {
140        Slice2DMut {
141            len,
142            stride,
143            slice: self,
144        }
145    }
146
147    fn get_slice2d(&self, x: usize, y: usize) -> Option<Slice2D<'_, Self::Item>> {
148        if self.len() != x * y {
149            return None;
150        }
151        Some(Slice2D {
152            len: y,
153            stride: y,
154            slice: self,
155        })
156    }
157
158    fn get_slice2d_mut(&mut self, x: usize, y: usize) -> Option<Slice2DMut<'_, Self::Item>> {
159        if self.len() != x * y {
160            return None;
161        }
162        Some(Slice2DMut {
163            len: y,
164            stride: y,
165            slice: self,
166        })
167    }
168}
169
170#[cfg(test)]
171mod test {
172    pub use crate::Slice2DExt;
173
174    #[test]
175    fn test() {
176        let v = [1, 2, 3, 4, 5, 6, 7, 8, 9];
177        let mut slice = v.get_slice2d(3, 3).unwrap();
178        assert_eq!(slice[0][0], 1);
179        assert_eq!(slice[0][1], 2);
180        assert_eq!(slice[0][2], 3);
181        assert_eq!(slice[1][0], 4);
182        assert_eq!(slice[1][1], 5);
183        assert_eq!(slice[1][2], 6);
184        assert_eq!(slice[2][0], 7);
185        assert_eq!(slice[2][1], 8);
186        assert_eq!(slice[2][2], 9);
187        assert_eq!(&slice[1], &[4, 5, 6]);
188
189        assert_eq!(slice.next().unwrap(), &[1, 2, 3]);
190        assert_eq!(slice.next().unwrap(), &[4, 5, 6]);
191        assert_eq!(slice.next().unwrap(), &[7, 8, 9]);
192        assert_eq!(slice.next(), None);
193        assert_eq!(slice.next(), None);
194
195        let mut v = [1, 2, 3, 4, 5, 6];
196        let slice = v.get_slice2d_mut(3, 2).unwrap();
197        assert_eq!(slice[0][0], 1);
198        assert_eq!(slice[0][1], 2);
199        assert_eq!(slice[1][0], 3);
200        assert_eq!(slice[1][1], 4);
201        assert_eq!(slice[2][0], 5);
202        assert_eq!(slice[2][1], 6);
203        assert_eq!(&slice[1], &[3, 4]);
204    }
205}