summaryrefslogtreecommitdiff
path: root/crates/utils/src/pin.rs
blob: 202904d5f3ba75d50f60d95fbd25a3528fa4623b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//! Utilities having to do with pinning. I sure hope these are sound!

use contracts::requires;
use core::pin::Pin;
use std::ptr::NonNull;

/// Iterates over projections of elements out of a pinned slice.
pub fn pin_project_slice_mut_iter<T>(slice: Pin<&mut [T]>) -> impl Iterator<Item = Pin<&mut T>> {
    let base_ptr: NonNull<T> = NonNull::from(slice.as_ref().get_ref()).cast();
    (0..slice.len()).map(move |i| {
        // SAFETY: This is in-bounds, since the original slice was valid. No other references to
        // the data can exist, since we visit each index once and have an exclusive borrow on the
        // slice.
        let ptr = unsafe { base_ptr.add(i).as_mut() };
        // SAFETY: This is not certainly sound; see https://github.com/rust-lang/rust/issues/104108
        unsafe { Pin::new_unchecked(ptr) }
    })
}

/// Projects a single element out of a pinned slice.
#[requires(index < slice.len())]
pub fn pin_project_slice_mut<T>(slice: Pin<&mut [T]>, index: usize) -> Pin<&mut T> {
    // SAFETY: This is not certainly sound; see https://github.com/rust-lang/rust/issues/104108
    unsafe { slice.map_unchecked_mut(|slice| &mut slice[index]) }
}