Reputation: 3903
I would like to create a function - let's call it foo
.
I would like this function to take predicate
parameter that is FnOnce
Predicate takes one parameter t
- reference of type T
.
Predicate returns Future that captures t
lifetime.
Typical predicate
can look like this:
fn predicate<'a>(instance: &'a SomeType) -> Future<Output = ()> + 'a
.
While I'm able to achieve this using higher order lifetime bounds and BoxFuture
:
fn foo_boxed<T, E, R>(predicate: E)
where
for<'a> E: FnOnce(&'a T) -> BoxFuture<'a, R> + Send + 'static,
R: Send + 'static,
{
}
I would like to achieve the same result using generics only.
It looks like for<'a>
syntax matches the nearest parameter only, so the following won't compile:
fn foo_non_boxed_1<T, E, F>(predicate: E)
where
for<'a> E: FnOnce(&'a T) -> F + Send + 'static,
F: Future + Send + 'a, // 'a is undeclared here
F::Output: Send + 'static,
{
}
Inside the foo
I would like to store the predicate for later use and call it from another thread, passing T
.
Is there any way to achieve this?
Upvotes: 2
Views: 61
Reputation: 1141
You need an extra trait to work around <Type as FnOnce(T) -> _>::Output
not being valid, but here is a solution:
use std::future::Future;
trait MyFnOnce<T, O>: FnOnce(T) -> O {
type Output;
}
impl<T, O, F> MyFnOnce<T, O> for F
where
F: FnOnce(T) -> O,
{
type Output = O;
}
fn foo_non_boxed_1<T, E, F>(predicate: E)
where
E: for<'a> FnOnce(&'a T) -> F + Send + 'static,
for<'a> <E as MyFnOnce<&'a T, F>>::Output: 'a,
F: Future + Send,
F::Output: Send + 'static,
{
}
Alternatively, on Nightly you don't need the extra trait but two feature flags:
#![feature(fn_traits, unboxed_closures)]
use std::future::Future;
fn foo_non_boxed_1<T, E, F>(predicate: E)
where
E: for<'a> FnOnce(&'a T) -> F + Send + 'static,
for<'a> <E as FnOnce<&'a T>>::Output: 'a,
F: Future + Send,
F::Output: Send + 'static,
{
}
Upvotes: 1