Skip to content

nik-rev/better-tokio-select

Repository files navigation

better_tokio_select

crates.io docs.rs license msrv github

This crate exports the macro tokio_select!, which, unlike tokio::select!, can be formatted by rustfmt!

better_tokio_select = "0.2"

Syntax

This macro has all the same capabilities as tokio::select!, but the syntax is slightly different.

tokio::select! takes a list of branches:

<pattern> = <async expression> (, if <precondition>)? => <handler>,

Example:

tokio::select! {
    Ok(res) = reader.read(&mut buf), if can_read => {
        writer.write_all(res.bytes)
    }
}

tokio_select! takes a match .. expression as an argument, which has a list of arms:

.. if let <pattern> = <async expression> (&& <precondition>)? => <handler>,

Example:

tokio_select!(match .. {
    .. if let Ok(res) = reader.read(&mut buf) && can_read => {
        writer.write_all(res.bytes)
    }
})

For rustfmt to work, the argument to a macro must be a valid Rust expression. Hence the odd-looking ..s. Rust compiler expects a pattern in that position, and we provide it with one.

Admittedly, the syntax is a little strange. But it’s also formattable by rustfmt. Trade-offs, people, trade-offs!

Examples

TCP Proxy with Cancellation and Guard

tokio::select!:

tokio::select! {
    res = reader.read(&mut buf), if can_read => {
        let n = res?;
        if n == 0 { return Ok(()); }
        writer.write_all(&buf[..n]).await?;
    }

    _ = shutdown.recv() => {
        return Ok(());
    }
}

tokio_select!:

tokio_select!(match .. {
    .. if let Ok(n) = reader.read(&mut buf) && can_read => {
        let n = res?;
        if n == 0 { return Ok(()); }
        writer.write_all(&buf[..n]).await?;
    }

    .. if let _ = shutdown.recv() => {
        return Ok(())
    }
})

Rate-Limited Message Processor

tokio::select! {
    biased;

    Some(Message::Data { id, payload }) = rx.recv() => {
        process(id, payload).await;
    }

    else => {
        println!("no messages pending");
        tokio::time::sleep(Duration::from_millis(50)).await;
    }
}

tokio_select!:

tokio_select!(biased, match .. {
    .. if let Some(Message::Data { id, payload }) = rx.recv() => {
        process(id, payload).await;
    }

    _ => {
        println!("no messages pending");
        tokio::time::sleep(Duration::from_millis(50)).await;
    }
})

More examples

More examples are available in the documentation of tokio_select!.

Global import

You can make the tokio_select! macro globally available in your crate, without needing to import it, with:

#[macro_use(tokio_select)]
extern crate better_tokio_select;

About

tokio::select! that can be formatted by rustfmt

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

 
 
 

Languages