# Worst Executor
[![Build status](https://github.com/elichai/worst-executor/actions/workflows/ci.yaml/badge.svg)](https://github.com/elichai/worst-executor/actions)
[![Latest version](https://img.shields.io/crates/v/worst-executor.svg)](https://crates.io/crates/worst-executor)
![License](https://img.shields.io/crates/l/worst-executor.svg)
[![dependency status](https://deps.rs/repo/github/elichai/worst-executor/status.svg)](https://deps.rs/repo/github/elichai/worst-executor)
The simplest async executor possible.
This crate provides a single function, `block_on`, which takes a future and
blocks the current thread until the future is resolved.
The way it works is by "spin-looping" over the `poll` method until it is ready.
The nice thing about this is that it optimizes very well,
for example `worst_executor::block_on(async { 42 })` compiles to a single `mov` instruction.
The bad thing about this is that it does not actually do any scheduling, meaning that if you
wait on a future that never resolves, your program will hang. which is why you should probably not use this.
Note that because of its simplicity, the library only uses `core` and does not require `std` or `alloc`
nor does it have any dependencies, and is literally 16 lines of code.
* [Documentation](https://docs.rs/worst-executor)
## Usage
Add this to your `Cargo.toml`:
```toml
[dependencies]
worst-executor = "0.1"
```
Then in your main.rs:
```rust
fn main() {
worst_executor::block_on(async {
// Your async code goes here.
});
}
```
### Use cases
Say you're using a library which returns a future, but you know it does no I/O,
and you want to use it in a synchronous context without bringing in a full async runtime like tokio/smol/async-std
You can use `worst_executor::block_on` to block the current thread until the future is resolved.
Another scenario can be that you want to run an "event loop" in a single thread using `async` rust.
so you can use the `core::future::join` macro together with the `futures::select` macro
to handle the control flow of your program, while always running on a single thread and never yielding.
### Single threaded tcp server
```rust
use async_net::{TcpListener, TcpStream};
use futures::{stream::FuturesUnordered, AsyncReadExt, AsyncWriteExt, StreamExt};
use worst_executor::block_on;
block_on(async {
let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
let mut connection_handlers = FuturesUnordered::new();
// This stream is infinite so it's OK to call fuse.
let mut listener = listener.incoming().fuse();
loop {
futures::select! {
new_connection = listener.select_next_some() => connection_handlers.push(handle_connection(new_connection?)),
socket = connection_handlers.select_next_some() =>
if let Some(socket) = socket {
connection_handlers.push(handle_connection(socket));
},
}
}
})
async fn handle_connection(mut stream: TcpStream) -> Option {
let mut buf = [0u8; 1024];
let n = match stream.read(&mut buf).await {
Ok(n) if n == 0 => return Some(stream),
Ok(n) => n,
Err(e) => {
eprintln!("failed to read from the socket {e:?}");
return None;
}
};
// Write the data back
stream.write_all(&buf[0..n]).await
.map_err(|e| eprintln!("failed to write to the socket {e:?}"))
.map(|()| stream)
.ok()
}
```