Go has a history of suggesting you provide a ctx context.Context
parameter to
all functions in an async context, such as web servers. This is useful for passing
deadlines and such down into the callstack, to allow leaf-functions to schedule shutdowns.
Rust already passes a context value automatically for you in all async functions,
this is already named Context
but it's heavily under-featured - only providing a 'wake-up' handle.
Making use of the nightly Provider API
,
we can modify this context to provide values on demand down the callstack. This avoids
using thread_locals, which requires std
, or passing through a TypeMap
with every
function call, which is unergonomic and requires alloc
.
A demonstration of an async deadline, using get_value
and provide_ref
```rust use contextrs::{getvalue, ProviderFutExt}; use std::time::{Instant, Duration};
// New type makes it easier to have unique keys in the context
struct Deadline(Instant);
struct Expired;
impl Deadline { // check if the deadline stored in the context has expired // returns OK if no deadline is stored. async fn expired() -> Result<(), Expired> { getvalue().await.map(|Deadline(deadline)| { // if there is a deadline set, check if it has expired if deadline < Instant::now() { Err(Expired) } else { Ok(()) } }).unwrapor(Ok(())) // or ignore it if no deadline is set } }
// some top level work - agnostic to the context async fn somework() -> Result<(), Expired> { loop { somenested_function().await? } }
// some deeply nested work, cares about the deadline context async fn somenestedfunction() -> Result<(), Expired> { // will acquire the deadline from the context itself Deadline::expired().await?;
// do some logic in here
Ok(())
}
async fn main() { // timeout in 2 seconds let deadline = Instant::now() + Duration::from_secs(2);
let res = some_work().provide_ref(&Deadline(deadline)).await;
assert_eq!(res, Err(Expired));
} ```
If you only need to access the value temporarily, and the value you want
is expensive to clone, you can use with_ref
instead of get_value
.
This will accept a closure with the ref provided for a short lived lifetime.