#async #macro-derive #async-trait #tokio #ad-hoc #async-std #default

async-dropper

作为Derive宏的AsyncDrop最差实现的解决方案

13个不稳定版本 (3个重大更改)

0.3.1 2023年10月26日
0.3.0 2023年10月20日
0.2.5 2023年10月18日
0.2.3 2023年8月9日
0.0.1 2023年7月29日

#136异步

Download history 502/week @ 2024-04-03 517/week @ 2024-04-10 471/week @ 2024-04-17 314/week @ 2024-04-24 365/week @ 2024-05-01 364/week @ 2024-05-08 603/week @ 2024-05-15 369/week @ 2024-05-22 657/week @ 2024-05-29 491/week @ 2024-06-05 761/week @ 2024-06-12 666/week @ 2024-06-19 971/week @ 2024-06-26 964/week @ 2024-07-03 1030/week @ 2024-07-10 935/week @ 2024-07-17

每月下载量4,103次
4 个crate中(3个直接使用) 使用

MIT 许可证

46KB
574

🗑 async-dropper

async-dropper 可能是你见过的最差的Ad-hoc AsyncDrop 实现,并且它以两种方式工作

  • async_dropper::AsyncDropper 几乎是从 这个StackOverflow回答 中直接复制(感谢 paholg!)
  • async_dropper::AsyncDrop 是一个Trait和 自定义derive宏,它尝试使用 DefaultPartialEq 来确定何时异步丢弃,在 Drop 时自动进行。

此crate中的代码最直接受到 这个StackOverflow关于Async Drop的线程 和许多其他对话的启发

安装

您必须为此crate设置功能,因为它与两种异步运行时都兼容,并可以使用上面概述的 任一 方法

# if using tokio, choose one of the two lines below
cargo add async-dropper --features tokio,derive     # use tokio, with the derive approach
cargo add async-dropper --features tokio,simple     # use tokio, with the simple approach

# if using async-std, chose one of the two lines below
cargo add async-dropper --features async-std,derive # use async-std, with the derive approach
cargo add async-dropper --features async-std,simple # use async-std, with the simple approach

如果您手动编辑 Cargo.toml,请 选择以下行之一

[dependencies]
#async-dropper = { version = "0.3", features = [ "tokio", "derive" ] }
#async-dropper = { version = "0.3", features = [ "tokio", "simple" ] }

#async-dropper = { version = "0.3", features = [ "async-std", "derive" ] }
#async-dropper = { version = "0.3", features = [ "async-std", "simple" ] }

警告 async-dropper 不允许同时使用 async-stdtokio 功能(请参阅下面的 常见问题解答)。但是,您可以使用 simplederive 功能同时使用

快速入门

async_dropper::simple

要使用使用包装结构体(AsyncDropper<<T>>)的“简单”版本,请参阅examples/simple_tokio.rs

use std::{
    result::Result,
    time::Duration,
};

use async_dropper_simple::{AsyncDrop, AsyncDropper};
use async_trait::async_trait;

// NOTE: this example is rooted in crates/async-dropper

/// This object will be async-dropped (which must be wrapped in AsyncDropper)
#[derive(Default)]
struct AsyncThing(String);

#[async_trait]
impl AsyncDrop for AsyncThing {
    async fn async_drop(&mut self) {
        eprintln!("async dropping [{}]!", self.0);
        tokio::time::sleep(Duration::from_secs(2)).await;
        eprintln!("dropped [{}]!", self.0);
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    {
        let _example_obj = AsyncDropper::new(AsyncThing(String::from("test")));
        eprintln!("here comes the (async) drop");
        // drop will be triggered here, and it will take *however long it takes*
        // you could also call `drop(_example_obj)`
    }

    Ok(())
}

您可以运行示例并查看输出

cargo run --example simple-tokio --features=tokio

async_dropper::派生

派生宏是一个尝试实现AsyncDrop(但不实际包装现有结构体)的创新(可能也是鲁莽)的尝试。

async_dropper::derive使用DefaultPartialEq检查问题结构体是否与其默认值等效

为了使这种方法有效,您的T应该具有低成本创建的Default,并且将默认值与现有值进行比较应该有意义的差异(并识别不再使用的对象)。请仔细考虑此模型是否适用于您的用例

例如,请参阅examples/derive_tokio.rs

use std::{
    result::Result,
    time::Duration,
};

use async_dropper::derive::AsyncDrop;
use async_trait::async_trait;

/// This object will be async-dropped
///
/// Objects that are dropped *must* implement [Default] and [PartialEq]
/// (so make members optional, hide them behind Rc/Arc as necessary)
#[derive(Debug, Default, PartialEq, Eq, AsyncDrop)]
struct AsyncThing(String);

/// Implementation of [AsyncDrop] that specifies the actual behavior
#[async_trait]
impl AsyncDrop for AsyncThing {
    // simulated work during async_drop
    async fn async_drop(&mut self) -> Result<(), AsyncDropError> {
        eprintln!("async dropping [{}]!", self.0);
        tokio::time::sleep(Duration::from_secs(2)).await;
        eprintln!("dropped [{}]!", self.0);
        Ok(())
    }

    fn drop_timeout(&self) -> Duration {
        Duration::from_secs(5) // extended from default 3 seconds, as an example
    }

    // NOTE: the method below is automatically derived for you, but you can override it
    // make sure that the object is equal to T::default() by the end, otherwise it will panic!
    // fn reset(&mut self) {
    //     self.0 = String::default();
    // }

    // NOTE: below was not implemented since we want the default of DropFailAction::Continue
    // fn drop_fail_action(&self) -> DropFailAction;
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    {
        let _example_obj = AsyncThing(String::from("test"));
        eprintln!("here comes the (async) drop");
        // drop will be triggered here
        // you could also call `drop(_example_obj)`
    }

    Ok(())
}

您可以运行示例并查看输出

cargo run --example derive-tokio --features=tokio

支持的环境

async-dropper与以下异步环境兼容

名称 是否支持?
tokio的异步
async-std的异步

常见问题解答(FAQ)

为什么async-dropper假设我正在使用either async-stdtokio

因为您很可能正在使用。如果这对您来说是个问题,它可以更改,请提交问题

为什么我必须在simplederive功能之间选择?

simple策略和derive策略对它们所作用的T有不同的要求。

为了避免要求不必要的和可能不兼容的特性,您应该选择一个功能(即方法)来使用。

如果这个“功能”给您带来问题,它可以更改,请提交问题

async_dropper::derive的成本是什么?

async_dropper::derive引入了浪费,即

  • 一个受Mutex保护的T::default()实例,该实例在程序运行期间存在
  • 一个额外的T::default(),它由一个被丢弃的T组成。

因此,您对T执行的每次drop都会执行两次丢弃——一次是对T::default()的丢弃,另一次是对您的 T的丢弃,该T已被转换为 T::default(通过reset(&mut self))。

开发

要开始开发 async-dropper,请运行以下 just 目标

just setup build

为了检查您的更改是否正确,您可能需要运行

just test

如果您想查看可以运行而不带任何参数的完整目标列表。

just

有一些有用的目标,如 just build-watch,它将不断构建项目,归功于 cargo watch

发布

从该存储库的顶级目录

PUBLISH_CRATE=yes PKG=<crate name> just release <version>

例如,要为 patch 创建下一个 async-dropper-simple 的版本

PUBLISH_CRATE=yes PKG=async-dropper-simple just release patch

贡献

欢迎贡献!如果您发现 async-dropper 中应包含的错误或改进,请 [创建问题][crate-issue] 或发起拉取请求。

依赖项

~1–12MB
~137K SLoC