# unsync
[](https://github.com/udoprog/unsync)
[](https://crates.io/crates/unsync)
[](https://docs.rs/unsync)
[](https://github.com/udoprog/unsync/actions?query=branch%3Amain)
Unsynchronized synchronization primitives for async Rust.
This crate provides a fairly simple set of synchronization primitives which
are explicitly `!Send` and `!Sync`. This makes them useful for use in
singlethreaded systems like [yew].
You can think of this as a modern replacement to the now-deprecated
[futures::unsync] module.
## Why do you want `!Send` / `!Sync` synchronization primitives?
Having unsynchronized sync primitives might seem *weird* since they are
largely used for inter-task communication across threads.
The need for such primitives increase as we are seeing more singlethreaded
systems like [yew] mature and are receiving richer support for async
programming. In order to make them as efficient as possible it's useful that
they are written with unsynchronized systems and constraints in mind so that
they don't have to make use of atomics and locks.
The overhead of synchronization in real systems should be minor because of
the role channels play in typical applications and they are optimized for
uncontended use. But unsynchronized code still has the ability to optimize
better for both performance and size.
In one of my applications replacing the use of `tokio::sync::oneshot` with
`unsync::oneshot` reduced the size of the resulting binary by 30kb (10kb
when optimized with `wasm-opt`). Synthetic benchmarks in this project hints
at the unsync channels being about twice as fast for optimized builds when
used inside of a [LocalSet].
I haven't dug too deep into the specifics of why this is, but as long as
this is the case I'd like to have access to drop in replacements allowing
someone to tap into these benefits.
[yew]:
[LocalSet]: https://docs.rs/tokio/latest/tokio/task/struct.LocalSet.html
## Usage
Add the following to your `Cargo.toml`:
```toml
unsync = "0.1.1"
```
## Examples
```rust
use unsync::spsc::{channel, Sender, Receiver};
use std::error::Error;
use tokio::task;
async fn receiver(mut rx: Receiver) -> Vec {
let mut out = Vec::new();
while let Some(m) = rx.recv().await {
out.push(m);
}
out
}
async fn sender(mut tx: Sender) -> Result<(), Box> {
for n in 0..1000 {
tx.send(n).await?;
}
Ok(())
}
async fn run() -> Result<(), Box> {
let (tx, rx) = channel(4);
let _ = task::spawn_local(sender(tx));
let out = task::spawn_local(receiver(rx)).await?;
let expected = (0..1000).collect::>();
assert_eq!(out, expected);
Ok(())
}
```
[futures::unsync]: