use std::marker::PhantomData; use enum_dispatch::enum_dispatch; type Function<'a> = unsafe extern "C" fn(PointerWithLifetime<'a>); #[derive(Clone, Copy)] #[repr(transparent)] pub struct PointerWithLifetime<'a> { value: usize, lifetime: core::marker::PhantomData<&'a ()> } impl<'a> From for PointerWithLifetime<'a> { fn from(value : usize) -> Self { PointerWithLifetime {value, lifetime: PhantomData } } } impl<'a, T> From<&'a T> for PointerWithLifetime<'a> { fn from(reference: &'a T) -> Self { let p = reference as *const T as usize; return Self::from(p); } } impl<'a> core::fmt::Debug for PointerWithLifetime<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "PointerWithLifetime::from(0x{:x})", self.value) } } impl <'a> PointerWithLifetime<'a> { /// safety: T must be the same type as this pointer was created from. unsafe fn cast(self) -> &'a T { unsafe{&*(self.value as *const T)} } } #[enum_dispatch] trait Execute : Sized{ fn execute(&self); fn get_exec<'a>(&'a self) -> (Function, PointerWithLifetime<'a>) { let f = execute_from_c::; return (f, PointerWithLifetime::from(self)); } } struct Hallo{name: String} impl Execute for Hallo { fn execute(&self) { println!("Hallo {}", self.name); } } struct Bla{b: u8} impl Execute for Bla { fn execute(&self) { println!("Bla: {}", self.b); } } #[enum_dispatch(Execute)] enum Instruction { Bla, Hallo } unsafe extern "C" fn execute_from_c(c_self: PointerWithLifetime<'_>) { c_self.cast::().execute(); } fn main() { let ins1 : Instruction= Bla{b: 3}.into(); ins1.execute(); let ins2 : Instruction= Hallo{name: "du da".into()}.into(); ins2.execute(); dbg!(ins1.get_exec()); dbg!(ins2.get_exec()); unsafe{ let (f,a) = ins1.get_exec(); callit(f, a); } unsafe{ let (f,a) = ins2.get_exec(); callit(f, a); } let x = callit; dbg!(std::ptr::addr_of!(x)); } pub unsafe extern "C" fn callit<'a>(f: Function<'a>, a: PointerWithLifetime<'a>) { f(a); }