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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#[expect(clippy::module_name_repetitions)]
/// Types for which mutable references can be safely shared with each CUDA
/// thread without breaking Rust's no-mutable-aliasing memory safety
/// guarantees.
///
/// # Safety
///
/// A type may only implement [`SafeMutableAliasing`], if and
/// only if all of the safety conditions below hold:
///
/// * Calling [`std::mem::replace`] on a mutable reference of the type does
///   *not* return a value which owns memory which it must deallocate on drop.
///   For instance, `&mut [T]` satisfies this criteria, but `Box<T>` does not.
///
/// * No safe alising mutable access is provided to the same memory locations
///   across multiple CUDA threads. You can use the
///   [`SplitSliceOverCudaThreadsConstStride`](crate::utils::aliasing::SplitSliceOverCudaThreadsConstStride)
///   and
///   [`SplitSliceOverCudaThreadsDynamicStride`](crate::utils::aliasing::SplitSliceOverCudaThreadsDynamicStride)
///   wrapper types to ensure that each thread is only given access to to its
///   own sub-slice partition so that aliasing is avoided.
///
/// * A mutable reference of the type must not provide mutable access to some
///   shallow inner state (in contrast to deep, which refers to values behind
///   references) of the value which the API user expects to be mutably shared
///   between all threads even if it is not in practice so as to not violate the
///   second condition. For instance, `Vec<T>` violates this third condition, as
///   code with access to `&mut Vec<T>` can also mutate the length of the
///   vector, which is shallow state that is expected to be propagated to the
///   caller of a function sharing this vector (it is also related to the deep
///   contents of the vector via a safety invariant) and might thus assume that
///   mutations of this length are either shared across threads or shared back
///   with the host after the kernel has completed, neither of which is
///   possible. In contrast, `&mut [T]` satisfies this condition, as it is well
///   known that modifying the shallow length of a slice (by assigning a
///   sub-slice) inside a function does not alter the length of the slice that
///   the caller of the function passed in.
pub unsafe trait SafeMutableAliasing {}

unsafe impl<
        'a,
        T: crate::safety::StackOnly
            + crate::safety::PortableBitSemantics
            + const_type_layout::TypeGraphLayout,
        const STRIDE: usize,
    > SafeMutableAliasing
    for crate::utils::aliasing::SplitSliceOverCudaThreadsConstStride<&'a mut [T], STRIDE>
{
}

unsafe impl<
        'a,
        T: crate::safety::StackOnly
            + crate::safety::PortableBitSemantics
            + const_type_layout::TypeGraphLayout,
    > SafeMutableAliasing
    for crate::utils::aliasing::SplitSliceOverCudaThreadsDynamicStride<&'a mut [T]>
{
}

#[cfg(any(feature = "host", feature = "device"))]
unsafe impl<
        T: crate::safety::StackOnly
            + crate::safety::PortableBitSemantics
            + const_type_layout::TypeGraphLayout,
        const M2D: bool,
        const M2H: bool,
        const STRIDE: usize,
    > SafeMutableAliasing
    for crate::utils::aliasing::SplitSliceOverCudaThreadsConstStride<
        crate::utils::exchange::buffer::CudaExchangeBuffer<T, M2D, M2H>,
        STRIDE,
    >
{
}

#[cfg(any(feature = "host", feature = "device"))]
unsafe impl<
        T: crate::safety::StackOnly
            + crate::safety::PortableBitSemantics
            + const_type_layout::TypeGraphLayout,
        const M2D: bool,
        const M2H: bool,
    > SafeMutableAliasing
    for crate::utils::aliasing::SplitSliceOverCudaThreadsDynamicStride<
        crate::utils::exchange::buffer::CudaExchangeBuffer<T, M2D, M2H>,
    >
{
}