pub trait Timer {
type Instant: Copy + PartialOrd;
type Sleep: Future<Output = ()>;
// Required methods
fn sleep(&self, d: Duration) -> Self::Sleep;
fn now(&self) -> Self::Instant;
fn elapsed_since(&self, earlier: Self::Instant) -> Duration;
}Expand description
Timer is defined once, in hclient-core: the portable core needs it
for timeouts and backoff. This is just a re-export.
Discard comes with it: Timer::Sleep is a named associated type, and
a runtime whose native timer resolves to something other than () — as
async_io::Timer does — needs the adapter to satisfy it. Re-exported
here so a runtime crate does not have to depend on hclient-core
directly just to name one wrapper.
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::Deadlineholds aPin<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. Seehclient-native’spoolmodule 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 is the same idea
applied to a socket; this is not a new shape in the seam.
Required Associated Types§
type Instant: Copy + PartialOrd
Sourcetype Sleep: Future<Output = ()>
type Sleep: Future<Output = ()>
The future Timer::sleep returns, named.
Sendness is deliberately not required here, exactly as it is not
required of Timer itself: a caller that needs a Send sleep gets
it because its own clock’s Sleep happens to be Send, inferred
rather than declared.
Required Methods§
fn sleep(&self, d: Duration) -> Self::Sleep
fn now(&self) -> Self::Instant
fn elapsed_since(&self, earlier: Self::Instant) -> Duration
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".