cxx/
rust_slice.rs

1#![allow(missing_docs)]
2
3use core::mem::{self, MaybeUninit};
4use core::ptr::{self, NonNull};
5use core::slice;
6
7// ABI compatible with C++ rust::Slice<T> (not necessarily &[T]).
8#[repr(C)]
9pub struct RustSlice {
10    repr: [MaybeUninit<usize>; mem::size_of::<NonNull<[()]>>() / mem::size_of::<usize>()],
11}
12
13impl RustSlice {
14    pub fn from_ref<T>(slice: &[T]) -> Self {
15        let ptr = NonNull::from(slice).cast::<T>();
16        let len = slice.len();
17        Self::from_raw_parts(ptr, len)
18    }
19
20    pub fn from_mut<T>(slice: &mut [T]) -> Self {
21        let ptr = NonNull::from(&mut *slice).cast::<T>();
22        let len = slice.len();
23        Self::from_raw_parts(ptr, len)
24    }
25
26    pub unsafe fn as_slice<'a, T>(self) -> &'a [T] {
27        let ptr = self.as_non_null_ptr().as_ptr();
28        let len = self.len();
29        unsafe { slice::from_raw_parts(ptr, len) }
30    }
31
32    pub unsafe fn as_mut_slice<'a, T>(self) -> &'a mut [T] {
33        let ptr = self.as_non_null_ptr().as_ptr();
34        let len = self.len();
35        unsafe { slice::from_raw_parts_mut(ptr, len) }
36    }
37
38    pub(crate) fn from_raw_parts<T>(ptr: NonNull<T>, len: usize) -> Self {
39        // TODO: use NonNull::from_raw_parts(ptr.cast(), len) when stable.
40        // https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html#method.from_raw_parts
41        // https://github.com/rust-lang/rust/issues/81513
42        let ptr = ptr::slice_from_raw_parts_mut(ptr.as_ptr().cast(), len);
43        unsafe { mem::transmute::<NonNull<[()]>, RustSlice>(NonNull::new_unchecked(ptr)) }
44    }
45
46    pub(crate) fn as_non_null_ptr<T>(&self) -> NonNull<T> {
47        let rust_slice = RustSlice { repr: self.repr };
48        let repr = unsafe { mem::transmute::<RustSlice, NonNull<[()]>>(rust_slice) };
49        repr.cast()
50    }
51
52    pub(crate) fn len(&self) -> usize {
53        let rust_slice = RustSlice { repr: self.repr };
54        let repr = unsafe { mem::transmute::<RustSlice, NonNull<[()]>>(rust_slice) };
55        // TODO: use repr.len() when stable.
56        // https://doc.rust-lang.org/nightly/std/ptr/struct.NonNull.html#method.len
57        // https://github.com/rust-lang/rust/issues/71146
58        unsafe { repr.as_ref() }.len()
59    }
60}
61
62const_assert_eq!(mem::size_of::<NonNull<[()]>>(), mem::size_of::<RustSlice>());
63const_assert_eq!(
64    mem::align_of::<NonNull<[()]>>(),
65    mem::align_of::<RustSlice>(),
66);