toolbox_rs/
unsafe_slice.rs

1use std::cell::UnsafeCell;
2
3/// This struct serves as a wrapper around unsafe accesses to a vector of
4/// elements.
5///
6/// This can be used if (and only if) we know (and the compiler doesn't) that
7/// threads do not access the same index during the concurrent processing.
8///
9/// DO NOT REUSE IN YOUR PROJECTS!
10///
11#[derive(Copy, Clone)]
12pub struct UnsafeSlice<'a, T> {
13    slice: &'a [UnsafeCell<T>],
14}
15unsafe impl<T: Send + Sync> Send for UnsafeSlice<'_, T> {}
16unsafe impl<T: Send + Sync> Sync for UnsafeSlice<'_, T> {}
17
18impl<'a, T> UnsafeSlice<'a, T> {
19    pub fn new(slice: &'a mut [T]) -> Self {
20        let ptr = slice as *mut [T] as *const [UnsafeCell<T>];
21        Self {
22            slice: unsafe { &*ptr },
23        }
24    }
25
26    ///  # Safety
27    ///  Two threads concurrently writing to the same location will cause UB!!
28    #[allow(clippy::mut_from_ref)]
29    pub unsafe fn get(&self, index: usize) -> &mut T {
30        &mut *self.slice[index].get()
31    }
32}
33
34#[cfg(test)]
35mod tests {
36    use super::UnsafeSlice;
37
38    #[test]
39    fn instantiate() {
40        let mut data = vec![0, 1, 23, 83, 38, 3, 8947, 2762];
41        let slice = UnsafeSlice::new(&mut data);
42        assert_eq!(unsafe { *slice.get(0) }, 0);
43        assert_eq!(unsafe { *slice.get(1) }, 1);
44        assert_eq!(unsafe { *slice.get(2) }, 23);
45        assert_eq!(unsafe { *slice.get(3) }, 83);
46        assert_eq!(unsafe { *slice.get(4) }, 38);
47        assert_eq!(unsafe { *slice.get(5) }, 3);
48        assert_eq!(unsafe { *slice.get(6) }, 8947);
49        assert_eq!(unsafe { *slice.get(7) }, 2762);
50    }
51}