https://github.com/tlowerison/scoped-futures
Rust utility crate for imposing upper bounds on Future lifetimes.
https://github.com/tlowerison/scoped-futures
rust rust-traits
Last synced: 2 months ago
JSON representation
Rust utility crate for imposing upper bounds on Future lifetimes.
- Host: GitHub
- URL: https://github.com/tlowerison/scoped-futures
- Owner: tlowerison
- License: apache-2.0
- Created: 2022-10-11T23:18:54.000Z (over 3 years ago)
- Default Branch: main
- Last Pushed: 2024-10-07T21:49:55.000Z (over 1 year ago)
- Last Synced: 2025-12-14T03:24:43.563Z (6 months ago)
- Topics: rust, rust-traits
- Language: Rust
- Homepage: https://crates.io/crates/scoped-futures
- Size: 36.1 KB
- Stars: 7
- Watchers: 0
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE-APACHE
Awesome Lists containing this project
README
# scoped-futures
A utility crate for imposing upper bounds on `Future` lifetimes. This is especially useful for callbacks that use higher-ranked lifetimes in their return type,
where it can prevent `'static` bounds from being placed on a returned `Future`.
This crate is effectively a port of Sabrina Jewson's [better alternative to lifetime GATs](https://sabrinajewson.org/blog/the-better-alternative-to-lifetime-gats)
for Futures.
## Example
```rust
use core::pin::Pin;
use scoped_futures::{ScopedBoxFuture, ScopedFutureExt};
pub struct Db {
count: u8,
}
impl Db {
async fn transaction<'a, F, T, E>(&mut self, callback: F) -> Result
where
// ScopedBoxFuture imposes a lifetime bound on 'b which prevents the hrtb below needing
// to be satisfied for all lifetimes (including 'static) and instead only lifetimes
// which live at most as long as 'a
F: for<'b /* where 'a: 'b */> FnOnce(&'b mut Self) -> ScopedBoxFuture<'a, 'b, Result> + Send + 'a,
T: 'a,
E: 'a,
{
callback(self).await
}
}`
pub async fn test_transaction<'a, 'b>(
db: &mut Db,
ok: &'a str,
err: &'b str,
is_ok: bool,
) -> Result<&'a str, &'b str> {
// note the lack of `move` or any cloning in front of the closure
db.transaction(|db| async move {
db.count += 1;
if is_ok {
Ok(ok)
} else {
Err(err)
}
}.scope_boxed()).await?;
// note that `async` can be used instead of `async move` since the callback param is unused
db.transaction(|_| async {
if is_ok {
Ok(ok)
} else {
Err(err)
}
}.scope_boxed()).await
}
#[test]
fn test_transaction_works() {
futures::executor::block_on(async {
let mut db = Db { count: 0 };
let ok = String::from("ok");
let err = String::from("err");
let result = test_transaction(&mut db, &ok, &err, true).await;
assert_eq!(ok, result.unwrap());
assert_eq!(1, db.count);
})
}
```