Skip to content

Commit

Permalink
Make [MaybeUninit<T>] as Slab integration better
Browse files Browse the repository at this point in the history
  • Loading branch information
fu5ha committed Nov 7, 2023
1 parent eccc08c commit 971de2a
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 31 deletions.
26 changes: 15 additions & 11 deletions src/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl From<ComputedOffsets> 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<T: Copy, S: Slab>(
pub fn copy_to_offset_exact<T: Copy, S: Slab + ?Sized>(
src: &T,
dst: &mut S,
start_offset: usize,
Expand Down Expand Up @@ -84,7 +84,7 @@ pub fn copy_to_offset_exact<T: Copy, S: Slab>(
/// 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<T: Copy, S: Slab>(
pub fn copy_to_offset_with_align_exact<T: Copy, S: Slab + ?Sized>(
src: &T,
dst: &mut S,
start_offset: usize,
Expand Down Expand Up @@ -127,7 +127,7 @@ pub fn copy_to_offset_with_align_exact<T: Copy, S: Slab>(
/// 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<T: Copy, S: Slab>(
pub fn copy_to_offset<T: Copy, S: Slab + ?Sized>(
src: &T,
dst: &mut S,
start_offset: usize,
Expand All @@ -154,7 +154,7 @@ pub fn copy_to_offset<T: Copy, S: Slab>(
/// 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<T: Copy, S: Slab>(
pub fn copy_to_offset_with_align<T: Copy, S: Slab + ?Sized>(
src: &T,
dst: &mut S,
start_offset: usize,
Expand Down Expand Up @@ -197,7 +197,7 @@ pub fn copy_to_offset_with_align<T: Copy, S: Slab>(
/// 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<T: Copy, S: Slab>(
pub fn copy_from_slice_to_offset_exact<T: Copy, S: Slab + ?Sized>(
src: &[T],
dst: &mut S,
start_offset: usize,
Expand Down Expand Up @@ -225,7 +225,7 @@ pub fn copy_from_slice_to_offset_exact<T: Copy, S: Slab>(
/// 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<T: Copy, S: Slab>(
pub fn copy_from_slice_to_offset_with_align_exact<T: Copy, S: Slab + ?Sized>(
src: &[T],
dst: &mut S,
start_offset: usize,
Expand Down Expand Up @@ -268,7 +268,7 @@ pub fn copy_from_slice_to_offset_with_align_exact<T: Copy, S: Slab>(
/// 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<T: Copy, S: Slab>(
pub fn copy_from_slice_to_offset<T: Copy, S: Slab + ?Sized>(
src: &[T],
dst: &mut S,
start_offset: usize,
Expand Down Expand Up @@ -297,7 +297,7 @@ pub fn copy_from_slice_to_offset<T: Copy, S: Slab>(
/// 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<T: Copy, S: Slab>(
pub fn copy_from_slice_to_offset_with_align<T: Copy, S: Slab + ?Sized>(
src: &[T],
dst: &mut S,
start_offset: usize,
Expand Down Expand Up @@ -351,7 +351,7 @@ pub fn copy_from_slice_to_offset_with_align<T: Copy, S: Slab>(
/// [crate-level Safety documentation][`crate#safety`] for more.
#[cfg(feature = "std")]
#[inline]
pub fn copy_from_iter_to_offset_with_align<T: Copy, Iter: Iterator<Item = T>, S: Slab>(
pub fn copy_from_iter_to_offset_with_align<T: Copy, Iter: Iterator<Item = T>, S: Slab + ?Sized>(
src: Iter,
dst: &mut S,
start_offset: usize,
Expand All @@ -374,7 +374,11 @@ pub fn copy_from_iter_to_offset_with_align<T: Copy, Iter: Iterator<Item = T>, 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<T: Copy, Iter: Iterator<Item = T>, S: Slab>(
pub fn copy_from_iter_to_offset_with_align_packed<
T: Copy,
Iter: Iterator<Item = T>,
S: Slab + ?Sized,
>(
mut src: Iter,
dst: &mut S,
start_offset: usize,
Expand Down Expand Up @@ -407,7 +411,7 @@ pub fn copy_from_iter_to_offset_with_align_packed<T: Copy, Iter: Iterator<Item =
pub fn copy_from_iter_to_offset_with_align_exact_packed<
T: Copy,
Iter: Iterator<Item = T>,
S: Slab,
S: Slab + ?Sized,
>(
mut src: Iter,
dst: &mut S,
Expand Down
72 changes: 66 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,10 +360,10 @@ pub unsafe trait Slab {
}
}

// SAFETY: The captured `[MaybeUninit<u8>]` will all be part of the same allocation object, and borrowck
// SAFETY: The captured `[MaybeUninit<T>]` 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<u8>] {
unsafe impl<T> Slab for [MaybeUninit<T>] {
fn base_ptr(&self) -> *const u8 {
self.as_ptr().cast()
}
Expand Down Expand Up @@ -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<S: Slab>(
pub(crate) fn compute_and_validate_offsets<S: Slab + ?Sized>(
slab: &S,
start_offset: usize,
t_layout: Layout,
Expand Down Expand Up @@ -662,10 +662,11 @@ fn align_offset_up_to(ptr: usize, offset: usize, align: usize) -> Option<usize>
Some(aligned_ptr - ptr)
}

/// Make a `[MaybeUninit<u8>; N]` on the stack, which implements [`Slab`] and can therefore be used
/// Make a `[MaybeUninit<T>; 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<const N: usize>() -> [MaybeUninit<u8>; N] {
[MaybeUninit::uninit(); N]
pub fn make_stack_slab<T, const N: usize>() -> [MaybeUninit<T>; N] {
// SAFETY: An uninitialized `[MaybeUninit<_>; N]` is valid.
unsafe { MaybeUninit::<[MaybeUninit<T>; N]>::uninit().assume_init() }
}

/// A raw allocation on the heap which implements [`Slab`] and gets deallocated on [`Drop`].
Expand Down Expand Up @@ -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::<OverlapHit, MAX_HITS>();

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::<OverlapHit>(),
};

copy_from_slice_to_offset(&HITS_TO_WRITE, &mut unsafe { slab.borrow_as_slab() }, 0)
.unwrap();

return HITS_TO_WRITE.len();
}
}
}
34 changes: 20 additions & 14 deletions src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::<T>();
Expand Down Expand Up @@ -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::<T>();
Expand Down Expand Up @@ -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::<T>();
let offsets = compute_and_validate_offsets(slab, offset, t_layout, 1, true)?;

Expand Down Expand Up @@ -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::<T>();
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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<T>, Error> {
Expand Down Expand Up @@ -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<T> {
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down

0 comments on commit 971de2a

Please sign in to comment.