1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use Duration;
use Future;
use Pin;
use ;
/// The one runtime capability the portable core needs: timeouts and
/// backoff. Networking and spawning live in the transports.
///
/// Not `hyper::rt::Timer`: that one has `Sleep: Send + Sync` unconditionally,
/// `sleep()` returns `Pin<Box<dyn Sleep>>` (an allocation per sleep), and
/// `now()` is typed on `std::time::Instant`, which panics on
/// `wasm32-unknown-unknown`.
///
/// # Why [`Timer::Sleep`] is an associated type and not `impl Future`
///
/// An RPITIT — `fn sleep(&self, d: Duration) -> impl Future<Output = ()>` —
/// is more comfortable to write and costs two things:
///
/// - **A struct cannot hold a sleep.** It has no name to store, so a body
/// wrapper can only check elapsed time on each `poll_frame`, which
/// structurally cannot cut a response body that goes *completely* silent
/// after the head: nothing wakes the wrapper, so nothing ever looks at
/// the clock again. Measured with a counting waker and no executor
/// running, that shape registers **zero** wakes; a stored sleep
/// registers one. `hclient::body::Deadline` holds a
/// `Pin<Box<Tm::Sleep>>` for exactly this reason.
/// - **Generic code cannot spawn a background task.**
/// `hclient_rt::Spawn<F>` takes the future as a type parameter, so a
/// bound has to name it, and an anonymous future has no name. See
/// `hclient-native`'s `pool` module doc.
///
/// It also hides a third thing, the one most likely to be mistaken for a
/// bug: a backend whose native timer resolves to something other than
/// `()`, which `async { t.await; }` discards silently. Naming the type
/// makes that visible, and [`Discard`] is the adapter for it.
///
/// [`TcpConnect::Stream`](https://docs.rs/hclient-rt) is the same idea
/// applied to a socket; this is not a new shape in the seam.
/// Adapts a future that resolves to *something* into one that resolves to
/// `()`, for use as a [`Timer::Sleep`].
///
/// **This is not redundant, and it is not a mistake.** Two of this
/// project's clocks have a native timer whose `Output` is not `()`:
/// `async_io::Timer` resolves to the `std::time::Instant` at which it
/// fired, and `hclient-fetch`'s `SendJsFuture` resolves to
/// `Result<JsValue, JsValue>`. While [`Timer::sleep`] was an RPITIT both
/// were discarded invisibly inside an `async` block; with a named
/// associated type the discard has to be written down, and this is where
/// it is written down once instead of twice.
///
/// `F: Unpin` rather than a pin projection: every timer this wraps is
/// `Unpin` already, and this workspace forbids `unsafe`, so the safe
/// projection is the only one available and the bound is honest about it.
;