Skip to content

Instantly share code, notes, and snippets.

@qryxip
Created November 21, 2019 09:53
Show Gist options
  • Select an option

  • Save qryxip/f3683544f8cd802564aa1c62bd91b44f to your computer and use it in GitHub Desktop.

Select an option

Save qryxip/f3683544f8cd802564aa1c62bd91b44f to your computer and use it in GitHub Desktop.
Provides release mode only unchecked indexing like `unchecked-index` crate
/// 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