Created
December 10, 2021 03:22
-
-
Save azriel91/e7b4739df6a7db7f16ea96e5ef7c6e22 to your computer and use it in GitHub Desktop.
Store any function and call it with borrowed ID.
This file contains hidden or 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
// 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