#future #async #async-await #await #macro #api-bindings

macro agnostik-attributes

Executor agnostik attributes

1 stable release

1.2.0 Nov 27, 2020
1.1.1 Nov 23, 2020

#80 in #await

25 downloads per month
Used in agnostik


91 lines


Crates.io doc CI

Agnostik is a layer between your application and the executor for your async stuff. It lets you switch the executors smooth and easy without having to change your applications code.


  • Run futures and wait for them to finish
  • Spawn Futures using the underlying executor
  • Spawn blocking tasks using special threads that are able to execute blocking code

Get started

Check the tests for simple examples.

If you have cargo-edit installed, you can just execute this:

cargo add agnostik

otherwise, add this to your Cargo.toml file

agnostik = "0.1.0"


Switching executors

Note: Libraries should not enable any runtime feature. You can choose the executor, by using cargo features. There can only be one enabled runtime. Valid features are:

  • runtime_bastion to use the Bastion Executor
  • runtime_tokio to use the Tokio runtime
  • runtime_asyncstd to use the AsyncStd runtime
  • runtime_smol to use the new and awesome smol runtime

E.g. to use the Tokio runtime, add the following line to your Cargo.toml

agnostik = { version = "0.1.0", features = ["runtime_tokio"]}


Agnostiks API is very easy and only has a few methods to use. Here's an example with the bastion-executor.

use agnostik::prelude::*;

fn main() {
    let runtime = Agnostik::bastion();

    let future = runtime.spawn(async {
        println!("Hello from bastions executor!");
    let future = runtime.spawn_blocking(|| {

There's also a global executor instance that can be used to spawn futures without creating and storing your own executor. If you specify multiple runtimes, the global executor will be the following:

  • smol if tokio and smol are enabled
  • bastion if async_std, smol and / or tokio is enabled
fn main() {
    let future = agnostik::spawn(async { println!("Hello from bastion executor!"); 1 });
    let result = agnostik::block_on(future);
    assert_eq!(result, 1);

If you want to use another executor, you just have to replace the Agnostik::bastion() method call, with the method that corresponds to your executor.


  • Agnostik::bastion() for bastion
  • Agnostik::async_std() for async std
  • Agnostik::tokio() for tokio. Warning: See "How to use tokio runtime"
  • Agnostik::tokio_with_runtime(runtime) if you want to use your own tokio::runtime::Runtime object. Warning: See "How to use tokio runtime"
  • Agnostik::no_std() (coming soon) to create an exeutor that works in a nostd environment

How to use tokio runtime

It's not supported to use the tokio::main macro together with agnostik, because Agnostik requires a Runtime object, which is created by calling Runtime::new(). If your are using the tokio::main macro, there will be a panic, because you can't create a runtime inside a runtime.

Here's how to fix it:

use agnostik::prelude::*;

async fn main() {
    let runtime = Agnostik::tokio();
    let result = runtime.spawn(async_task()).await;

    println!("The result is {}", result)

This would fail with a panic. How to do it correctly:

use agnostik::prelude::*;
use tokio::runtime::Runtime;

fn main() {
    // see tokio docs for more methods to create a runtime
    let runtime = Runtime::new().expect("Failed to create a runtime"); // 1
    let runtime = Agnostik::tokio_with_runtime(runtime); // 2

    let result = runtime.spawn(async_task());
    let result = runtime.block_on(result);

    println!("The result is {}", result)

You can replace 1 and 2 with Agnostik::tokio(), because this method call will create a Runtime object using Runtime::new().

Getting Help

Please head to our Discord.


This project is licensed under the Apache2 or MIT License.


~33K SLoC