Created
July 12, 2024 20:14
-
-
Save kognise/0280e2c742cd9c07b1079776009927af to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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