Playground: Rust Playground
I want to generify FnHolder
so it can take any type of FnMut with any singular return type. However, FnHolder::invoke()
requires an explicit return type that is implied within the existence of the FnMut. Is there a way to generify this?
use std::pin::Pin;
extern crate crossbeam; // 0.7.2
use crossbeam::atomic::AtomicCell;
use std::sync::Arc;
struct Tmp {
value: usize
}
struct FnHolder {
inner: Arc<AtomicCell<Box<dyn FnMut(usize) -> usize>>>
}
unsafe impl Send for FnHolder {}
unsafe impl Sync for FnHolder {}
impl Clone for FnHolder {
fn clone(&self) -> Self {
Self {inner: self.inner.clone()}
}
}
impl FnHolder {
pub fn new(fx: Box<dyn FnMut(usize) -> usize>) -> Self {
Self {inner: Arc::new(AtomicCell::new(fx))}
}
pub fn invoke(&self, input: usize) -> usize {
unsafe { (&mut *self.inner.as_ptr())(input) }
}
}
impl Tmp {
// Contract: follow the contract of Pin, and, keep self alive at least as long as the boxed closure below
fn create_fn(mut self: Pin<&mut Self>) -> Box<dyn FnMut(usize) -> usize> {
let self_ptr = &mut *self as *mut Self; // We have to ensure that self lives-on as long as this function gets called
Box::new(
move |val: usize| unsafe {
let this = &mut *self_ptr;
this.value += val;
this.value
}
)
}
}
fn main() {
let mut tmp = Box::pin(Tmp { value: 0 });
let fn_holder = FnHolder::new(tmp.as_mut().create_fn());
//std::mem::drop(tmp); Doing this violates the contract
for idx in 0.. 1000 {
let fn_holder = fn_holder.clone();
std::thread::spawn(move || {
println!("[{}] {}", idx, fn_holder.invoke(10));
}).join();
}
println!("{}", fn_holder.invoke(10));
}