From 3564de893e0a8abd8917697b3d337d7085b6a775 Mon Sep 17 00:00:00 2001 From: Avril Date: Thu, 25 Mar 2021 00:39:16 +0000 Subject: [PATCH] with_alloca works --- src/ffi.rs | 2 +- src/lib.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/ffi.rs b/src/ffi.rs index 17d28ae..0f6b49b 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1,6 +1,6 @@ use std::ffi::c_void; -pub type CallbackRaw = extern "C" fn (ptr: *mut c_void, data: *mut c_void)->(); +pub type CallbackRaw = unsafe extern "C" fn (ptr: *mut c_void, data: *mut c_void)->(); extern "C" { fn _alloca_trampoline(size: usize, cb: Option, data: *mut c_void); diff --git a/src/lib.rs b/src/lib.rs index 3b5052b..6019bcc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,10 +1,80 @@ +#![allow(dead_code)] + +use std::{ + mem::{ + MaybeUninit, + ManuallyDrop, + }, + panic::{ + self, + AssertUnwindSafe, + }, + slice, + ffi::c_void, +}; mod ffi; +pub fn with_alloca(size: usize, callback: F) -> T +where F: FnOnce(&mut [MaybeUninit]) -> T +{ + let mut callback = ManuallyDrop::new(callback); + let mut rval = MaybeUninit::uninit(); + + let mut callback = |allocad_ptr: *mut c_void| { + unsafe { + let slice = slice::from_raw_parts_mut(allocad_ptr as *mut MaybeUninit, size); + let callback = ManuallyDrop::take(&mut callback); + rval = MaybeUninit::new(panic::catch_unwind(AssertUnwindSafe(move || callback(slice)))); + } + }; + + /// Create and use the trampoline for input closure `F`. + #[inline(always)] fn create_trampoline(_: &F) -> ffi::CallbackRaw + where F: FnMut(*mut c_void) + { + unsafe extern "C" fn trampoline(ptr: *mut c_void, data: *mut c_void) + { + (&mut *(data as *mut F))(ptr); + } + + trampoline:: + } + + let rval = unsafe { + ffi::alloca_trampoline(size, create_trampoline(&callback), &mut callback as *mut _ as *mut c_void); + rval.assume_init() + }; + + match rval + { + Ok(v) => v, + Err(pan) => panic::resume_unwind(pan), + } +} #[cfg(test)] mod tests { + #[test] + fn with_alloca() + { + use std::mem::MaybeUninit; + + const SIZE: usize = 128; + let sum = super::with_alloca(SIZE, |buf| { + + println!("Buffer size is {}", buf.len()); + for (i, x) in (1..).zip(buf.iter_mut()) { + *x = MaybeUninit::new(i as u8); + } + eprintln!("Buffer is now {:?}", unsafe { std::mem::transmute::<_, & &mut [u8]>(&buf) }); + + buf.iter().map(|x| unsafe { x.assume_init() } as u64).sum::() + }); + + assert_eq!(sum, (1..=SIZE).sum::() as u64); + } #[test] fn raw_trampoline() {