peku33
peku33

Reputation: 3903

Using higher order lifetime bounds for associated types

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

Answers (1)

jplatte
jplatte

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

Related Questions