# async-ops
[![CI](https://github.com/saserr/async-ops/actions/workflows/CI.yml/badge.svg)](https://github.com/saserr/async-ops/actions/workflows/CI.yml)
[![codecov](https://codecov.io/gh/saserr/async-ops/branch/main/graph/badge.svg?token=2K2DABXJMS)](https://codecov.io/gh/saserr/async-ops)
[![License](https://img.shields.io/badge/license-Apache--2.0_OR_MIT-blue.svg)](
https://github.com/saserr/async-ops)
This crate provides a way to use
[some `std::ops` traits](#supported-stdops-traits) with `Futures`. To be able to
use a `std::ops` trait with a `Future`, first you need to wrap the `Future`
with `Async` using `async_ops::on`. Then, as long the `Future::Output` type
implements a supported `std::ops` trait, then the same `std::ops` trait will be
implemented by the `Async` instance.
Another option is to wrap a `Future` with `Async` using `async_ops::assignable!`
to enable usage of the `Assign` variants of `std::ops` traits on the `Future`.
## Example
When writing `async` code it is common to do operations that are supported
through `std::ops`. For example, adding to numbers might look like this:
```rust
use futures_executor::block_on;
// Immediately returning a number is done for simplicity and production code
// wouldn't just immediately return a value.
let a = async { 40 };
let b = async { 2 };
let result = async { a.await + b.await };
assert_eq!(42, block_on(result));
```
Actually, the above code is not optimally implemented because `a` and `b` are
`await`-ed sequentially, instead of concurrently. The appropriate solution is to
use `join!` to be able to concurrently `await` both values like this:
```rust
use futures_executor::block_on;
use futures_util::join;
let a = async { 40 };
let b = async { 2 };
let result = async {
let (a, b) = join!(a, b);
a + b
};
assert_eq!(42, block_on(result));
```
Or, just use `async_ops::on` to do the same thing like the above example in one
line:
```rust
use futures_executor::block_on;
let a = async { 40 };
let b = async { 2 };
let result = async { (async_ops::on(a) + b).await };
assert_eq!(42, block_on(result));
```
Note that the `async_ops::on` example will also concurrently `await` both
values.
## Supported `std::ops` traits
Add
`Async` implements `Add where Rhs: Future` when the wrapped
`Future::Output` type implements `Add`. The resulting type of the
addition is
`Async>::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 40 };
let b = async { 2 };
let result = async { (async_ops::on(a) + b).await };
assert_eq!(42, block_on(result));
```
AddAssign
`Async` implements `AddAssign where Rhs: Future` when the wrapped `Future`
type implements `Assignable< as Add>::Output>`, which in turn
requires the `Future::Output` type to implement `Add`.
```rust
use futures_executor::block_on;
let a = async { 40 };
let b = async { 2 };
let result = async {
async_ops::assignable!(a);
a += b;
a.await
};
assert_eq!(42, block_on(result));
```
BitAnd
`Async` implements `BitAnd where Rhs: Future` when the wrapped
`Future::Output` type implements `BitAnd`. The resulting type of
the bitwise and is
`Async>::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 110 };
let b = async { 59 };
let result = async { (async_ops::on(a) & b).await };
assert_eq!(42, block_on(result));
```
BitAndAssign
`Async` implements `BitAndAssign where Rhs: Future` when the wrapped
`Future` type implements `Assignable< as BitAnd>::Output>`,
which in turn requires the `Future::Output` type to implement
`BitAnd`.
```rust
use futures_executor::block_on;
let a = async { 110 };
let b = async { 59 };
let result = async {
async_ops::assignable!(a);
a &= b;
a.await
};
assert_eq!(42, block_on(result));
```
BitOr
`Async` implements `BitOr where Rhs: Future` when the wrapped
`Future::Output` type implements `BitOr`. The resulting type of the
bitwise or is
`Async>::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 40 };
let b = async { 10 };
let result = async { (async_ops::on(a) | b).await };
assert_eq!(42, block_on(result));
```
BitOrAssign
`Async` implements `BitOrAssign where Rhs: Future` when the wrapped
`Future` type implements `Assignable< as BitOr>::Output>`,
which in turn requires the `Future::Output` type to implement
`BitOr`.
```rust
use futures_executor::block_on;
let a = async { 40 };
let b = async { 10 };
let result = async {
async_ops::assignable!(a);
a |= b;
a.await
};
assert_eq!(42, block_on(result));
```
BitXor
`Async` implements `BitXor where Rhs: Future` when the wrapped
`Future::Output` type implements `BitXor`. The resulting type of
the bitwise xor is
`Async>::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 38 };
let b = async { 12 };
let result = async { (async_ops::on(a) ^ b).await };
assert_eq!(42, block_on(result));
```
BitXorAssign
`Async` implements `BitXorAssign where Rhs: Future` when the wrapped
`Future` type implements `Assignable< as BitXor>::Output>`,
which in turn requires the `Future::Output` type to implement
`BitXor`.
```rust
use futures_executor::block_on;
let a = async { 38 };
let b = async { 12 };
let result = async {
async_ops::assignable!(a);
a ^= b;
a.await
};
assert_eq!(42, block_on(result));
```
Div
`Async` implements `Div where Rhs: Future` when the wrapped
`Future::Output` type implements `Div`. The resulting type of the
division is
`Async>::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 84 };
let b = async { 2 };
let result = async { (async_ops::on(a) / b).await };
assert_eq!(42, block_on(result));
```
DivAssign
`Async` implements `DivAssign where Rhs: Future` when the wrapped `Future`
type implements `Assignable< as Div>::Output>`, which in turn
requires the `Future::Output` type to implement `Div`.
```rust
use futures_executor::block_on;
let a = async { 84 };
let b = async { 2 };
let result = async {
async_ops::assignable!(a);
a /= b;
a.await
};
assert_eq!(42, block_on(result));
```
Mul
`Async` implements `Mul where Rhs: Future` when the wrapped
`Future::Output` type implements `Mul`. The resulting type of the
multiplication is
`Async>::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 21 };
let b = async { 2 };
let result = async { (async_ops::on(a) * b).await };
assert_eq!(42, block_on(result));
```
MulAssign
`Async` implements `MulAssign where Rhs: Future` when the wrapped `Future`
type implements `Assignable< as Mul>::Output>`, which in turn
requires the `Future::Output` type to implement `Mul`.
```rust
use futures_executor::block_on;
let a = async { 21 };
let b = async { 2 };
let result = async {
async_ops::assignable!(a);
a *= b;
a.await
};
assert_eq!(42, block_on(result));
```
Neg
`Async` implements `Neg` when the wrapped `Future::Output` type implements
`Neg`. The resulting type of the negation is
`Async::Output>>`.
```rust
use futures_executor::block_on;
let a = async { -42 };
let result = async { (-async_ops::on(a)).await };
assert_eq!(42, block_on(result));
```
Not
`Async` implements `Not` when the wrapped `Future::Output` type implements
`Not`. The resulting type of the logical negation is
`Async::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 213_u8 };
let result = async { (!async_ops::on(a)).await };
assert_eq!(42, block_on(result));
```
Rem
`Async` implements `Rem where Rhs: Future` when the wrapped
`Future::Output` type implements `Rem`. The resulting type of the
reminder operation is
`Async>::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 42 };
let b = async { 5 };
let result = async { (async_ops::on(a) % b).await };
assert_eq!(2, block_on(result));
```
RemAssign
`Async` implements `RemAssign where Rhs: Future` when the wrapped `Future`
type implements `Assignable< as Rem>::Output>`, which in turn
requires the `Future::Output` type to implement `Rem`.
```rust
use futures_executor::block_on;
let a = async { 42 };
let b = async { 5 };
let result = async {
async_ops::assignable!(a);
a %= b;
a.await
};
assert_eq!(2, block_on(result));
```
Shl
`Async` implements `Shl where Rhs: Future` when the wrapped
`Future::Output` type implements `Shl`. The resulting type of the
left shift is
`Async>::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 21 };
let b = async { 1 };
let result = async { (async_ops::on(a) << b).await };
assert_eq!(42, block_on(result));
```
ShlAssign
`Async` implements `ShlAssign where Rhs: Future` when the wrapped `Future`
type implements `Assignable< as Shl>::Output>`, which in turn
requires the `Future::Output` type to implement `Shl`.
```rust
use futures_executor::block_on;
let a = async { 21 };
let b = async { 1 };
let result = async {
async_ops::assignable!(a);
a <<= b;
a.await
};
assert_eq!(42, block_on(result));
```
Shr
`Async` implements `Shr where Rhs: Future` when the wrapped
`Future::Output` type implements `Shr`. The resulting type of the
right shift is
`Async>::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 168 };
let b = async { 2 };
let result = async { (async_ops::on(a) >> b).await };
assert_eq!(42, block_on(result));
```
ShrAssign
`Async` implements `ShrAssign where Rhs: Future` when the wrapped `Future`
type implements `Assignable< as Shr>::Output>`, which in turn
requires the `Future::Output` type to implement `Shr`.
```rust
use futures_executor::block_on;
let a = async { 168 };
let b = async { 2 };
let result = async {
async_ops::assignable!(a);
a >>= b;
a.await
};
assert_eq!(42, block_on(result));
```
Sub
`Async` implements `Sub where Rhs: Future` when the wrapped
`Future::Output` type implements `Sub`. The resulting type of the
subtraction is
`Async>::Output>>`.
```rust
use futures_executor::block_on;
let a = async { 44 };
let b = async { 2 };
let result = async { (async_ops::on(a) - b).await };
assert_eq!(42, block_on(result));
```
SubAssign
`Async` implements `SubAssign where Rhs: Future` when the wrapped `Future`
type implements `Assignable< as Sub>::Output>`, which in turn
requires the `Future::Output` type to implement `Sub`.
```rust
use futures_executor::block_on;
let a = async { 44 };
let b = async { 2 };
let result = async {
async_ops::assignable!(a);
a -= b;
a.await
};
assert_eq!(42, block_on(result));
```
## License
Licensed under either of
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE)
or )
* MIT license ([LICENSE-MIT](LICENSE-MIT) or
)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the
[Apache License Version 2.0](LICENSE-APACHE), shall be dual licensed as above,
without any additional terms or conditions.