Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support nio async runtime #289

Merged
merged 2 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ members = [
exclude = [
"benches",
"benches_rt/glommio",
"benches_rt/nio",
"benches_rt/smol",
"benches_rt/tokio",
"benches_rt/vs_actix-web",
]

[workspace.dependencies]
byte_reader = { version = "3.1", features = ["text"] }
serde = { version = "1.0", features = ["derive"] }
byte_reader = { version = "3.1", features = ["text"] }
serde = { version = "1.0", features = ["derive"] }
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<br>

- *macro-less and type-safe* APIs for intuitive and declarative code
- *multiple runtimes* are supported:`tokio`, `async-std`, `smol`, `glommio`, `worker` (Cloudflare Workers)
- *multiple runtimes* are supported:`tokio`, `async-std`, `smol`, `nio`, `glommio`, `worker` (Cloudflare Workers)

<div align="right">
<a href="https://github.com/ohkami-rs/ohkami/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/crates/l/ohkami.svg" /></a>
Expand Down Expand Up @@ -78,11 +78,12 @@ Hello, your_name!

## Feature flags

### `"rt_tokio"`, `"rt_async-std"`, `"rt_smol"`, `"rt_glommio"`:native async runtime
### `"rt_tokio"`, `"rt_async-std"`, `"rt_smol"`, `"rt_nio"`, `"rt_glommio"`:native async runtime

- [tokio](https://github.com/tokio-rs/tokio)
- [async-std](https://github.com/async-rs/async-std)
- [smol](https://github.com/smol-rs/smol)
- [nio](https://github.com/nurmohammed840/nio)
- [glommio](https://github.com/DataDog/glommio)

### `"rt_worker"`:Cloudflare Workers
Expand Down
9 changes: 4 additions & 5 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ tasks:
- task: test:examples
- task: test:doc
- task: test:no_rt
- for: [tokio, async-std, smol, glommio, worker]
- for: [tokio, async-std, smol, nio, glommio, worker]
task: test:rt
vars: { rt: '{{.ITEM}}' }

check:
deps:
- task: check:no_rt
- for: [tokio, async-std, smol, glommio]
- for: [tokio, async-std, smol, nio, glommio]
task: check:native_rt
vars: { native_rt: '{{.ITEM}}' }
- task: check:rt_worker
Expand All @@ -32,10 +32,9 @@ tasks:
- (! cargo version | grep -q 'nightly')
cmds:
- cd benches && cargo bench --features DEBUG --no-run
- cd benches_rt/glommio && cargo check
- cd benches_rt/smol && cargo check
- cd benches_rt/tokio && cargo check
- cd benches_rt/vs_actix-web && cargo check
- for: [tokio, smol, nio, glommio]
cmd: cd benches_rt/{{.ITEM}} && cargo check

bench:
status:
Expand Down
24 changes: 24 additions & 0 deletions benches_rt/nio/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "ohkami_benches-with-nio"
version = "0.0.0"
edition = "2021"
authors = ["kanarus <[email protected]>"]

[dependencies]
# set `default-features = false` to assure "DEBUG" feature be off even when DEBUGing `../ohkami`
ohkami = { path = "../../ohkami", default-features = false, features = ["rt_nio"] }
nio = { version = "0.0" }

[profile.release]
opt-level = 3
debug = false
debug-assertions = false
lto = true
panic = "abort"
incremental = false
codegen-units = 1
rpath = false
strip = false

[features]
DEBUG = ["ohkami/DEBUG"]
9 changes: 9 additions & 0 deletions benches_rt/nio/src/bin/param.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use ohkami::prelude::*;

#[nio::main]
async fn main() {
Ohkami::new((
"/user/:id"
.GET(|id: String| async {id}),
)).howl("0.0.0.0:3000").await
}
13 changes: 8 additions & 5 deletions ohkami/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ ohkami_macros = { version = "=0.21.0", path = "../ohkami_macros" }
tokio = { version = "1", optional = true, features = ["rt", "net", "time"] }
async-std = { version = "1", optional = true }
smol = { version = "2", optional = true }
nio = { version = "0.0", optional = true }
glommio = { version = "0.9", optional = true }
worker = { version = "0.4", optional = true }

Expand All @@ -39,16 +40,17 @@ sha2 = { version = "0.10", default-features = false }
ctrlc = { version = "3.4", optional = true }
num_cpus = { version = "1.16", optional = true }
futures-util = { version = "0.3", optional = true, default-features = false, features = ["io", "async-await-macro"] }
mews = { version = "0.1", optional = true }
mews = { version = "0.2", optional = true }


[features]
default = ["testing"]

rt_tokio = ["__rt__", "__rt_native__", "dep:tokio", "tokio/io-util", "tokio/macros", "mews?/tokio"]
rt_async-std = ["__rt__", "__rt_native__", "dep:async-std", "dep:futures-util", "mews?/async-std"]
rt_smol = ["__rt__", "__rt_native__", "dep:smol", "dep:futures-util", "mews?/smol"]
rt_glommio = ["__rt__", "__rt_native__", "dep:glommio", "dep:futures-util", "dep:num_cpus", "mews?/glommio"]
rt_tokio = ["__rt__", "__rt_native__", "dep:tokio", "tokio/io-util", "tokio/macros", "mews?/rt_tokio" ]
rt_async-std = ["__rt__", "__rt_native__", "dep:async-std", "dep:futures-util", "mews?/rt_async-std"]
rt_smol = ["__rt__", "__rt_native__", "dep:smol", "dep:futures-util", "mews?/rt_smol" ]
rt_nio = ["__rt__", "__rt_native__", "dep:nio", "dep:tokio", "tokio/io-util", "mews?/rt_nio" ]
rt_glommio = ["__rt__", "__rt_native__", "dep:glommio", "dep:futures-util", "dep:num_cpus", "mews?/rt_glommio" ]
rt_worker = ["__rt__", "dep:worker", "ohkami_macros/worker"]

nightly = []
Expand All @@ -70,6 +72,7 @@ DEBUG = ["tokio?/rt-multi-thread"]
# "rt_tokio",
# #"rt_async-std",
# #"rt_smol",
# #"rt_nio",
# #"rt_glommio",
# #"rt_worker",
# #"DEBUG",
Expand Down
86 changes: 55 additions & 31 deletions ohkami/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! <br>
//!
//! - *macro-less and type-safe* APIs for intuitive and declarative code
//! - *multi runtimes* are supported:`tokio`, `async-std`, `worker` (Cloudflare Workers)
//! - *multi runtimes* are supported:`tokio`, `async-std`, `smol`, `nio`, `glommio`, `worker` (Cloudflare Workers)
//!
//! <div align="right">
//! <a href="https://github.com/ohkami-rs/ohkami/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/crates/l/ohkami.svg" /></a>
Expand All @@ -28,16 +28,12 @@


#[cfg(any(
all(feature="rt_tokio", feature="rt_async-std"),
all(feature="rt_tokio", feature="rt_smol"),
all(feature="rt_tokio", feature="rt_glommio"),
all(feature="rt_tokio", feature="rt_worker"),
all(feature="rt_async-std", feature="rt_smol"),
all(feature="rt_async-std", feature="rt_glommio"),
all(feature="rt_async-std", feature="rt_worker"),
all(feature="rt_smol", feature="rt_glommio"),
all(feature="rt_smol", feature="rt_worker"),
all(feature="rt_glommio", feature="rt_worker"),
all(feature="rt_tokio", any(feature="rt_async-std", feature="rt_smol", feature="rt_nio", feature="rt_glommio", feature="rt_worker" )),
all(feature="rt_async-std", any(feature="rt_smol", feature="rt_nio", feature="rt_glommio", feature="rt_worker", feature="rt_tokio" )),
all(feature="rt_smol", any(feature="rt_nio", feature="rt_glommio", feature="rt_worker", feature="rt_tokio", feature="rt_async-std")),
all(feature="rt_nio", any(feature="rt_glommio", feature="rt_worker", feature="rt_tokio", feature="rt_async-std", feature="rt_smol" )),
all(feature="rt_glommio", any(feature="rt_worker", feature="rt_tokio", feature="rt_async-std", feature="rt_smol", feature="rt_nio" )),
all(feature="rt_worker", any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol", feature="rt_nio", feature="rt_glommio" )),
))] compile_error! {"
Can't activate multiple `rt_*` features at once!
"}
Expand All @@ -62,13 +58,15 @@ mod __rt__ {
pub(crate) use async_std::net::{TcpListener, TcpStream, ToSocketAddrs};
#[cfg(feature="rt_smol")]
pub(crate) use smol::net::{TcpListener, TcpStream, AsyncToSocketAddrs as ToSocketAddrs};
#[cfg(feature="rt_nio")]
pub(crate) use {nio::net::{TcpListener, TcpStream}, std::net::ToSocketAddrs};
#[cfg(feature="rt_glommio")]
pub(crate) use {glommio::net::{TcpListener, TcpStream}, std::net::ToSocketAddrs};

pub(crate) async fn bind(address: impl ToSocketAddrs) -> TcpListener {
let binded = TcpListener::bind(address);

#[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_smol"))]
#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol", feature="rt_nio"))]
let binded = binded.await;

binded.expect("Failed to bind TCP listener")
Expand All @@ -82,6 +80,8 @@ mod __rt__ {
pub(crate) async fn sleep(duration: std::time::Duration) {
smol::Timer::after(duration).await;
}
#[cfg(feature="rt_nio")]
pub(crate) use nio::time::sleep;
#[cfg(feature="rt_glommio")]
pub(crate) use glommio::timer::sleep;

Expand All @@ -91,6 +91,8 @@ mod __rt__ {
pub(crate) use async_std::io::ReadExt as AsyncRead;
#[cfg(feature="rt_smol")]
pub(crate) use futures_util::AsyncReadExt as AsyncRead;
#[cfg(feature="rt_nio")]
pub(crate) use tokio::io::AsyncReadExt as AsyncRead;
#[cfg(feature="rt_glommio")]
pub(crate) use futures_util::AsyncReadExt as AsyncRead;

Expand All @@ -100,6 +102,8 @@ mod __rt__ {
pub(crate) use async_std::io::WriteExt as AsyncWrite;
#[cfg(feature="rt_smol")]
pub(crate) use futures_util::AsyncWriteExt as AsyncWrite;
#[cfg(feature="rt_nio")]
pub(crate) use tokio::io::AsyncWriteExt as AsyncWrite;
#[cfg(feature="rt_glommio")]
pub(crate) use futures_util::AsyncWriteExt as AsyncWrite;

Expand All @@ -109,10 +113,12 @@ mod __rt__ {
pub(crate) use futures_util::select;
#[cfg(feature="rt_smol")]
pub(crate) use futures_util::select;
#[cfg(feature="rt_nio")]
pub(crate) use tokio::select;
#[cfg(feature="rt_glommio")]
pub(crate) use futures_util::select;

#[cfg(any(feature="rt_tokio"))]
#[cfg(any(feature="rt_tokio", feature="rt_nio"))]
pub(crate) const fn selectable<F: std::future::Future>(future: F) -> F {
future
}
Expand All @@ -121,7 +127,7 @@ mod __rt__ {
::futures_util::FutureExt::fuse(future)
}

#[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_smol"))]
#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol", feature="rt_nio"))]
mod task {
pub trait Task: std::future::Future<Output: Send + 'static> + Send + 'static {}
impl<F: std::future::Future<Output: Send + 'static> + Send + 'static> Task for F {}
Expand All @@ -141,27 +147,45 @@ mod __rt__ {
#[cfg(feature="rt_smol")]
smol::spawn(task).detach();

#[cfg(feature="rt_nio")]
nio::spawn(task);

#[cfg(feature="rt_glommio")]
glommio::spawn_local(task).detach();
}

#[cfg(feature="testing")]
#[cfg(test)]
pub(crate) fn block_on(future: impl std::future::Future) {
#[cfg(feature="rt_tokio")]
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build().unwrap()
.block_on(future);

#[cfg(feature="rt_async-std")]
async_std::task::block_on(future);

#[cfg(feature="rt_smol")]
smol::block_on(future);

#[cfg(feature="rt_glommio")]
glommio::LocalExecutor::default().run(future);
#[cfg(all(test, feature="testing"))]
pub(crate) mod testing {
pub(crate) fn block_on(future: impl std::future::Future) {
#[cfg(feature="rt_tokio")]
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build().unwrap()
.block_on(future);

#[cfg(feature="rt_async-std")]
async_std::task::block_on(future);

#[cfg(feature="rt_smol")]
smol::block_on(future);

#[cfg(feature="rt_nio")]
nio::runtime::Builder::new_multi_thread()
.enable_all()
.build().unwrap()
.block_on(future);

#[cfg(feature="rt_glommio")]
glommio::LocalExecutor::default().run(future);
}

pub(crate) const PORT: u16 = {
#[cfg(feature="rt_tokio") ] {3001}
#[cfg(feature="rt_async-std")] {3002}
#[cfg(feature="rt_smol") ] {3003}
#[cfg(feature="rt_nio") ] {3004}
#[cfg(feature="rt_glommio") ] {3005}
};
}
}

Expand Down
23 changes: 12 additions & 11 deletions ohkami/src/ohkami/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use std::sync::Arc;
#[cfg(feature="__rt_native__")]
use crate::{__rt__, Session};

/// # Ohkami - a robust wolf who serves your web app
/// # Ohkami - a smart wolf who serves your web app
///
/// <br>
///
Expand Down Expand Up @@ -105,8 +105,9 @@ use crate::{__rt__, Session};
/// `async ({path_params}?, {FromRequest type}s...) -> {IntoResponse type}`
///
/// #### path_params:
/// A tuple of types that implement `FromParam` trait.\
/// If the path contains only one parameter, then you can omit the tuple.\
/// A tuple of types that implement `FromParam` trait e.g. `(&str, usize)`.\
/// If the path contains only one parameter, then you can omit the tuple \
/// e.g. just `param: &str`.\
/// (In current ohkami, at most *2* path params can be handled.)
///
/// <br>
Expand Down Expand Up @@ -248,7 +249,7 @@ impl Ohkami {
/// - `tokio::net::ToSocketAddrs` if using `tokio`
/// - `async_std::net::ToSocketAddrs` if using `async-std`
/// - `smol::net::AsyncToSocketAddrs` if using `smol`
/// - `std::net::ToSocketAddrs` if using `glommio`
/// - `std::net::ToSocketAddrs` if using `nio` or `glommio`
///
/// *note* : Keep-Alive timeout is 42 seconds and this is not
/// configureable by user (it'll be in future version...)
Expand Down Expand Up @@ -313,7 +314,7 @@ impl Ohkami {
__rt__::select! {
accept = __rt__::selectable(listener.accept()) => {
let (connection, addr) = {
#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol"))] {
#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol", feature="rt_nio"))] {
let Ok((connection, addr)) = accept else {continue};
(connection, addr)
}
Expand Down Expand Up @@ -453,12 +454,12 @@ mod sync {
use std::task::{Context, Poll, Waker};
use std::pin::Pin;

#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol"))]
#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol", feature="rt_nio"))]
use std::{sync::atomic::AtomicPtr, ptr::null_mut};
#[cfg(any(feature="rt_glommio"))]
use std::sync::Mutex;

#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol"))]
#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol", feature="rt_nio"))]
static WAKER: AtomicPtr<Waker> = AtomicPtr::new(null_mut());
#[cfg(any(feature="rt_glommio"))]
static WAKER: Mutex<Vec<(usize, Waker)>> = Mutex::new(Vec::new());
Expand All @@ -477,7 +478,7 @@ mod sync {
crate::DEBUG!("[CtrlC::catch] Ready");
Poll::Ready(())
} else {
#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol"))] {
#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol", feature="rt_nio"))] {
let prev_waker = WAKER.swap(
Box::into_raw(Box::new(cx.waker().clone())),
Ordering::SeqCst
Expand All @@ -502,7 +503,7 @@ mod sync {
}

pub fn new() -> Self {
#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol"))]
#[cfg(any(feature="rt_tokio", feature="rt_async-std", feature="rt_smol", feature="rt_nio"))]
::ctrlc::set_handler(|| {
CATCH.store(true, Ordering::SeqCst);
let waker = WAKER.swap(null_mut(), Ordering::SeqCst);
Expand Down Expand Up @@ -530,10 +531,10 @@ mod sync {
#[cfg(all(feature="testing", feature="__rt_native__"))]
#[cfg(test)]
#[test] fn can_howl_on_any_native_async_runtime() {
__rt__::block_on(async {
__rt__::testing::block_on(async {
crate::util::timeout_in(
std::time::Duration::from_secs(3),
Ohkami::new(()).howl("localhost:3000")
Ohkami::new(()).howl(("localhost", __rt__::testing::PORT))
).await
});
}