diff --git a/src/copy.rs b/src/copy.rs index fb74a31..ca0b2ba 100644 --- a/src/copy.rs +++ b/src/copy.rs @@ -56,7 +56,7 @@ impl From for CopyRecord { /// things if you read the copied data in the wrong way. See the /// [crate-level Safety documentation][`crate#safety`] for more. #[inline(always)] -pub fn copy_to_offset_exact( +pub fn copy_to_offset_exact( src: &T, dst: &mut S, start_offset: usize, @@ -84,7 +84,7 @@ pub fn copy_to_offset_exact( /// things if you read the copied data in the wrong way. See the /// [crate-level Safety documentation][`crate#safety`] for more. #[inline(always)] -pub fn copy_to_offset_with_align_exact( +pub fn copy_to_offset_with_align_exact( src: &T, dst: &mut S, start_offset: usize, @@ -127,7 +127,7 @@ pub fn copy_to_offset_with_align_exact( /// things if you read the copied data in the wrong way. See the /// [crate-level Safety documentation][`crate#safety`] for more. #[inline] -pub fn copy_to_offset( +pub fn copy_to_offset( src: &T, dst: &mut S, start_offset: usize, @@ -154,7 +154,7 @@ pub fn copy_to_offset( /// things if you read the copied data in the wrong way. See the /// [crate-level Safety documentation][`crate#safety`] for more. #[inline] -pub fn copy_to_offset_with_align( +pub fn copy_to_offset_with_align( src: &T, dst: &mut S, start_offset: usize, @@ -197,7 +197,7 @@ pub fn copy_to_offset_with_align( /// things if you read the copied data in the wrong way. See the /// [crate-level Safety documentation][`crate#safety`] for more. #[inline] -pub fn copy_from_slice_to_offset_exact( +pub fn copy_from_slice_to_offset_exact( src: &[T], dst: &mut S, start_offset: usize, @@ -225,7 +225,7 @@ pub fn copy_from_slice_to_offset_exact( /// things if you read the copied data in the wrong way. See the /// [crate-level Safety documentation][`crate#safety`] for more. #[inline] -pub fn copy_from_slice_to_offset_with_align_exact( +pub fn copy_from_slice_to_offset_with_align_exact( src: &[T], dst: &mut S, start_offset: usize, @@ -268,7 +268,7 @@ pub fn copy_from_slice_to_offset_with_align_exact( /// things if you read the copied data in the wrong way. See the /// [crate-level Safety documentation][`crate#safety`] for more. #[inline] -pub fn copy_from_slice_to_offset( +pub fn copy_from_slice_to_offset( src: &[T], dst: &mut S, start_offset: usize, @@ -297,7 +297,7 @@ pub fn copy_from_slice_to_offset( /// things if you read the copied data in the wrong way. See the /// [crate-level Safety documentation][`crate#safety`] for more. #[inline] -pub fn copy_from_slice_to_offset_with_align( +pub fn copy_from_slice_to_offset_with_align( src: &[T], dst: &mut S, start_offset: usize, @@ -351,7 +351,7 @@ pub fn copy_from_slice_to_offset_with_align( /// [crate-level Safety documentation][`crate#safety`] for more. #[cfg(feature = "std")] #[inline] -pub fn copy_from_iter_to_offset_with_align, S: Slab>( +pub fn copy_from_iter_to_offset_with_align, S: Slab + ?Sized>( src: Iter, dst: &mut S, start_offset: usize, @@ -374,7 +374,11 @@ pub fn copy_from_iter_to_offset_with_align, S: /// Because of this, only one [`CopyRecord`] is returned specifying the record of the /// entire block of copied data. If the `src` iterator is empty, returns `None`. #[inline] -pub fn copy_from_iter_to_offset_with_align_packed, S: Slab>( +pub fn copy_from_iter_to_offset_with_align_packed< + T: Copy, + Iter: Iterator, + S: Slab + ?Sized, +>( mut src: Iter, dst: &mut S, start_offset: usize, @@ -407,7 +411,7 @@ pub fn copy_from_iter_to_offset_with_align_packed, - S: Slab, + S: Slab + ?Sized, >( mut src: Iter, dst: &mut S, diff --git a/src/lib.rs b/src/lib.rs index 0c40409..d982dd9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -360,10 +360,10 @@ pub unsafe trait Slab { } } -// SAFETY: The captured `[MaybeUninit]` will all be part of the same allocation object, and borrowck +// SAFETY: The captured `[MaybeUninit]` will all be part of the same allocation object, and borrowck // will ensure that the borrows that occur on `self` on the relevant methods live long enough since they are // native borrows anyway. -unsafe impl Slab for [MaybeUninit] { +unsafe impl Slab for [MaybeUninit] { fn base_ptr(&self) -> *const u8 { self.as_ptr().cast() } @@ -611,7 +611,7 @@ pub(crate) struct ComputedOffsets { /// Compute and validate offsets for a copy or read operation with the given parameters. #[inline(always)] -pub(crate) fn compute_and_validate_offsets( +pub(crate) fn compute_and_validate_offsets( slab: &S, start_offset: usize, t_layout: Layout, @@ -662,10 +662,11 @@ fn align_offset_up_to(ptr: usize, offset: usize, align: usize) -> Option Some(aligned_ptr - ptr) } -/// Make a `[MaybeUninit; N]` on the stack, which implements [`Slab`] and can therefore be used +/// Make a `[MaybeUninit; N]` on the stack, which implements [`Slab`] and can therefore be used /// with many of the helpers provided by this crate. -pub fn make_stack_slab() -> [MaybeUninit; N] { - [MaybeUninit::uninit(); N] +pub fn make_stack_slab() -> [MaybeUninit; N] { + // SAFETY: An uninitialized `[MaybeUninit<_>; N]` is valid. + unsafe { MaybeUninit::<[MaybeUninit; N]>::uninit().assume_init() } } /// A raw allocation on the heap which implements [`Slab`] and gets deallocated on [`Drop`]. @@ -721,3 +722,62 @@ unsafe impl Slab for HeapSlab { self.layout.size() } } + +#[cfg(test)] +mod test { + use core::ffi::c_void; + use core::ptr::NonNull; + + use crate::copy_from_slice_to_offset; + use crate::make_stack_slab; + use crate::readback_slice_from_ffi; + use crate::RawAllocation; + + #[test] + fn readback_ffi() { + #[repr(C)] + #[derive(Clone, Copy, Default, PartialEq, Debug)] + struct OverlapHit { + pos: [f32; 3], + normal: [f32; 3], + } + + const MAX_HITS: usize = 32; + + let mut hits_slab = make_stack_slab::(); + + let readback_hits = unsafe { + readback_slice_from_ffi(hits_slab.as_mut_slice(), |ptr, _| { + let written_hits = ffi_get_hits(ptr, MAX_HITS); + written_hits + }) + } + .unwrap(); + + assert_eq!(&HITS_TO_WRITE, readback_hits); + + const HITS_TO_WRITE: [OverlapHit; 2] = [ + OverlapHit { + pos: [1.0, 2.0, 10.0], + normal: [0.0, 1.0, 0.0], + }, + OverlapHit { + pos: [11.0, 5.0, 100.0], + normal: [0.0, 0.0, 1.0], + }, + ]; + + // simulate C ffi call to a physics lib + fn ffi_get_hits(out_hits: *mut c_void, max_len: usize) -> usize { + let mut slab = RawAllocation { + base_ptr: NonNull::new(out_hits.cast()).unwrap(), + size: max_len * core::mem::size_of::(), + }; + + copy_from_slice_to_offset(&HITS_TO_WRITE, &mut unsafe { slab.borrow_as_slab() }, 0) + .unwrap(); + + return HITS_TO_WRITE.len(); + } + } +} diff --git a/src/read.rs b/src/read.rs index b0b86c0..717fffe 100644 --- a/src/read.rs +++ b/src/read.rs @@ -22,7 +22,7 @@ use super::*; /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. pub unsafe fn readback_from_ffi<'a, T, S, F>(slab: &'a mut S, fill_slab: F) -> Result<&'a T, Error> where - S: Slab, + S: Slab + ?Sized, F: FnOnce(*mut c_void), { let t_layout = Layout::new::(); @@ -68,7 +68,7 @@ pub unsafe fn readback_slice_from_ffi<'a, T, S, F>( fill_slab: F, ) -> Result<&'a [T], Error> where - S: Slab, + S: Slab + ?Sized, F: FnOnce(*mut c_void, usize) -> usize, { let t_layout = Layout::new::(); @@ -112,7 +112,10 @@ where /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub unsafe fn read_at_offset<'a, T, S: Slab>(slab: &'a S, offset: usize) -> Result<&'a T, Error> { +pub unsafe fn read_at_offset<'a, T, S: Slab + ?Sized>( + slab: &'a S, + offset: usize, +) -> Result<&'a T, Error> { let t_layout = Layout::new::(); let offsets = compute_and_validate_offsets(slab, offset, t_layout, 1, true)?; @@ -144,7 +147,10 @@ pub unsafe fn read_at_offset<'a, T, S: Slab>(slab: &'a S, offset: usize) -> Resu /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub unsafe fn read_at_offset_unchecked<'a, T, S: Slab>(slab: &'a S, offset: usize) -> &'a T { +pub unsafe fn read_at_offset_unchecked<'a, T, S: Slab + ?Sized>( + slab: &'a S, + offset: usize, +) -> &'a T { // SAFETY: if offset is within the slab as guaranteed by function-level safety, this is // safe since a slab's size must be < isize::MAX let ptr = unsafe { slab.base_ptr().add(offset) }.cast::(); @@ -182,7 +188,7 @@ pub unsafe fn read_at_offset_unchecked<'a, T, S: Slab>(slab: &'a S, offset: usiz /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub unsafe fn read_at_offset_mut<'a, T, S: Slab>( +pub unsafe fn read_at_offset_mut<'a, T, S: Slab + ?Sized>( slab: &'a mut S, offset: usize, ) -> Result<&'a mut T, Error> { @@ -225,7 +231,7 @@ pub unsafe fn read_at_offset_mut<'a, T, S: Slab>( /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub unsafe fn read_at_offset_mut_unchecked<'a, T, S: Slab>( +pub unsafe fn read_at_offset_mut_unchecked<'a, T, S: Slab + ?Sized>( slab: &'a mut S, offset: usize, ) -> &'a mut T { @@ -266,7 +272,7 @@ pub unsafe fn read_at_offset_mut_unchecked<'a, T, S: Slab>( /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub fn get_maybe_uninit_at_offset_mut<'a, T, S: Slab>( +pub fn get_maybe_uninit_at_offset_mut<'a, T, S: Slab + ?Sized>( slab: &'a mut S, offset: usize, ) -> Result<&'a mut MaybeUninit, Error> { @@ -308,7 +314,7 @@ pub fn get_maybe_uninit_at_offset_mut<'a, T, S: Slab>( /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub unsafe fn get_maybe_uninit_at_offset_mut_unchecked<'a, T, S: Slab>( +pub unsafe fn get_maybe_uninit_at_offset_mut_unchecked<'a, T, S: Slab + ?Sized>( slab: &'a mut S, offset: usize, ) -> &'a mut MaybeUninit { @@ -341,7 +347,7 @@ pub unsafe fn get_maybe_uninit_at_offset_mut_unchecked<'a, T, S: Slab>( /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub unsafe fn read_slice_at_offset<'a, T, S: Slab>( +pub unsafe fn read_slice_at_offset<'a, T, S: Slab + ?Sized>( slab: &'a S, offset: usize, len: usize, @@ -382,7 +388,7 @@ pub unsafe fn read_slice_at_offset<'a, T, S: Slab>( /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. /// - See also safety docs of [`core::slice::from_raw_parts`]. #[inline] -pub unsafe fn read_slice_at_offset_unchecked<'a, T, S: Slab>( +pub unsafe fn read_slice_at_offset_unchecked<'a, T, S: Slab + ?Sized>( slab: &'a S, offset: usize, len: usize, @@ -425,7 +431,7 @@ pub unsafe fn read_slice_at_offset_unchecked<'a, T, S: Slab>( /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub unsafe fn read_slice_at_offset_mut<'a, T, S: Slab>( +pub unsafe fn read_slice_at_offset_mut<'a, T, S: Slab + ?Sized>( slab: &'a mut S, offset: usize, len: usize, @@ -474,7 +480,7 @@ pub unsafe fn read_slice_at_offset_mut<'a, T, S: Slab>( /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub unsafe fn read_slice_at_offset_mut_unchecked<'a, T, S: Slab>( +pub unsafe fn read_slice_at_offset_mut_unchecked<'a, T, S: Slab + ?Sized>( slab: &'a mut S, offset: usize, len: usize, @@ -517,7 +523,7 @@ pub unsafe fn read_slice_at_offset_mut_unchecked<'a, T, S: Slab>( /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub fn get_maybe_uninit_slice_at_offset_mut<'a, T, S: Slab>( +pub fn get_maybe_uninit_slice_at_offset_mut<'a, T, S: Slab + ?Sized>( slab: &'a mut S, offset: usize, len: usize, @@ -565,7 +571,7 @@ pub fn get_maybe_uninit_slice_at_offset_mut<'a, T, S: Slab>( /// \* Validity is a complex topic not to be taken lightly. /// See [this rust reference page](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) for more details. #[inline] -pub unsafe fn get_maybe_uninit_slice_at_offset_mut_unchecked<'a, T, S: Slab>( +pub unsafe fn get_maybe_uninit_slice_at_offset_mut_unchecked<'a, T, S: Slab + ?Sized>( slab: &'a mut S, offset: usize, len: usize,