Skip to content

Instantly share code, notes, and snippets.

@kognise
Created July 12, 2024 20:14
Show Gist options
  • Save kognise/0280e2c742cd9c07b1079776009927af to your computer and use it in GitHub Desktop.
Save kognise/0280e2c742cd9c07b1079776009927af to your computer and use it in GitHub Desktop.
use std::marker::PhantomData;
use std::ptr;
// Behaves like &'a mut dyn FnMut,
// except requires only one pointer indirection for functions without data.
struct ShallowFnMutRef<'a> {
fn_ptr: unsafe fn(*mut ()),
data: *mut (),
_marker: PhantomData<&'a mut ()>,
}
impl<'a> ShallowFnMutRef<'a> {
fn from_closure<F: FnMut()>(f: &'a mut F) -> Self {
unsafe fn call_closure<F: FnMut()>(closure_ptr: *mut ()) {
(&mut*closure_ptr.cast::<F>())();
}
Self {
fn_ptr: call_closure::<F>,
data: (f as *mut F).cast::<()>(),
_marker: PhantomData,
}
}
fn from_fn<F: Fn() + 'a>(_: F) -> Self {
const { assert!(std::mem::size_of::<F>() == 0) }
fn forward_to_f<F: Fn()>(_: *mut ()) {
let f: F = unsafe { ptr::NonNull::<F>::dangling().as_ptr().read() };
f();
}
Self {
fn_ptr: forward_to_f::<F>,
data: ptr::null_mut(),
_marker: PhantomData,
}
}
fn call(&mut self) {
unsafe { (self.fn_ptr)(self.data) }
}
}
fn foo() {
println!("foo called");
}
fn main() {
let s = String::from("closure called");
let mut closure = move || println!("{s}");
ShallowFnMutRef::from_fn(foo).call();
ShallowFnMutRef::from_closure(&mut closure).call();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment