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
macro_rules! portable_bit_semantics_docs {
    ($item:item) => {
        /// Types whose in-memory bit representation on the CPU host is safe to copy
        /// to and read back on the GPU device while maintaining the same semantics,
        /// iff the type layout on the CPU matches the type layout on the GPU.
        ///
        /// For a type to implement [`PortableBitSemantics`], it
        ///
        /// * should have the same memory layout on both the CPU and GPU, and
        ///
        /// * must not contain any references to data that are exposed as safely
        ///   accessible on both ends but actually inaccessible on one.
        ///
        /// For instance, a reference `&u8` to host memory has the same well-defined
        /// layout on both CPU and GPU (if their pointer sizes and alignments
        /// match), but it is not portable since the host memory is generally
        /// not accessible from the GPU.
        ///
        /// This trait is automatically implemented when the compiler determines
        /// it's appropriate.
        ///
        /// Note that this trait is *sealed*, i.e. you cannot implement it on your
        /// own custom types.
        ///
        /// Trait bounds usually combine [`PortableBitSemantics`] with
        /// [`TypeGraphLayout`](const_type_layout::TypeGraphLayout) to check that
        /// the type layout is indeed the same on both the host CPU and the GPU
        /// device.
        ///
        /// Types that implement [`StackOnly`](crate::safety::StackOnly) and
        /// [`TypeGraphLayout`](const_type_layout::TypeGraphLayout) satisfy both
        /// of the above criteria and thus also implement [`PortableBitSemantics`].
        $item
    };
}

#[cfg(not(doc))]
portable_bit_semantics_docs! {
    #[expect(clippy::module_name_repetitions)]
    pub trait PortableBitSemantics: sealed::PortableBitSemantics {}
}
#[cfg(doc)]
portable_bit_semantics_docs! {
    pub use sealed::PortableBitSemantics;
}

#[cfg(not(doc))]
impl<T: ?Sized + sealed::PortableBitSemantics> PortableBitSemantics for T {}

mod sealed {
    pub auto trait PortableBitSemantics {}

    impl<T: ?Sized> !PortableBitSemantics for &T {}
    impl<T: ?Sized> !PortableBitSemantics for &mut T {}
    impl<T: ?Sized> !PortableBitSemantics for *const T {}
    impl<T: ?Sized> !PortableBitSemantics for *mut T {}

    impl<T> PortableBitSemantics for core::marker::PhantomData<T> {}

    impl<T: PortableBitSemantics> PortableBitSemantics for crate::utils::ffi::DeviceConstPointer<T> {}
    impl<T: PortableBitSemantics> PortableBitSemantics for crate::utils::ffi::DeviceMutPointer<T> {}
    impl<T: PortableBitSemantics> PortableBitSemantics for crate::utils::ffi::DeviceOwnedPointer<T> {}
}