#![no_std]
#![deny(unsafe_op_in_unsafe_fn)]
#[cfg(feature = "std")]
extern crate std;
use core::{fmt, mem};
fn get_many_check_valid<const N: usize>(
indices: &[usize; N],
len: usize,
) -> bool {
let mut valid = true;
for (i, &idx) in indices.iter().enumerate() {
valid &= idx < len;
for &idx2 in &indices[..i] {
valid &= idx != idx2;
}
}
valid
}
pub unsafe trait GetManyMutExt {
type Element;
fn get_many_mut<const N: usize>(
&mut self,
indices: [usize; N],
) -> Result<[&mut Self::Element; N], GetManyMutError<N>>;
unsafe fn get_many_unchecked_mut<const N: usize>(
&mut self,
indices: [usize; N],
) -> [&mut Self::Element; N];
}
unsafe impl<T> GetManyMutExt for [T] {
type Element = T;
fn get_many_mut<const N: usize>(
&mut self,
indices: [usize; N],
) -> Result<[&mut Self::Element; N], GetManyMutError<N>> {
if get_many_check_valid(&indices, self.len()) {
unsafe {
Ok(<Self as GetManyMutExt>::get_many_unchecked_mut(
self, indices,
))
}
} else {
Err(GetManyMutError)
}
}
unsafe fn get_many_unchecked_mut<const N: usize>(
&mut self,
indices: [usize; N],
) -> [&mut T; N] {
let ptr: *mut T = self.as_mut_ptr();
let mut arr: mem::MaybeUninit<[&mut T; N]> = mem::MaybeUninit::uninit();
let arr_ptr: *mut *mut T = arr.as_mut_ptr().cast();
unsafe {
for i in 0..N {
let idx = indices[i];
*arr_ptr.add(i) = &mut *ptr.add(idx);
}
arr.assume_init()
}
}
}
unsafe impl<T, const M: usize> GetManyMutExt for [T; M] {
type Element = T;
fn get_many_mut<const N: usize>(
&mut self,
indices: [usize; N],
) -> Result<[&mut Self::Element; N], GetManyMutError<N>> {
<[T] as GetManyMutExt>::get_many_mut(self, indices)
}
unsafe fn get_many_unchecked_mut<const N: usize>(
&mut self,
indices: [usize; N],
) -> [&mut T; N] {
unsafe { <[T] as GetManyMutExt>::get_many_unchecked_mut(self, indices) }
}
}
#[non_exhaustive]
pub struct GetManyMutError<const N: usize>;
impl<const N: usize> fmt::Debug for GetManyMutError<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GetManyMutError").finish_non_exhaustive()
}
}
impl<const N: usize> fmt::Display for GetManyMutError<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(
"an index is out of bounds or appeared multiple times in the array",
f,
)
}
}
#[cfg(feature = "std")]
impl<const N: usize> std::error::Error for GetManyMutError<N> {}