stack_algebra/
index.rs

1use crate::Matrix;
2
3mod private {
4
5    pub trait Sealed {}
6    impl Sealed for usize {}
7    impl Sealed for (usize, usize) {}
8}
9
10/// A helper trait used for indexing operations.
11///
12/// This is the [`Matrix`] version of [`SliceIndex`][`core::slice::SliceIndex`].
13/// You should not use or implement this trait directly but instead use the
14/// corresponding methods on [`Matrix`].
15///
16/// # Safety
17///
18/// Implementations of this trait have to promise that if the argument
19/// to `get_(mut_)unchecked` is a safe reference, then so is the result.
20pub unsafe trait MatrixIndex<T: ?Sized>: private::Sealed {
21    /// The output type returned by methods.
22    type Output: ?Sized;
23
24    /// Returns a shared reference to the output at this location, if in
25    /// bounds.
26    fn get(self, matrix: &T) -> Option<&Self::Output>;
27
28    /// Returns a mutable reference to the output at this location, if in
29    /// bounds.
30    fn get_mut(self, matrix: &mut T) -> Option<&mut Self::Output>;
31
32    /// Returns a shared reference to the output at this location, without
33    /// performing any bounds checking.
34    ///
35    /// # Safety
36    ///
37    /// Calling this method with an out-of-bounds index or a dangling `matrix`
38    /// pointer is *[undefined behavior]* even if the resulting reference is not
39    /// used.
40    ///
41    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
42    unsafe fn get_unchecked(self, matrix: *const T) -> *const Self::Output;
43
44    /// Returns a mutable reference to the output at this location, without
45    /// performing any bounds checking.
46    ///
47    /// # Safety
48    ///
49    /// Calling this method with an out-of-bounds index or a dangling `matrix`
50    /// pointer is *[undefined behavior]* even if the resulting reference is not
51    /// used.
52    ///
53    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
54    unsafe fn get_unchecked_mut(self, stride: *mut T) -> *mut Self::Output;
55
56    /// Returns a shared reference to the output at this location, panicking
57    /// if out of bounds.
58    #[track_caller]
59    fn index(self, stride: &T) -> &Self::Output;
60
61    /// Returns a mutable reference to the output at this location, panicking
62    /// if out of bounds.
63    #[track_caller]
64    fn index_mut(self, stride: &mut T) -> &mut Self::Output;
65}
66
67unsafe impl<T, const M: usize, const N: usize> MatrixIndex<Matrix<M, N, T>> for usize {
68    type Output = T;
69
70    #[inline]
71    fn get(self, matrix: &Matrix<M, N, T>) -> Option<&Self::Output> {
72        matrix.as_slice().get(self)
73    }
74
75    #[inline]
76    fn get_mut(self, matrix: &mut Matrix<M, N, T>) -> Option<&mut Self::Output> {
77        matrix.as_mut_slice().get_mut(self)
78    }
79
80    #[inline]
81    unsafe fn get_unchecked(self, matrix: *const Matrix<M, N, T>) -> *const Self::Output {
82        // SAFETY: it is the caller's responsibility not to call this with an
83        // out-of-bounds index or a dangling `matrix` pointer.
84        let matrix = unsafe { (*matrix).as_slice() };
85        unsafe { matrix.get_unchecked(self) }
86    }
87
88    #[inline]
89    unsafe fn get_unchecked_mut(self, matrix: *mut Matrix<M, N, T>) -> *mut Self::Output {
90        // SAFETY: it is the caller's responsibility not to call this with an
91        // out-of-bounds index or a dangling `matrix` pointer.
92        let matrix = unsafe { (*matrix).as_mut_slice() };
93        unsafe { matrix.get_unchecked_mut(self) }
94    }
95
96    #[track_caller]
97    #[inline]
98    fn index(self, matrix: &Matrix<M, N, T>) -> &Self::Output {
99        &matrix.as_slice()[self]
100    }
101
102    #[track_caller]
103    #[inline]
104    fn index_mut(self, matrix: &mut Matrix<M, N, T>) -> &mut Self::Output {
105        &mut matrix.as_mut_slice()[self]
106    }
107}
108
109unsafe impl<T, const M: usize, const N: usize> MatrixIndex<Matrix<M, N, T>> for (usize, usize) {
110    type Output = T;
111
112    #[inline]
113    fn get(self, matrix: &Matrix<M, N, T>) -> Option<&Self::Output> {
114        matrix.as_slice().get(self.1 * M + self.0)
115    }
116
117    #[inline]
118    fn get_mut(self, matrix: &mut Matrix<M, N, T>) -> Option<&mut Self::Output> {
119        matrix.as_mut_slice().get_mut(self.1 * M + self.0)
120    }
121
122    #[inline]
123    unsafe fn get_unchecked(self, matrix: *const Matrix<M, N, T>) -> *const Self::Output {
124        // SAFETY: it is the caller's responsibility not to call this with an
125        // out-of-bounds index or a dangling `matrix` pointer.
126        let matrix = unsafe { (*matrix).as_slice() };
127        unsafe { matrix.get_unchecked(self.1 * M + self.0) }
128    }
129
130    #[inline]
131    unsafe fn get_unchecked_mut(self, matrix: *mut Matrix<M, N, T>) -> *mut Self::Output {
132        // SAFETY: it is the caller's responsibility not to call this with an
133        // out-of-bounds index or a dangling `matrix` pointer.
134        let matrix = unsafe { (*matrix).as_mut_slice() };
135        unsafe { matrix.get_unchecked_mut(self.1 * M + self.0) }
136    }
137
138    #[track_caller]
139    #[inline]
140    fn index(self, matrix: &Matrix<M, N, T>) -> &Self::Output {
141        &matrix.as_slice()[self.1 * M + self.0]
142    }
143
144    #[track_caller]
145    #[inline]
146    fn index_mut(self, matrix: &mut Matrix<M, N, T>) -> &mut Self::Output {
147        &mut matrix.as_mut_slice()[self.1 * M + self.0]
148    }
149}