Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/conradludgate/context-rs
cursed context stuffing, like go's context.Context
https://github.com/conradludgate/context-rs
Last synced: 4 days ago
JSON representation
cursed context stuffing, like go's context.Context
- Host: GitHub
- URL: https://github.com/conradludgate/context-rs
- Owner: conradludgate
- Created: 2023-01-21T12:35:18.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-01-23T09:45:52.000Z (almost 2 years ago)
- Last Synced: 2024-10-13T15:11:23.861Z (about 1 month ago)
- Language: Rust
- Size: 41 KB
- Stars: 4
- Watchers: 2
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# context-rs
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`](https://doc.rust-lang.org/std/task/struct.Context.html)
but it's heavily under-featured - only providing a 'wake-up' handle.Making use of the nightly [`Provider API`](https://doc.rust-lang.org/std/any/trait.Provider.html),
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`.## Examples
A demonstration of an async deadline, using `get_value` and `provide_ref`
```rust
use context_rs::{get_value, ProviderFutExt};
use std::time::{Instant, Duration};// New type makes it easier to have unique keys in the context
#[derive(Clone)]
struct Deadline(Instant);#[derive(Debug, PartialEq)]
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> {
get_value().await.map(|Deadline(deadline)| {
// if there is a deadline set, check if it has expired
if deadline < Instant::now() {
Err(Expired)
} else {
Ok(())
}
}).unwrap_or(Ok(())) // or ignore it if no deadline is set
}
}// some top level work - agnostic to the context
async fn some_work() -> Result<(), Expired> {
loop {
some_nested_function().await?
}
}// some deeply nested work, cares about the deadline context
async fn some_nested_function() -> Result<(), Expired> {
// will acquire the deadline from the context itself
Deadline::expired().await?;// do some logic in here
Ok(())
}#[tokio::main]
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.