Skip to content

Commit f0c1eb4

Browse files
Flesh a few more examples out
1 parent 406e7a6 commit f0c1eb4

File tree

1 file changed

+42
-7
lines changed

1 file changed

+42
-7
lines changed

posts/inside-rust/2024-08-09-async-closures-call-for-testing.md

+42-7
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ Recent [work](https://github.com/rust-lang/rust/pull/120361) has focused on reim
4646
fn test<F>(callback: F)
4747
where
4848
// Either:
49-
async Fn(Arg, Arg) -> Ret
49+
async Fn(Arg, Arg) -> Ret,
5050
// Or:
51-
AsyncFn(Arg, Arg) -> Ret
51+
AsyncFn(Arg, Arg) -> Ret,
5252
```
5353

5454
(It's currently an [open question](https://github.com/rust-lang/rust/issues/128129) exactly how to spell this bound, so both syntaxes are implemented in parallel.)
@@ -77,16 +77,31 @@ And on the callee side, write async fn trait bounds instead of writing "regular"
7777

7878
```rust
7979
// Instead of writing:
80-
fn doesnt_exactly_take_an_async_closure<F, Fut>()
80+
fn doesnt_exactly_take_an_async_closure<F, Fut>(callback: F)
8181
where
8282
F: FnOnce() -> Fut,
8383
Fut: Future<Output = String>
8484
{ todo!() }
8585

8686
// Write this:
87-
fn takes_an_async_closure<F: async FnOnce() -> String>() { todo!() }
87+
fn takes_an_async_closure<F: async FnOnce() -> String>(callback: F) { todo!() }
8888
// Or this:
89-
fn takes_an_async_closure<F: AsyncFnOnce() -> String>() { todo!() }
89+
fn takes_an_async_closure<F: AsyncFnOnce() -> String>(callback: F) { todo!() }
90+
```
91+
92+
Or if you're emulating a higher-ranked async closure with boxing:
93+
94+
```rust
95+
// Instead of writing:
96+
fn higher_ranked<F>(callback: F)
97+
where
98+
F: Fn(&Arg) -> Pin<Box<dyn Future<Output = ()> + '_>>
99+
{ todo!() }
100+
101+
// Write this:
102+
fn higher_ranked<F: async Fn(&Arg)> { todo!() }
103+
// Or this:
104+
fn higher_ranked<F: AsyncFn(&Arg)> { todo!() }
90105
```
91106

92107
## Shortcomings interacting with the async ecosystem
@@ -98,7 +113,7 @@ If you're going to try to rewrite your async projects, there are a few shortcomi
98113
When you name an async callable bound with the *old* style, before first-class async fn trait bounds, then as a side-effect of needing to use two type parameters, you can put additional bounds (e.g. `+ Send` or `+ 'static`) on the `Future` part of the bound, like:
99114

100115
```rust
101-
fn async_callback<F, Fut>()
116+
fn async_callback<F, Fut>(callback: F)
102117
where
103118
F: FnOnce() -> Fut,
104119
Fut: Future<Output = String> + Send + 'static
@@ -119,6 +134,26 @@ We expect to improve async closure signature inference as we move forward.
119134

120135
Some libraries take their callbacks as function *pointers* (`fn()`) rather than generics. Async closures don't currently implement the same coercion from closure to `fn() -> ...`. Some libraries may mitigate this problem by adapting their API to take generic `impl Fn()` instead of `fn()` pointers as an argument.
121136

122-
We don't expect to implement this coercion unless there's a particularly good reason to support it, since this can usually be handled manually by the caller by using an inner function item.
137+
We don't expect to implement this coercion unless there's a particularly good reason to support it, since this can usually be handled manually by the caller by using an inner function item, or by using an `Fn` bound instead: for example:
138+
139+
```rust
140+
fn needs_fn_pointer<T: Future<Output = ()>>(callback: fn() -> T) { todo!() }
141+
142+
fn main() {
143+
// Instead of writing:
144+
needs_fn_pointer(async || { todo!() });
145+
// Since async closures don't currently support coercion to `fn() -> ...`.
146+
147+
// You can use an inner async fn item:
148+
async fn callback() { todo!() }
149+
needs_fn_pointer(callback);
150+
}
151+
152+
// Or if you don't need to take *exactly* a function pointer,
153+
// you can rewrite `needs_fn_pointer` like:
154+
fn needs_fn_pointer(callback: impl async Fn()) { todo!() }
155+
// Or with `AsyncFn`:
156+
fn needs_fn_pointer(callback: impl AsyncFn()) { todo!() }
157+
```
123158

124159
[RFC 3668]: https://rust-lang.github.io/rfcs/3668-async-closures.html

0 commit comments

Comments
 (0)