First try: Hide the Future type
pub trait Callback<A>: for<'any> FnMut(A::V<'any>) -> Self::Fut
where
A: Arg,
{
type Fut: Future<Output = ()> + Send;
}
Unfortunately, it hits the common pitfall of async callbacks.
error: lifetime may not live long enough
--> src/main.rs:76:23
|
76 | let _ = run(|res| async move {
| __________________----_^
| | | |
| | | return type of closure `[async block@src/main.rs:76:23: 78:6]` contains a lifetime `'2`
| | has type `Response<'1>`
77 | | println!("{:?}", res);
78 | | })
| |_____^ returning this value requires that `'1` must outlive `'2`
See this post FYI: How to express that the Future returned by a closure lives only as long as its argument?
Second try: Use Box::Pin to connect the lifetime relation between inputs and the output
error[E0582]: binding for associated type `Output` references lifetime `'any`, which does not appear in the trait input types
--> src/main.rs:57:55
|
57 | pub trait Callback<A>: for<'any> FnMut(A::V<'any>) -> BoxFuture<'any, ()>
| ^^^^^^^^^^^^^^^^^^^
error[E0582]: binding for associated type `Output` references lifetime `'any`, which does not appear in the trait input types
--> src/main.rs:66:39
|
66 | F: for<'any> FnMut(A::V<'any>) -> BoxFuture<'any, ()>
| ^^^^^^^^^^^^^^^^^^^
Well, Rust doesn't allow the HRTB here.
Third try: Put the lifetime on the trait
pub trait Callback<'any, A>: FnMut(A::V<'any>) -> BoxFuture<'any, ()>
where
A: Arg + 'any,
It works.
Bonus: Relax the lifetime bound on Arg::V<'a> where Self: 'a
pub trait Callback<'arg, A>: FnMut(A::V<'arg>) -> BoxFuture<'arg, ()>
where
A: Arg,
Retro: Apply the same trick to the first try
error: implementation of `Callback` is not general enough
--> src/main.rs:74:13
|
74 | let _ = run(|res| async move {
| _____________^
75 | | println!("{:?}", res);
76 | | })
| |______^ implementation of `Callback` is not general enough
|
= note: `[closure@src/main.rs:74:17: 74:22]` must implement `Callback<'0, AbstructStruct>`, for any lifetime `'0`...
= note: ...but it actually implements `Callback<'1, AbstructStruct>`, for some specific lifetime `'1`
It only works for async functions
[1]
Update: I've added the code here as an example of my crate async_closure.
You don't have to
- define your Callback trait
- or Box the return Future
- or worry about captured variables with references
but I don't recommend using it.
which is known for no reason, Lifetime bounds to use for Future that isn't supposed to outlive calling scope - #3 by steffahn ↩︎