dont_panic_slice/
lib.rs

1//! Non-panicking drop-in replacement for slices. Instead of panic it causes link time error if
2//! bounds are not checked. (Not fully drop-in replacement yet. Some features are missing.)
3//!
4//! # Example
5//!
6//! ```no_compile
7//! #[macro_use]
8//! extern crate dont_panic_slice;
9//!
10//! use dont_panic_slice::DPSlice;
11//!
12//! fn main() {
13//!     let arr = [0, 1, 2, 3];
14//!     let dps = <&DPSlice<_>>::from(&arr as &[_]);
15//!     assert_eq!(dps[0], 0);
16//!     assert_eq!(dps[3], 3);
17//!     // This would not compile (instead of run time panicking)
18//!     assert_eq!(dps[42], 42);
19//! }
20//! ```
21//!
22//! You must compile it with `--release`. If you don't want to slow down debug builds, you can use
23//! `--features=panic` to switch to normal panicking behaviour. 
24
25#![no_std]
26
27#[macro_use]
28extern crate dont_panic;
29
30pub struct DPSlice<T>([T]);
31
32impl<T> DPSlice<T> {
33    pub fn as_rust_slice(this: &Self) -> &[T] {
34        unsafe { ::core::mem::transmute(this) }
35    }
36
37    pub fn as_rust_slice_mut(this: &mut Self) -> &mut [T] {
38        unsafe { ::core::mem::transmute(this) }
39    }
40
41    pub fn len(&self) -> usize {
42        Self::as_rust_slice(self).len()
43    }
44
45    pub fn is_empty(&self) -> bool {
46        Self::as_rust_slice(self).is_empty()
47    }
48
49    pub fn first(&self) -> Option<&T> {
50        Self::as_rust_slice(self).first()
51    }
52
53    pub fn first_mut(&mut self) -> Option<&mut T> {
54        Self::as_rust_slice_mut(self).first_mut()
55    }
56
57    pub fn split_first(&self) -> Option<(&T, &[T])> {
58        Self::as_rust_slice(self).split_first()
59    }
60
61    pub fn split_first_mut(&self) -> Option<(&T, &[T])> {
62        Self::as_rust_slice(self).split_first()
63    }
64
65    pub fn split_last(&self) -> Option<(&T, &[T])> {
66        Self::as_rust_slice(self).split_last()
67    }
68
69    pub fn split_last_mut(&mut self) -> Option<(&T, &[T])> {
70        Self::as_rust_slice_mut(self).split_last()
71    }
72
73    pub fn swap(&mut self, a: usize, b: usize) {
74        if a > self.len() {
75            dont_panic!("index out of bounds: the len is {} but the index is {}", self.len(), a);
76        }
77
78        if b > self.len() {
79            dont_panic!("index out of bounds: the len is {} but the index is {}", self.len(), b);
80        }
81
82        Self::as_rust_slice_mut(self).swap(a, b);
83    }
84
85    pub fn windows(&self, size: usize) -> ::core::slice::Windows<T> {
86        dp_assert!(size != 0);
87
88        Self::as_rust_slice(self).windows(size)
89    }
90
91    pub fn chunks(&self, size: usize) -> ::core::slice::Chunks<T> {
92        dp_assert!(size != 0);
93
94        Self::as_rust_slice(self).chunks(size)
95    }
96
97    pub fn chunks_mut(&mut self, size: usize) -> ::core::slice::ChunksMut<T> {
98        dp_assert!(size != 0);
99
100        Self::as_rust_slice_mut(self).chunks_mut(size)
101    }
102
103    pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
104        if mid > self.len() {
105            dont_panic!("index {} out of range for slice of length {}", mid, self.len());
106        }
107
108        Self::as_rust_slice(self).split_at(mid)
109    }
110
111    pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
112        if mid > self.len() {
113            dont_panic!("index {} out of range for slice of length {}", mid, self.len());
114        }
115
116        Self::as_rust_slice_mut(self).split_at_mut(mid)
117    }
118}
119
120impl<'a, T> From<&'a [T]> for &'a DPSlice<T> {
121    fn from(slice: &[T]) -> Self {
122        unsafe { ::core::mem::transmute(slice) }
123    }
124}
125
126/* Coherence :'(
127impl<'a, T> From<&'a DPSlice<T>> for &'a [T] {
128    fn from(slice: &DPSlice<T>) -> Self {
129        unsafe { ::core::mem::transmute(slice) }
130    }
131}
132*/
133
134impl<'a, T> From<&'a mut [T]> for &'a mut DPSlice<T> {
135    fn from(slice: &mut [T]) -> Self {
136        unsafe { ::core::mem::transmute(slice) }
137    }
138}
139
140/* Coherence :'(
141impl<'a, T> From<&'a mut DPSlice<T>> for &'a mut [T] {
142    fn from(slice: &mut DPSlice<T>) -> Self {
143        unsafe { ::core::mem::transmute(slice) }
144    }
145}
146*/
147
148impl<T> ::core::ops::Index<usize> for DPSlice<T> {
149    type Output = T;
150
151    #[inline(always)]
152    fn index(&self, index: usize) -> &Self::Output {
153        Self::as_rust_slice(self).get(index).unwrap_or_else(|| dont_panic!("index out of bounds: the len is {} but the index is {}", self.len(), index))
154    }
155}
156
157impl<T> ::core::ops::IndexMut<usize> for DPSlice<T> {
158    #[inline(always)]
159    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
160        Self::as_rust_slice_mut(self).get_mut(index).unwrap_or_else(|| dont_panic!("index out of bounds: the len is {} but the index is {}", self.len(), index))
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use ::DPSlice;
167
168    #[test]
169    fn it_works() {
170        let arr = [0, 1, 2, 3];
171        let dps = <&DPSlice<_>>::from(&arr as &[_]);
172        assert_eq!(dps[0], 0);
173        assert_eq!(dps[3], 3);
174    }
175
176    #[cfg(feature = "panic")]
177    #[test]
178    #[should_panic]
179    fn panic() {
180        let arr = [0, 1, 2, 3];
181        let dps = <&DPSlice<_>>::from(&arr as &[_]);
182        assert_eq!(dps[42], 0);
183        assert_eq!(dps[3], 3);
184    }
185
186    #[cfg(feature = "panic")]
187    #[test]
188    fn no_panic() {
189        let arr = [0, 1, 2, 3];
190        let dps = <&DPSlice<_>>::from(&arr as &[_]);
191        assert_eq!(dps[0], 0);
192        assert_eq!(dps[3], 3);
193    }
194}