semisafe 1.0.0

Semi-safe utilities for performance-critical Rust
Documentation
use std::slice::SliceIndex;

/// Returns element or subslice at `index` without bounds checks in release
/// builds.
///
/// Use this only when surrounding code guarantees that `index` selects a valid
/// in-bounds region of `arr`. In debug builds this delegates to [`slice::get`]
/// and panics on invalid indexes or ranges. In release builds, violating that
/// precondition causes undefined behavior.
///
/// # Panics
///
/// Panics in debug builds if `index` is out of bounds for `arr`.
///
/// # Examples
///
/// ```
/// let values = [10, 20, 30];
/// let value = semisafe::slice::get(&values, 1);
/// assert_eq!(*value, 20);
/// ```
#[inline(always)]
pub fn get<T, I: SliceIndex<[T]>>(arr: &[T], index: I) -> &<I as SliceIndex<[T]>>::Output {
    #[cfg(debug_assertions)]
    {
        arr.get(index).expect("array index out of bounds")
    }

    #[cfg(not(debug_assertions))]
    {
        unsafe { arr.get_unchecked(index) }
    }
}

/// Returns mutable element or subslice at `index` without bounds checks in
/// release builds.
///
/// Use this only when surrounding code guarantees that `index` selects a valid
/// in-bounds region of `arr`. In debug builds this delegates to
/// [`slice::get_mut`] and panics on invalid indexes or ranges. In release
/// builds, violating that precondition causes undefined behavior.
///
/// # Panics
///
/// Panics in debug builds if `index` is out of bounds for `arr`.
///
/// # Examples
///
/// ```
/// let mut values = [10, 20, 30];
/// *semisafe::slice::get_mut(&mut values, 1) = 99;
/// assert_eq!(values, [10, 99, 30]);
/// ```
#[inline(always)]
pub fn get_mut<T, I: SliceIndex<[T]>>(
    arr: &mut [T],
    index: I,
) -> &mut <I as SliceIndex<[T]>>::Output {
    #[cfg(debug_assertions)]
    {
        arr.get_mut(index).expect("array index out of bounds")
    }

    #[cfg(not(debug_assertions))]
    {
        unsafe { arr.get_unchecked_mut(index) }
    }
}

/// Splits `arr` at `index` without bounds checks in release builds.
///
/// Use this only when surrounding code guarantees that `index <= arr.len()`.
/// In debug builds this delegates to [`slice::split_at`] and panics when index
/// is out of bounds. In release builds, violating that precondition causes
/// undefined behavior.
///
/// # Panics
///
/// Panics in debug builds if `index > arr.len()`.
///
/// # Examples
///
/// ```
/// let values = [1, 2, 3, 4];
/// let (left, right) = semisafe::slice::split_at(&values, 2);
/// assert_eq!(left, &[1, 2]);
/// assert_eq!(right, &[3, 4]);
/// ```
#[inline(always)]
pub const fn split_at<T>(arr: &[T], index: usize) -> (&[T], &[T]) {
    #[cfg(debug_assertions)]
    {
        arr.split_at(index)
    }

    #[cfg(not(debug_assertions))]
    {
        unsafe { arr.split_at_unchecked(index) }
    }
}

/// Splits `arr` at `index` into two mutable slices without bounds checks in
/// release builds.
///
/// Use this only when surrounding code guarantees that `index <= arr.len()`.
/// In debug builds this delegates to [`slice::split_at_mut`] and panics when
/// index is out of bounds. In release builds, violating that precondition
/// causes undefined behavior.
///
/// # Panics
///
/// Panics in debug builds if `index > arr.len()`.
///
/// # Examples
///
/// ```
/// let mut values = [1, 2, 3, 4];
/// let (left, right) = semisafe::slice::split_at_mut(&mut values, 2);
/// left[0] = 10;
/// right[0] = 30;
/// assert_eq!(values, [10, 2, 30, 4]);
/// ```
#[inline(always)]
pub const fn split_at_mut<T>(arr: &mut [T], index: usize) -> (&mut [T], &mut [T]) {
    #[cfg(debug_assertions)]
    {
        arr.split_at_mut(index)
    }

    #[cfg(not(debug_assertions))]
    {
        unsafe { arr.split_at_mut_unchecked(index) }
    }
}

/// Copies all elements from `src` into `dest`, using a memcpy.
///
/// The length of `src` must be the same as `dest`.
///
/// # Panics
///
/// This function will panic in debug builds if the two slices have different lengths.
///
/// # Examples
///
/// ```
/// let src = [1, 2, 3, 4];
/// let mut dest = [0, 0, 0, 0];
/// semisafe::slice::copy(&src, &mut dest);
/// assert_eq!(src, dest);
/// ```
pub const fn copy<T: Copy>(src: &[T], dest: &mut [T]) {
    #[cfg(debug_assertions)]
    {
        dest.copy_from_slice(src);
    }

    #[cfg(not(debug_assertions))]
    {
        unsafe { core::ptr::copy_nonoverlapping(src.as_ptr(), dest.as_mut_ptr(), src.len()) }
    }
}