1
2#![cfg_attr(not(test), no_std)]
47
48#[cfg(not(test))]
49extern crate core as std;
50
51#[derive(Copy)]
56pub struct UncheckedIndex<S>(S);
57
58impl<S: Copy> Clone for UncheckedIndex<S> {
59 fn clone(&self) -> Self { *self }
60}
61
62pub unsafe fn unchecked_index<T>(v: T) -> UncheckedIndex<T>
72{
73 UncheckedIndex(v)
74}
75
76pub unsafe fn get_unchecked<T: ?Sized, I>(v: &T, index: I) -> &T::Output
86 where T: GetUnchecked<I>
87{
88 #[cfg(debug_assertions)]
89 v.assert_indexable_with(&index);
90 v.get_unchecked(index)
91}
92
93pub unsafe fn get_unchecked_mut<T: ?Sized, I>(v: &mut T, index: I) -> &mut T::Output
103 where T: GetUncheckedMut<I>
104{
105 #[cfg(debug_assertions)]
106 v.assert_indexable_with(&index);
107 v.get_unchecked_mut(index)
108}
109
110use std::ops::{Deref, DerefMut, Index, IndexMut};
111
112impl<T> Deref for UncheckedIndex<T> {
113 type Target = T;
114 fn deref(&self) -> &T {
115 &self.0
116 }
117}
118
119impl<T> DerefMut for UncheckedIndex<T> {
120 fn deref_mut(&mut self) -> &mut T {
121 &mut self.0
122 }
123}
124
125impl<T, I> Index<I> for UncheckedIndex<T>
126 where T: GetUnchecked<I>
127{
128 type Output = T::Output;
129
130 #[inline]
140 fn index(&self, index: I) -> &Self::Output {
141 unsafe {
142 get_unchecked(&self.0, index)
143 }
144 }
145}
146
147impl<T, I> IndexMut<I> for UncheckedIndex<T>
148 where T: GetUncheckedMut<I>
149{
150 #[inline]
160 fn index_mut(&mut self, index: I) -> &mut Self::Output {
161 unsafe {
162 get_unchecked_mut(&mut self.0, index)
163 }
164 }
165}
166
167pub trait CheckIndex<I> {
168 fn assert_indexable_with(&self, index: &I);
173}
174
175impl<'a, T: ?Sized, I> CheckIndex<I> for &'a T where T: CheckIndex<I> {
176 fn assert_indexable_with(&self, index: &I) {
177 (**self).assert_indexable_with(index)
178 }
179}
180
181impl<'a, T: ?Sized, I> CheckIndex<I> for &'a mut T where T: CheckIndex<I> {
182 fn assert_indexable_with(&self, index: &I) {
183 (**self).assert_indexable_with(index)
184 }
185}
186
187pub trait GetUnchecked<I>: CheckIndex<I> {
188 type Output: ?Sized;
189 unsafe fn get_unchecked(&self, index: I) -> &Self::Output;
190}
191
192pub trait GetUncheckedMut<I>: GetUnchecked<I> {
193 unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut Self::Output;
194}
195
196impl<'a, T: ?Sized, I> GetUnchecked<I> for &'a T
197 where T: GetUnchecked<I>
198{
199 type Output = T::Output;
200 unsafe fn get_unchecked(&self, index: I) -> &Self::Output {
201 (**self).get_unchecked(index)
202 }
203}
204
205impl<'a, T: ?Sized, I> GetUnchecked<I> for &'a mut T
206 where T: GetUnchecked<I>
207{
208 type Output = T::Output;
209 unsafe fn get_unchecked(&self, index: I) -> &Self::Output {
210 (**self).get_unchecked(index)
211 }
212}
213
214impl<'a, T: ?Sized, I> GetUncheckedMut<I> for &'a mut T
215 where T: GetUncheckedMut<I>
216{
217 unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut Self::Output {
218 (**self).get_unchecked_mut(index)
219 }
220}
221
222mod slice_impls;
223
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228
229 #[test]
230 fn it_works() {
231 let mut data = [0; 8];
232 unsafe {
233 let mut data = unchecked_index(&mut data);
234 for i in 0..data.len() {
235 data[i] = i;
236 }
237 }
238 assert_eq!(data, [0, 1, 2, 3, 4, 5, 6, 7]);
239 }
240
241 #[cfg(debug_assertions)]
242 #[test]
243 #[should_panic]
244 fn debug_oob_check_write() {
245 let mut data = [0; 8];
246 unsafe {
247 let mut data = unchecked_index(&mut data[..7]);
248 data[7] = 1;
249 }
250 }
251
252 #[cfg(debug_assertions)]
253 #[test]
254 #[should_panic]
255 fn debug_oob_check_read() {
256 let mut data = [0; 8];
257 unsafe {
258 let data = unchecked_index(&mut data[..7]);
259 println!("{}", data[17]);
260 }
261 }
262
263 #[cfg(not(debug_assertions))]
264 #[test]
265 fn non_debug_oob() {
266 let mut data = [0; 8];
268 unsafe {
269 let mut data = unchecked_index(&mut data[..7]);
270 data[7] = 1;
271 }
272 assert_eq!(data, [0, 0, 0, 0, 0, 0, 0, 1]);
273 }
274
275 #[cfg(debug_assertions)]
276 #[test]
277 #[should_panic]
278 fn debug_oob_check_read_slice_1() {
279 let mut data = [0; 8];
280 unsafe {
281 let data = unchecked_index(&mut data[..7]);
282 println!("{:?}", &data[5..10]);
283 }
284 }
285
286 #[cfg(debug_assertions)]
287 #[test]
288 #[should_panic]
289 fn debug_oob_check_read_slice_2() {
290 let mut data = [0; 8];
291 unsafe {
292 let data = unchecked_index(&mut data[..7]);
293 println!("{:?}", &data[7..6]);
294 }
295 }
296
297 #[cfg(debug_assertions)]
298 #[test]
299 #[should_panic]
300 fn debug_oob_check_read_slice_3() {
301 let mut data = [0; 8];
302 unsafe {
303 let data = unchecked_index(&mut data[..7]);
304 println!("{:?}", &data[8..]);
305 }
306 }
307
308 #[cfg(debug_assertions)]
309 #[test]
310 #[should_panic]
311 fn debug_oob_check_read_slice_4() {
312 let mut data = [0; 8];
313 unsafe {
314 let data = unchecked_index(&mut data[..7]);
315 println!("{:?}", &data[..9]);
316 }
317 }
318
319 #[cfg(not(debug_assertions))]
320 #[test]
321 fn non_debug_oob_slice() {
322 let mut data = [0; 8];
324 unsafe {
325 let mut data = unchecked_index(&mut data[..7]);
326 data[7..8][0] = 1;
327 }
328 assert_eq!(data, [0, 0, 0, 0, 0, 0, 0, 1]);
329 }
330}