• Stars
    star
    142
  • Rank 258,495 (Top 6 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created over 4 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Executor Agnostic Runtime that can run your futures with your favourite Executor

Agnostik

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.

Features

  • 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.2"

Usage

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:

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

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

Examples

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!");
    })
    runtime.block_on(future)
    
    let future = runtime.spawn_blocking(|| {
        expensive_blocking_method();
    })
    runtime.block_on(future)
}

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.

Use

  • 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::*;

#[tokio::main]
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.

License

This project is licensed under the Apache2 or MIT License.