Skip to main content

indexmap/map/
disjoint.rs

1#![allow(unsafe_code)]
2
3use crate::GetDisjointMutError;
4
5/// Like `slice::get_disjoint_mut`, although we're not dealing with ranges (yet).
6// TODO(MSRV 1.86): remove this in favor of the standard library's method.
7pub(super) fn get_disjoint_mut<T, const N: usize>(
8    entries: &mut [T],
9    indices: [usize; N],
10) -> Result<[&mut T; N], GetDisjointMutError> {
11    // SAFETY: Can't allow duplicate indices as we would return mutable refs to the same data.
12    let len = entries.len();
13    for i in 0..N {
14        let idx = indices[i];
15        if idx >= len {
16            return Err(GetDisjointMutError::IndexOutOfBounds);
17        } else if indices[..i].contains(&idx) {
18            return Err(GetDisjointMutError::OverlappingIndices);
19        }
20    }
21
22    let entries_ptr = entries.as_mut_ptr();
23    Ok(indices.map(move |idx| {
24        // SAFETY: The base pointer is valid as it comes from a slice and the reference is always
25        // in-bounds & unique as we've already checked the indices above.
26        unsafe { &mut *(entries_ptr.add(idx)) }
27    }))
28}
29
30/// Like `slice::get_disjoint_mut` but with optional indices,
31/// allowing for absent keys from the user's original request.
32#[track_caller]
33pub(super) fn get_disjoint_opt_mut<T, const N: usize>(
34    entries: &mut [T],
35    indices: [Option<usize>; N],
36) -> [Option<&mut T>; N] {
37    // SAFETY: Can't allow duplicate indices as we would return mutable refs to the same data.
38    let len = entries.len();
39    for i in 0..N {
40        if let Some(idx) = indices[i] {
41            if idx >= len {
42                unreachable!("`get_index_of` returned an out-of-bounds index");
43            } else if indices[..i].contains(&Some(idx)) {
44                panic!("duplicate keys found");
45            }
46        }
47    }
48
49    let entries_ptr = entries.as_mut_ptr();
50    indices.map(move |idx_opt| {
51        match idx_opt {
52            Some(idx) => {
53                // SAFETY: The base pointer is valid as it comes from a slice and the reference is always
54                // in-bounds & unique as we've already checked the indices above.
55                Some(unsafe { &mut *entries_ptr.add(idx) })
56            }
57            None => None,
58        }
59    })
60}