Created
November 21, 2019 09:53
-
-
Save qryxip/f3683544f8cd802564aa1c62bd91b44f to your computer and use it in GitHub Desktop.
Provides release mode only unchecked indexing like `unchecked-index` crate
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /// The following code is licensed under [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/). | |
| fn main() { | |
| use unchecked_slice_index::SliceExt as _; | |
| let mut xs = vec![0]; | |
| unsafe { | |
| xs.with_unchecked_indices(|mut xs| { | |
| xs[0] += 1; | |
| assert_eq!(xs[0], 1); | |
| }); | |
| } | |
| } | |
| /// Provides **release mode only** unchecked indexing. | |
| /// | |
| /// ## MSRV (Minimum Supported Rust Version) | |
| /// | |
| /// 1.33 | |
| /// | |
| /// ## Differences with [`unchecked-index`](https://crates.io/crates/unchecked-index) | |
| /// | |
| /// - The wrapper is provided inside a closure. | |
| /// - All unchecked indexing cannnot to be occurred outside of `unsafe` blocks. | |
| /// - The wrapper cannot be [moved out](https://doc.rust-lang.org/stable/std/mem/fn.replace.html) since it is given as `Pin<_>`. | |
| /// - `unchecked_slice_index` does not (currently) provide [`CheckIndex`](https://docs.rs/unchecked-index/0.2/unchecked_index/trait.CheckIndex.html). | |
| /// - Licensed under [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/). | |
| mod unchecked_slice_index { | |
| use std::marker::Unpin; | |
| use std::ops::{Deref, DerefMut, Index, IndexMut}; | |
| use std::pin::Pin; | |
| use std::slice::SliceIndex; | |
| pub(crate) trait SliceExt { | |
| /// Provides **release mode only** unchecked indexing. | |
| /// | |
| /// # Safety | |
| /// | |
| /// All indexing of the `UnsafeSliceIndex` must be in bounds of the slice. | |
| unsafe fn with_unchecked_indices<F: FnOnce(Pin<UnsafeSliceIndex<&mut Self>>) -> O, O>( | |
| &mut self, | |
| f: F, | |
| ) -> O; | |
| } | |
| impl<T: Unpin> SliceExt for [T] { | |
| unsafe fn with_unchecked_indices<F: FnOnce(Pin<UnsafeSliceIndex<&mut Self>>) -> O, O>( | |
| &mut self, | |
| f: F, | |
| ) -> O { | |
| f(Pin::new(UnsafeSliceIndex(self))) | |
| } | |
| } | |
| /// A wrapper of slice which all indexing are unchecked in release mode. | |
| /// | |
| /// # Safety | |
| /// | |
| /// All indexing must be in the bounds. | |
| pub(crate) struct UnsafeSliceIndex<S>(S); | |
| impl<S> Deref for UnsafeSliceIndex<S> { | |
| type Target = S; | |
| fn deref(&self) -> &S { | |
| &self.0 | |
| } | |
| } | |
| impl<S> DerefMut for UnsafeSliceIndex<S> { | |
| fn deref_mut(&mut self) -> &mut S { | |
| &mut self.0 | |
| } | |
| } | |
| impl<T, I: SliceIndex<[T], Output = O>, O> Index<I> for UnsafeSliceIndex<&mut [T]> | |
| where | |
| [T]: Index<I, Output = O>, | |
| { | |
| type Output = O; | |
| #[inline] | |
| fn index(&self, index: I) -> &O { | |
| if cfg!(debug_assertions) { | |
| &self.0[index] | |
| } else { | |
| unsafe { self.0.get_unchecked(index) } | |
| } | |
| } | |
| } | |
| impl<T, I: SliceIndex<[T], Output = O>, O> IndexMut<I> for UnsafeSliceIndex<&mut [T]> | |
| where | |
| [T]: IndexMut<I, Output = O>, | |
| { | |
| #[inline] | |
| fn index_mut(&mut self, index: I) -> &mut O { | |
| if cfg!(debug_assertions) { | |
| &mut self.0[index] | |
| } else { | |
| unsafe { self.0.get_unchecked_mut(index) } | |
| } | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment