Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/t3hmrman/async-dropper
🗑 async-dropper is probably the least-worst ad-hoc AysncDrop implementation you've seen so far.
https://github.com/t3hmrman/async-dropper
async rust rust-lang utility-library
Last synced: about 1 month ago
JSON representation
🗑 async-dropper is probably the least-worst ad-hoc AysncDrop implementation you've seen so far.
- Host: GitHub
- URL: https://github.com/t3hmrman/async-dropper
- Owner: t3hmrman
- License: mit
- Created: 2023-07-26T07:28:37.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-01-31T08:24:57.000Z (11 months ago)
- Last Synced: 2024-04-17T08:10:21.877Z (8 months ago)
- Topics: async, rust, rust-lang, utility-library
- Language: Rust
- Homepage: https://crates.io/crates/async-dropper
- Size: 186 KB
- Stars: 30
- Watchers: 1
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-rust - t3hmrman/async-dropper - dropper](https://crates.io/crates/async-dropper)] - Implementation of `AsyncDrop` (Libraries / Asynchronous)
- awesome-rust - t3hmrman/async-dropper - dropper](https://crates.io/crates/async-dropper)] - Implementation of `AsyncDrop` (Libraries / Asynchronous)
- fucking-awesome-rust - t3hmrman/async-dropper - dropper](crates.io/crates/async-dropper)] - Implementation of `AsyncDrop` (Libraries / Asynchronous)
- fucking-awesome-rust - t3hmrman/async-dropper - dropper](crates.io/crates/async-dropper)] - Implementation of `AsyncDrop` (Libraries / Asynchronous)
README
🗑
async-dropper
`async-dropper` is probably the least-worst ad-hoc `AsyncDrop` implementation you've seen, and it works in two ways:
- `async_dropper::AsyncDropper` is stolen nearly verbatim from [this StackOverflow answer](https://stackoverflow.com/a/75584109) (thanks to [`paholg`](https://stackoverflow.com/users/2977291/paholg)!)
- `async_dropper::AsyncDrop` is a Trait and [custom derive macro][rust-derive-macro], which try to use `Default` and `PartialEq` to determine when to async drop, automatically while `Drop`ing.The code in this crate was most directly inspired by [this StackOverflow thread on Async Drop](https://stackoverflow.com/questions/71541765/rust-async-drop) and many other conversations:
- [Async Drop? - Reddit](https://www.reddit.com/r/rust/comments/vckd9h/async_drop/)
- [Asynchronous Destructors - rust-lang.org](https://internals.rust-lang.org/t/asynchronous-destructors/11127)
- [Async Drop roadmap](https://rust-lang.github.io/async-fundamentals-initiative/roadmap/async_drop.html) (once this is done, this crate will be deprecated!)[rust-derive-macro]: https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros
## Install
You **must** set features on this crate, as it works with both async runtimes, and can use *either* approach outlined above:
```console
# 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
```If you're editing `Cargo.toml` by hand, **choose one** of the following lines:
```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" ] }
```> **Warning**
> `async-dropper` does not allow using both `async-std` and `tokio` features at the same time (see [the FAQ below](#FAQ)).
> You *can*, however, use both the `simple` and `derive` features at the same time### Other features
Here are some other features you might be interested in using:
| Crate | Feature | Description |
|-----------------|----------|------------------------------------------------------------------------------|
| `async-dropper` | `anyhow` | Enable [`anyhow`][crate-anyhow]-related functionality (ex. `From` instances) |[crate-anyhow]: https://crates.io/crates/anyhow
## Quickstart
### `async_dropper::simple`
To use the "simple" version which uses a wrapper struct (`AsyncDropper`), see [`examples/simple_tokio.rs`](./examples/simple_tokio.rs):
```rust
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> {
{
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(())
}```
You can run the example and see the output:
```console
cargo run --example simple-tokio --features=tokio
```### Don't like the `Default` requirement?
It [was suggested](https://github.com/t3hmrman/async-dropper/issues/12#issuecomment-1913642636) that for certain large structs, it may not be convenient to implement `Default` in order to use the simple `AsyncDropper`.
As of version `0.2.6`, `async-dropper-simple` has a feature flag called `no-default-bound` which allows you to skip the `Default` bound on your `T` (in `AsyncDropper`), by using an inner `Option` (thanks @beckend!).
### `async_dropper::derive`
The derive macro is a novel (and possibly foolhardy) attempt to implement `AsyncDrop` without actually wrapping the existing struct.
`async_dropper::derive` uses `Default` and `PartialEq` to *check if the struct in question is equivalent to it's default*.
For this approach to work well your `T` should have cheap-to-create `Default`s, and comparing a default value to an existing value should meaningfully differ (and identify an object that is no longer in use). **Please think thoroughly about whether this model works for your use case**.
For an example, see [`examples/derive_tokio.rs`](./examples/derive_tokio.rs):
```rust
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> {
{
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(())
}
```You can run the example and see the output:
```console
cargo run --example derive-tokio --features=tokio
```## Supported environments
`async-dropper` works with the following async environments:
| Name | Supported? |
|-----------------------------------|------------|
| Async w/ [`tokio`][tokio] | ✅ |
| Async w/ [`async-std`][async-std] | ✅ |[tokio]: https://crates.io/crates/tokio
[async-std]: https://crates.io/crates/async-std## FAQ
### Why does `async-dropper` assume that I'm using *either* `async-std` or `tokio`?
Because you probably are. If this is a problem for you, it *can* be changed, please [file an issue][create-issue].
### Why do I have to choose between `simple` and `derive` features?
The `simple` strategy and `derive` strategy impose different requirements on the `T` on which they act.
To avoid requiring unnnecessary and possibly incompatible traits, you should choose *one* of the features (i.e. approaches) to go with.
If this "feature" presents an issue for you, it *can* be changed, please [file an issue][create-issue].
### What does `async_dropper::derive` cost?
There is waste introduced by `async_dropper::derive`, namely:
- One `Mutex`-protected `T::default()` instance of your type, that exists as long as the program runs
- One extra `T::default()` that is made of an individual `T` being dropped.As a result, every `drop` you perform on a T will perform two drops -- one on a `T::default()` and another on *your* `T`, which has been *converted* to a `T::default` (via `reset(&mut self)`).
## Development
To get started working on developing `async-dropper`, run the following [`just`][just] targets:
```console
just setup build
```To check that your changes are fine, you'll probably want to run:
```console
just test
```If you want to see the full list of targets available that you can run `just` without any arguments.
```console
just
```There are a few useful targets like `just build-watch` which will continuously build the project thanks to [`cargo watch`][cargo-watch].
[just]: https://github.com/casey/just
[cargo-watch]: https://crates.io/crates/cargo-watch## Releasing
From the top level of this repository:
```console
PUBLISH_CRATE=yes PKG= just release
```For example, to create the next semver `patch` release for `async-dropper-simple`:
```console
PUBLISH_CRATE=yes PKG=async-dropper-simple just release patch
```## Contributing
Contributions are welcome! If you find a bug or an impovement that should be included in `async-dropper`, [create an issue][crate-issue] or open a pull request.
[create-issue]: https://github.com/t3hmrman/async-dropper/issues