# Agnostik [![Crates.io](https://img.shields.io/crates/v/agnostik)](https://crates.io/crates/agnostik) [![doc](https://img.shields.io/badge/rustdoc-agnostik-blue.svg)](https://docs.rs/agnostik) [![CI](https://github.com/bastion-rs/bastion/workflows/CI/badge.svg)](https://github.com/bastion-rs/agnostik/actions) 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](https://github.com/bastion-rs/agnostik/tree/master/tests) for simple examples. If you have [cargo-edit](https://github.com/killercup/cargo-edit) installed, you can just execute this: ``` cargo add agnostik ``` otherwise, add this to your Cargo.toml file ``` agnostik = "0.2.0" ``` ## 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: - `runtime_bastion` to use the [Bastion Executor](https://crates.io/crates/bastion-executor) - `runtime_tokio` to use the [Tokio](https://tokio.rs) runtime - `runtime_asyncstd` to use the [AsyncStd](https://async.rs) runtime - `runtime_smol` to use the new and awesome [smol](https://docs.rs/smol) runtime E.g. to use the Tokio runtime, add the following line to your Cargo.toml ``` agnostik = { version = "0.2.0", 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. ```rust 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 ```rust 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: ```rust 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: ```rust 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](https://discord.gg/DqRqtRT). ### License This project is licensed under the Apache2 or MIT License.