Skip to content

Instantly share code, notes, and snippets.

@azriel91
Created December 10, 2021 03:22
Show Gist options
  • Save azriel91/e7b4739df6a7db7f16ea96e5ef7c6e22 to your computer and use it in GitHub Desktop.
Save azriel91/e7b4739df6a7db7f16ea96e5ef7c6e22 to your computer and use it in GitHub Desktop.
Store any function and call it with borrowed ID.
// Cargo.toml
//
// [dependencies]
// resman = { version = "0.11.0", features = ["debug"] }
// futures = "0.3.18"
// tokio = { version = "1.13.0", features = ["rt"] }
use std::{fmt::Debug, marker::PhantomData};
use futures::{
future::{FutureExt, LocalBoxFuture},
StreamExt,
};
use resman::Resources;
trait FnSpec<R> {
fn call<'f1: 'f2, 'f2>(
&'f2 self,
id: &'f1 mut u8,
map: &'f2 Resources,
) -> LocalBoxFuture<'f2, R>;
}
struct FnSpecImpl<F, R, Args> {
f: F,
marker: PhantomData<(R, Args)>,
}
impl<F, R> FnSpec<R> for FnSpecImpl<F, R, ()>
where
F: for<'f> Fn(&'f mut u8) -> LocalBoxFuture<'f, R>,
{
fn call<'f1: 'f2, 'f2>(&self, id: &'f1 mut u8, _map: &'f2 Resources) -> LocalBoxFuture<'f2, R> {
(self.f)(id)
}
}
impl<F, R, A0> FnSpec<R> for FnSpecImpl<F, R, (A0,)>
where
F: for<'f> Fn(&'f mut u8, &'f A0) -> LocalBoxFuture<'f, R>,
A0: Debug + Send + Sync + 'static,
{
fn call<'f1: 'f2, 'f2>(
&'f2 self,
mut id: &'f1 mut u8,
map: &'f2 Resources,
) -> LocalBoxFuture<'f2, R> {
async move {
let id = &mut id;
let a0 = &map.borrow::<A0>();
(self.f)(id, a0).await
}
.boxed_local()
}
}
struct AnyFnWrapper<R>(Box<dyn FnSpec<R>>);
impl<R> AnyFnWrapper<R>
where
R: 'static,
{
fn new0<F>(f: F) -> Self
where
F: 'static,
FnSpecImpl<F, R, ()>: FnSpec<R>,
{
let fn_spec_impl = FnSpecImpl {
f,
marker: PhantomData,
};
Self(Box::new(fn_spec_impl))
}
fn new1<F, A0>(f: F) -> Self
where
F: for<'f> Fn(&'f mut u8, &'f A0) -> LocalBoxFuture<'f, R> + 'static,
A0: 'static,
FnSpecImpl<F, R, (A0,)>: FnSpec<R>,
{
let fn_spec_impl = FnSpecImpl {
f,
marker: PhantomData,
};
Self(Box::new(fn_spec_impl))
}
}
fn main() {
let fn1 = AnyFnWrapper::<u64>::new0(|id: &mut u8| async move { *id as u64 }.boxed_local());
let fn2 = AnyFnWrapper::<u64>::new1(|id: &mut u8, value: &u32| {
async move { (*id as u64) + (*value as u64) }.boxed_local()
});
let mut resources = Resources::new();
resources.insert(10u32);
let resources = &resources;
let rt = tokio::runtime::Builder::new_current_thread()
.build()
.expect("Failed to build runtime.");
let sum = rt.block_on(
futures::stream::iter([fn1, fn2].into_iter().enumerate())
.fold(0, |sum, (id, f)| async move {
sum + f.0.call(&mut ((id + 3) as u8), resources).await
}),
);
println!("sum: {}", sum);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment