#context #async-context #deadlines #call-stack #down #values #demand

nightly no-std context-rs

在异步调用栈中传递值,支持无 std 和无分配

2 个不稳定版本

0.2.2 2023 年 1 月 23 日
0.2.1 2023 年 1 月 23 日
0.2.0 2023 年 1 月 22 日
0.1.0 2023 年 1 月 21 日

1584Rust 模式

MIT 许可证

25KB
395

context-rs

Go 一直建议你在异步上下文中的所有函数,如 Web 服务器,提供一个 ctx context.Context 参数。这对于将截止日期等信息传递到调用栈中很有用,以便允许叶函数安排关闭。

Rust 已经为所有异步函数自动传递了一个上下文值,这已经命名为 Context,但它功能强大——只提供一个 '唤醒' 处理程序。

通过使用 nightly Provider API,我们可以修改这个上下文,以在调用栈中按需提供值。这避免了使用 thread_locals,这需要 std,或者在每个函数调用中传递一个 TypeMap,这既不直观又需要 alloc

示例

使用 get_valueprovide_ref 展示异步截止日期的示例

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));
}

如果你只需要临时访问值,并且你想要的值很昂贵,你可以使用 with_ref 而不是 get_value。这将接受一个闭包,该闭包接受提供的引用,具有短暂的生存期。

依赖关系

~0–1.2MB
~20K SLoC