diff --git a/Cargo.toml b/Cargo.toml index d6076c59..f8bc5181 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,10 +3,11 @@ resolver = "2" members = [ "ohkami", "ohkami_lib", - "ohkami_macros" + "ohkami_macros", ] exclude = [ "benches", + "benches_glommio", ] [workspace.dependencies] diff --git a/README.md b/README.md index c37887d3..92d6e569 100644 --- a/README.md +++ b/README.md @@ -66,9 +66,11 @@ Hello, your_name! ## Feature flags -### `"rt_tokio"`, `"rt_async-std"` +### `"rt_tokio"`, `"rt_async-std"`, `"rt_glommio"`:native async runtime -Select a native async runtime +- [tokio](https://github.com/tokio-rs/tokio) +- [async-std](https://github.com/async-rs/async-std) +- [glommio](https://github.com/DataDog/glommio) ### `"rt_worker"`:Cloudflare Workers diff --git a/Taskfile.yaml b/Taskfile.yaml index d2c35ee6..d2a5befc 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -8,6 +8,7 @@ tasks: - test_no_rt - test_rt_tokio - test_rt_async-std + - test_rt_glommio - test_rt_worker check: @@ -15,13 +16,14 @@ tasks: - check_no_rt - check_rt_tokio - check_rt_async-std + - check_rt_glommio - check_rt_worker bench_dryrun: - dir: benches cmds: - - cargo bench --features DEBUG --no-run - - cargo check --bin hello + - cd benches && cargo bench --features DEBUG --no-run + - cd benches && cargo check + - cd benches_glommio && cargo check bench: dir: benches @@ -73,6 +75,15 @@ tasks: - cargo test --lib --features rt_async-std,DEBUG,{{.MAYBE_NIGHTLY}} - cargo test --lib --features rt_async-std,DEBUG,sse,ws,{{.MAYBE_NIGHTLY}} + test_rt_glommio: + vars: + MAYBE_NIGHTLY: + sh: cargo version | grep -q 'nightly' && echo 'nightly' || echo '' + dir: ohkami + cmds: + - cargo test --lib --features rt_glommio,DEBUG,{{.MAYBE_NIGHTLY}} + - cargo test --lib --features rt_glommio,DEBUG,sse,ws,{{.MAYBE_NIGHTLY}} + test_rt_worker: vars: MAYBE_NIGHTLY: @@ -120,6 +131,17 @@ tasks: - cargo check --lib --features rt_async-std,sse,{{.MAYBE_NIGHTLY}} - cargo check --lib --features rt_async-std,sse,ws,{{.MAYBE_NIGHTLY}} + check_rt_glommio: + vars: + MAYBE_NIGHTLY: + sh: cargo version | grep -q 'nightly' && echo 'nightly' || echo '' + dir: ohkami + cmds: + - cargo check --lib --features rt_glommio,{{.MAYBE_NIGHTLY}} + - cargo check --lib --features rt_glommio,ip,{{.MAYBE_NIGHTLY}} + - cargo check --lib --features rt_glommio,sse,{{.MAYBE_NIGHTLY}} + - cargo check --lib --features rt_glommio,sse,ws,{{.MAYBE_NIGHTLY}} + check_rt_worker: vars: MAYBE_NIGHTLY: diff --git a/benches/src/bin/hello.rs b/benches/src/bin/hello.rs index c0981a77..7dc3b4f0 100644 --- a/benches/src/bin/hello.rs +++ b/benches/src/bin/hello.rs @@ -1,5 +1,5 @@ use ohkami::prelude::*; -use ohkami::{serde::*, format::JSON}; +use ohkami::format::JSON; #[cfg(feature="DEBUG")] #[derive(Clone)] diff --git a/benches_glommio/Cargo.toml b/benches_glommio/Cargo.toml new file mode 100644 index 00000000..bb28057e --- /dev/null +++ b/benches_glommio/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "ohkami_benches-with-glommio" +version = "0.0.0" +edition = "2021" +authors = ["kanarus "] + +[dependencies] +# set `default-features = false` to assure "DEBUG" feature be off even when DEBUGing `../ohkami` +ohkami = { path = "../ohkami", default-features = false, features = ["rt_glommio"] } +glommio = { version = "0.9" } diff --git a/benches_glommio/src/bin/param.rs b/benches_glommio/src/bin/param.rs new file mode 100644 index 00000000..33f3e50b --- /dev/null +++ b/benches_glommio/src/bin/param.rs @@ -0,0 +1,20 @@ +use ohkami::prelude::*; +use ohkami::utils::num_cpus; +use glommio::{LocalExecutorPoolBuilder, PoolPlacement, CpuSet}; + + +#[inline(always)] +async fn echo_id(id: String) -> String { + id +} + +fn main() { + LocalExecutorPoolBuilder::new(PoolPlacement::MaxSpread( + dbg!(num_cpus::get()), dbg!(CpuSet::online().ok()) + )).on_all_shards(|| { + Ohkami::new(( + "/user/:id" + .GET(echo_id), + )).howl("0.0.0.0:3000") + }).unwrap().join_all(); +} diff --git a/ohkami/Cargo.toml b/ohkami/Cargo.toml index ab593f81..d37ce4fd 100644 --- a/ohkami/Cargo.toml +++ b/ohkami/Cargo.toml @@ -23,6 +23,7 @@ ohkami_macros = { version = "=0.8.0", path = "../ohkami_macros" } tokio = { version = "1", optional = true, features = ["net", "rt", "io-util", "sync", "time"] } async-std = { version = "1", optional = true } +glommio = { version = "0.9", optional = true } worker = { version = "0.3", optional = true } byte_reader = { workspace = true } @@ -35,13 +36,17 @@ hmac = { version = "0.12", default-features = false } sha2 = { version = "0.10", default-features = false } sha1 = { version = "0.10", optional = true, default-features = false } +num_cpus = { version = "1.16", optional = true } +futures-util = { version = "0.3", optional = true, default-features = false, features = ["io"] } + [features] default = ["testing"] -rt_tokio = ["dep:tokio"] -rt_async-std = ["dep:async-std"] -rt_worker = ["dep:worker", "ohkami_macros/worker"] +rt_tokio = ["__rt__", "__rt_native__", "dep:tokio"] +rt_async-std = ["__rt__", "__rt_native__", "dep:async-std"] +rt_glommio = ["__rt__", "__rt_native__", "dep:glommio", "dep:num_cpus", "dep:futures-util"] +rt_worker = ["__rt__", "dep:worker", "ohkami_macros/worker"] nightly = [] testing = [] @@ -50,6 +55,10 @@ ws = ["dep:sha1"] graceful = ["rt_tokio", "tokio/signal", "tokio/macros"] ip = [] +##### internal ##### +__rt__ = [] +__rt_native__ = [] + ##### DEBUG ##### DEBUG = [ "tokio?/macros", @@ -64,6 +73,7 @@ DEBUG = [ # "ip", # "rt_tokio", # #"rt_async-std", +# #"rt_glommio", # #"rt_worker", # "DEBUG", #] \ No newline at end of file diff --git a/ohkami/src/fang/builtin.rs b/ohkami/src/fang/builtin.rs index 11918c78..fca8f146 100644 --- a/ohkami/src/fang/builtin.rs +++ b/ohkami/src/fang/builtin.rs @@ -7,7 +7,7 @@ pub use cors::CORS; mod jwt; pub use jwt::{JWT, JWTToken}; -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] mod timeout; -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] pub use timeout::Timeout; diff --git a/ohkami/src/fang/builtin/timeout.rs b/ohkami/src/fang/builtin/timeout.rs index a15ef929..da39335d 100644 --- a/ohkami/src/fang/builtin/timeout.rs +++ b/ohkami/src/fang/builtin/timeout.rs @@ -1,4 +1,4 @@ -#![cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#![cfg(feature="__rt_native__")] use std::time::Duration; diff --git a/ohkami/src/fang/mod.rs b/ohkami/src/fang/mod.rs index 6e704ed2..a84f0b9d 100644 --- a/ohkami/src/fang/mod.rs +++ b/ohkami/src/fang/mod.rs @@ -1,6 +1,6 @@ -#[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] +#[cfg(any(feature="__rt_native__",feature="rt_worker"))] mod handler; -#[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] +#[cfg(any(feature="__rt_native__",feature="rt_worker"))] pub(crate) use handler::{Handler, IntoHandler}; mod middleware; diff --git a/ohkami/src/header/map.rs b/ohkami/src/header/map.rs index 58f1fce6..a3525f6c 100644 --- a/ohkami/src/header/map.rs +++ b/ohkami/src/header/map.rs @@ -14,7 +14,7 @@ impl IndexMap { } } - #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] + #[allow(unused)] #[inline] pub(crate) fn clear(&mut self) { for idx in &mut self.index {*idx = Self::NULL} diff --git a/ohkami/src/lib.rs b/ohkami/src/lib.rs index d5028477..07cc5915 100644 --- a/ohkami/src/lib.rs +++ b/ohkami/src/lib.rs @@ -29,8 +29,11 @@ #[cfg(any( all(feature="rt_tokio", feature="rt_async-std"), - all(feature="rt_async-std", feature="rt_worker"), + all(feature="rt_async-std", feature="rt_glommio"), + all(feature="rt_glommio", feature="rt_worker"), all(feature="rt_worker", feature="rt_tokio"), + all(feature="rt_tokio", feature="rt_glommio"), + all(feature="rt_async-std", feature="rt_worker"), ))] compile_error! {" Can't activate multiple `rt_*` features at once! "} @@ -67,26 +70,36 @@ mod __rt__ { pub(crate) use tokio::net::{TcpListener, TcpStream, ToSocketAddrs}; #[cfg(feature="rt_async-std")] pub(crate) use async_std::net::{TcpListener, TcpStream, ToSocketAddrs}; + #[cfg(feature="rt_glommio")] + pub(crate) use {glommio::net::{TcpListener, TcpStream}, std::net::ToSocketAddrs}; #[cfg(feature="rt_tokio")] pub(crate) use tokio::task; #[cfg(feature="rt_async-std")] pub(crate) use async_std::task; + #[cfg(feature="rt_glommio")] + pub(crate) use glommio::task; #[cfg(feature="rt_tokio")] pub(crate) use tokio::time::sleep; #[cfg(feature="rt_async-std")] pub(crate) use async_std::task::sleep; + #[cfg(feature="rt_glommio")] + pub(crate) use glommio::timer::sleep; #[cfg(feature="rt_tokio")] pub(crate) use tokio::io::AsyncReadExt as AsyncReader; #[cfg(feature="rt_async-std")] pub(crate) use async_std::io::ReadExt as AsyncReader; + #[cfg(feature="rt_glommio")] + pub(crate) use futures_util::AsyncReadExt as AsyncReader; #[cfg(feature="rt_tokio")] pub(crate) use tokio::io::AsyncWriteExt as AsyncWriter; #[cfg(feature="rt_async-std")] pub(crate) use async_std::io::WriteExt as AsyncWriter; + #[cfg(feature="rt_glommio")] + pub(crate) use futures_util::AsyncWriteExt as AsyncWriter; } @@ -102,23 +115,25 @@ pub use fang::{Fang, FangProc}; pub mod format; +#[cfg(feature="__rt_native__")] mod session; -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] use session::Session; +#[cfg(feature="__rt__")] mod ohkami; -#[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] +#[cfg(feature="__rt__")] pub use ohkami::{Ohkami, Route}; pub mod header; pub mod typed; -#[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] +#[cfg(all(feature="ws", feature="__rt_native__"))] pub mod ws; #[cfg(feature="testing")] -#[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] +#[cfg(feature="__rt__")] pub mod testing; pub mod utils { @@ -207,7 +222,7 @@ pub mod utils { } }; - #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] + #[cfg(feature="__rt_native__")] pub fn timeout_in( duration: std::time::Duration, proc: impl std::future::Future @@ -234,11 +249,20 @@ pub mod utils { } } + #[cfg(feature="rt_glommio")] + /* for fang::builtin::timeout::Timeout::Proc::bite to return Send Future */ + /* SAFETY: proc and sleep are executed on the same thread in rt_glommio */ + /* ( glommio::timer::sleep itself returns not-Send Future because it's not needed due to the architecture ) */ + unsafe impl Send for Timeout {} + Timeout { proc, sleep: crate::__rt__::sleep(duration) } } #[cfg(feature="ip")] - pub(crate) const IP_0000: std::net::IpAddr = std::net::IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)); + pub const IP_0000: std::net::IpAddr = std::net::IpAddr::V4(std::net::Ipv4Addr::new(0, 0, 0, 0)); + + #[cfg(feature="rt_glommio")] + pub use num_cpus; } #[cfg(feature="rt_worker")] @@ -250,7 +274,7 @@ pub mod prelude { pub use crate::serde::{Serialize, Deserialize}; pub use crate::format::JSON; - #[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] + #[cfg(feature="__rt__")] pub use crate::{Route, Ohkami}; } @@ -296,7 +320,7 @@ pub mod __internal__ { /* for benchmarks */ #[cfg(feature="DEBUG")] - #[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] + #[cfg(feature="__rt__")] pub use crate::{ request::{RequestHeader, RequestHeaders}, response::{ResponseHeader, ResponseHeaders}, diff --git a/ohkami/src/ohkami/mod.rs b/ohkami/src/ohkami/mod.rs index 0ef39201..da46d2f7 100644 --- a/ohkami/src/ohkami/mod.rs +++ b/ohkami/src/ohkami/mod.rs @@ -1,4 +1,4 @@ -#![cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] +#![cfg(feature="__rt__")] #[cfg(test)] mod _test; @@ -12,7 +12,7 @@ use crate::fang::Fangs; use std::sync::Arc; use router::TrieRouter; -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] use crate::{__rt__, Session}; @@ -229,19 +229,22 @@ impl Ohkami { } } - #[cfg(any(feature="rt_tokio", feature="rt_async-std"))] + #[cfg(feature="__rt_native__")] /// Start serving at `address`! /// - /// `address` is `{runtime}::net::ToSocketAddrs`: + /// `address` is: /// - /// - `tokio::net::ToSocketAddrs` if you use `tokio` - /// - `async_std::net::ToSocketAddrs` if you use `async-std` + /// - `tokio::net::ToSocketAddrs` if using `tokio` + /// - `async_std::net::ToSocketAddrs` if using `async-std` + /// - `std::net::ToSocketAddrs` if using `glommio` /// /// *note* : Keep-Alive timeout is 42 seconds and this is not /// configureable by user (it'll be in future version...) /// ///
/// + /// --- + /// /// *example.rs* /// ```no_run /// use ohkami::prelude::*; @@ -263,60 +266,110 @@ impl Ohkami { /// )).howl("localhost:5000").await /// } /// ``` + /// + /// --- + /// + /// *example_glommio.rs* + /// ```ignore + /// use ohkami::prelude::*; + /// use ohkami::utils::num_cpus; + /// use glommio::{LocalExecutorPoolBuilder, PoolPlacement, CpuSet}; + /// + /// async fn hello() -> &'static str { + /// "Hello, ohkami!" + /// } + /// + /// fn main() { + /// LocalExecutorPoolBuilder::new(PoolPlacement::MaxSpread( + /// num_cpus::get(), CpuSet::online().ok() + /// )).on_all_shards(|| { + /// Ohkami::new(( + /// "/user/:id" + /// .GET(echo_id), + /// )).howl("0.0.0.0:3000") + /// }).unwrap().join_all(); + /// } + /// ``` pub async fn howl(self, address: impl __rt__::ToSocketAddrs) { let router = Arc::new(self.into_router().into_radix()); - let listener = __rt__::TcpListener::bind(address).await.expect("Failed to bind TCP listener: {e}"); + + #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] + let listener = __rt__::TcpListener::bind(address).await.expect("Failed to bind TCP listener"); + #[cfg(feature="rt_glommio")] + let listener = __rt__::TcpListener::bind(address).expect("Failed to bind TCP listener"); - #[cfg(all(feature="rt_tokio", feature="graceful"))] { - let ctrl_c = tokio::signal::ctrl_c(); + #[cfg(feature="rt_tokio")] { + #[cfg(feature="graceful")] { + let ctrl_c = tokio::signal::ctrl_c(); + + let (ctrl_c_tx, ctrl_c_rx) = tokio::sync::watch::channel(()); + __rt__::task::spawn(async { + ctrl_c.await.expect("Something was wrong around Ctrl-C"); + drop(ctrl_c_rx); + }); - let (ctrl_c_tx, ctrl_c_rx) = tokio::sync::watch::channel(()); - __rt__::task::spawn(async { - ctrl_c.await.expect("Something was wrong around Ctrl-C"); - drop(ctrl_c_rx); - }); + let (close_tx, close_rx) = tokio::sync::watch::channel(()); + loop { + tokio::select! { + accept = listener.accept() => { + crate::DEBUG!("Accepted {accept:#?}"); + + #[cfg(not(feature="ip"))] + let Ok((connection, _)) = accept else {continue}; + #[cfg(feature="ip")] + let Ok((connection, addr)) = accept else {continue}; + + let session = Session::new( + router.clone(), + connection, + #[cfg(feature="ip")] addr.ip() + ); + + let close_rx = close_rx.clone(); + __rt__::task::spawn(async { + session.manage().await; + drop(close_rx) + }); + }, + _ = ctrl_c_tx.closed() => { + crate::DEBUG!("Recieved Ctrl-C, trying graceful shutdown"); + drop(listener); + break + } + } + } - let (close_tx, close_rx) = tokio::sync::watch::channel(()); - loop { - tokio::select! { - accept = listener.accept() => { - crate::DEBUG!("Accepted {accept:#?}"); + crate::DEBUG!("Waiting {} session(s) to finish...", close_tx.receiver_count()); + drop(close_rx); + close_tx.closed().await; + } - #[cfg(not(feature="ip"))] - let Ok((connection, _)) = accept else {continue}; - #[cfg(feature="ip")] - let Ok((connection, addr)) = accept else {continue}; + #[cfg(not(feature="graceful"))] { + loop { + #[cfg(not(feature="ip"))] + let Ok((connection, _)) = listener.accept().await else {continue}; + #[cfg(feature="ip")] + let Ok((connection, addr)) = listener.accept().await else {continue}; - let session = Session::new( + __rt__::task::spawn({ + Session::new( router.clone(), connection, #[cfg(feature="ip")] addr.ip() - ); - - let close_rx = close_rx.clone(); - __rt__::task::spawn(async { - session.manage().await; - drop(close_rx) - }); - }, - _ = ctrl_c_tx.closed() => { - crate::DEBUG!("Recieved Ctrl-C, trying graceful shutdown"); - drop(listener); - break - } + ).manage() + }); } } - - crate::DEBUG!("Waiting {} session(s) to finish...", close_tx.receiver_count()); - drop(close_rx); - close_tx.closed().await; } - #[cfg(all(feature="rt_tokio", not(feature="graceful")))] { - loop { - #[cfg(not(feature="ip"))] - let Ok((connection, _)) = listener.accept().await else {continue}; + + #[cfg(feature="rt_async-std")] { + use async_std::stream::StreamExt as _/* .next() */; + + while let Some(connection) = listener.incoming().next().await { + let Ok(connection) = connection else {continue}; + #[cfg(feature="ip")] - let Ok((connection, addr)) = listener.accept().await else {continue}; + let Ok(addr) = connection.peer_addr() else {continue}; __rt__::task::spawn({ Session::new( @@ -327,22 +380,21 @@ impl Ohkami { }); } } - #[cfg(feature="rt_async-std")] { - use async_std::stream::StreamExt as _/* .next() */; - - while let Some(connection) = listener.incoming().next().await { - let Ok(connection) = connection else {continue}; + + #[cfg(feature="rt_glommio")] { + loop { + let Ok(connection) = listener.accept().await else {continue}; #[cfg(feature="ip")] let Ok(addr) = connection.peer_addr() else {continue}; - __rt__::task::spawn({ + glommio::spawn_local({ Session::new( router.clone(), connection, #[cfg(feature="ip")] addr.ip() ).manage() - }); + }).detach(); } } } diff --git a/ohkami/src/request/_test_headers.rs b/ohkami/src/request/_test_headers.rs index e50a7070..30e8a5d3 100644 --- a/ohkami/src/request/_test_headers.rs +++ b/ohkami/src/request/_test_headers.rs @@ -1,5 +1,5 @@ #![cfg(any(feature="testing", feature="DEBUG"))] -#![cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] +#![cfg(feature="__rt__")] use ohkami_lib::CowSlice; diff --git a/ohkami/src/request/_test_parse.rs b/ohkami/src/request/_test_parse.rs index 24d48815..8eaa7c04 100644 --- a/ohkami/src/request/_test_parse.rs +++ b/ohkami/src/request/_test_parse.rs @@ -1,42 +1,8 @@ -#![cfg(any(feature="rt_tokio", feature="rt_async-std"))] +#![cfg(feature="__rt_native__")] -use std::pin::Pin; -use ohkami_lib::{Slice, CowSlice}; #[allow(unused)] use super::{Request, Method, BUF_SIZE, Path, QueryParams, Store}; -macro_rules! assert_parse { - ($case:expr, $expected:expr) => { - let mut actual = Request::init(#[cfg(feature="ip")] crate::utils::IP_0000); - let mut actual = unsafe {Pin::new_unchecked(&mut actual)}; - actual.as_mut().read(&mut $case.as_bytes()).await.ok(); - - let expected = $expected; - - let _ = async {println!("")}.await; - - let __panic_message = format!("\n\ - ===== actual =====\n\ - {actual:#?}\n\ - \n\ - ===== expected =====\n\ - {expected:#?}\n\ - \n\ - "); - - if actual.get_mut() != &expected { - panic!("{__panic_message}") - } - }; -} - -fn metadataize(input: &str) -> Box<[u8; BUF_SIZE]> { - let mut buf = [0; BUF_SIZE]; - buf[..input.len().min(BUF_SIZE)] - .copy_from_slice(&input.as_bytes()[..input.len().min(BUF_SIZE)]); - Box::new(buf) -} - #[test] fn parse_path() { let mut path = Path::uninit(); @@ -52,8 +18,43 @@ fn parse_path() { assert_eq!(&*path, "/"); } +#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] #[crate::__rt__::test] async fn test_parse_request() { use super::{RequestHeader, RequestHeaders}; + use std::pin::Pin; + use ohkami_lib::{Slice, CowSlice}; + + fn metadataize(input: &str) -> Box<[u8; BUF_SIZE]> { + let mut buf = [0; BUF_SIZE]; + buf[..input.len().min(BUF_SIZE)] + .copy_from_slice(&input.as_bytes()[..input.len().min(BUF_SIZE)]); + Box::new(buf) + } + + macro_rules! assert_parse { + ($case:expr, $expected:expr) => { + let mut actual = Request::init(#[cfg(feature="ip")] crate::utils::IP_0000); + let mut actual = unsafe {Pin::new_unchecked(&mut actual)}; + actual.as_mut().read(&mut $case.as_bytes()).await.ok(); + + let expected = $expected; + + let _ = async {println!("")}.await; + + let __panic_message = format!("\n\ + ===== actual =====\n\ + {actual:#?}\n\ + \n\ + ===== expected =====\n\ + {expected:#?}\n\ + \n\ + "); + + if actual.get_mut() != &expected { + panic!("{__panic_message}") + } + }; + } const CASE_1: &str = "\ GET /hello.html HTTP/1.1\r\n\ diff --git a/ohkami/src/request/headers.rs b/ohkami/src/request/headers.rs index 627a302b..3d6ffb40 100644 --- a/ohkami/src/request/headers.rs +++ b/ohkami/src/request/headers.rs @@ -345,7 +345,7 @@ impl Headers { } } -#[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] +#[cfg(feature="__rt__")] impl Headers { #[inline] pub(crate) fn init() -> Self { @@ -359,7 +359,7 @@ impl Headers { Self::init() } - #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] + #[cfg(feature="__rt_native__")] #[inline] pub(crate) fn clear(&mut self) { self.standard.clear(); diff --git a/ohkami/src/request/memory.rs b/ohkami/src/request/memory.rs index 9e228fbd..9b4dd287 100644 --- a/ohkami/src/request/memory.rs +++ b/ohkami/src/request/memory.rs @@ -29,12 +29,13 @@ impl Hasher for TypeIDHasger { } } impl Store { - #[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] + #[cfg(feature="__rt__")] pub(super) const fn init() -> Self { Self(None) } - #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] - pub(super) fn clear(&mut self) { + + #[allow(unused)] + pub fn clear(&mut self) { if let Some(map) = &mut self.0 { map.clear() } diff --git a/ohkami/src/request/method.rs b/ohkami/src/request/method.rs index 3b151fb6..321c27dd 100644 --- a/ohkami/src/request/method.rs +++ b/ohkami/src/request/method.rs @@ -10,10 +10,7 @@ pub enum Method { } impl Method { - #[cfg(any( - all(feature="testing",feature="rt_worker"), - feature="rt_tokio",feature="rt_async-std"))] - #[inline(always)] pub(crate) const fn from_bytes(bytes: &[u8]) -> Option { + pub const fn from_bytes(bytes: &[u8]) -> Option { match bytes { b"GET" => Some(Self::GET), b"PUT" => Some(Self::PUT), diff --git a/ohkami/src/request/mod.rs b/ohkami/src/request/mod.rs index dff9e261..aa6d205e 100644 --- a/ohkami/src/request/mod.rs +++ b/ohkami/src/request/mod.rs @@ -4,8 +4,8 @@ pub use method::Method; mod path; pub(crate) use path::Path; -mod queries; -pub(crate) use queries::QueryParams; +mod query; +pub(crate) use query::QueryParams; mod headers; pub use headers::Headers as RequestHeaders; @@ -25,7 +25,7 @@ pub use from_request::*; use ohkami_lib::{Slice, CowSlice}; -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] use { crate::__rt__::AsyncReader, }; @@ -37,9 +37,9 @@ use { }; -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] pub(crate) const BUF_SIZE: usize = 1 << 10; -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] pub(crate) const PAYLOAD_LIMIT: usize = 1 << 32; /// # HTTP Request @@ -99,7 +99,7 @@ pub(crate) const PAYLOAD_LIMIT: usize = 1 << 32; /// } /// ``` pub struct Request { - #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] + #[cfg(feature="__rt_native__")] pub(super/* for test */) __buf__: Box<[u8; BUF_SIZE]>, #[cfg(feature="rt_worker")] @@ -168,14 +168,14 @@ pub struct Request { } impl Request { - #[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] + #[cfg(feature="__rt__")] #[inline] pub(crate) fn init( #[cfg(feature="ip")] addr: std::net::IpAddr ) -> Self { Self { - #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] + #[cfg(feature="__rt_native__")] __buf__: Box::new([0; BUF_SIZE]), #[cfg(feature="rt_worker")] @@ -196,7 +196,7 @@ impl Request { addr } } - #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] + #[cfg(feature="__rt_native__")] #[inline] pub(crate) fn clear(&mut self) { if self.__buf__[0] != 0 { @@ -211,7 +211,7 @@ impl Request { } /* else: just after `init`ed or `clear`ed */ } - #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] + #[cfg(feature="__rt_native__")] #[inline] pub(crate) async fn read( mut self: Pin<&mut Self>, @@ -285,7 +285,7 @@ impl Request { Ok(Some(())) } - #[cfg(any(feature="rt_tokio", feature="rt_async-std"))] + #[cfg(feature="__rt_native__")] #[inline] async fn read_payload( stream: &mut (impl AsyncReader + Unpin), @@ -461,14 +461,10 @@ const _: () = { } }; -#[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] +#[cfg(feature="__rt__")] #[cfg(test)] const _: () = { impl PartialEq for Request { fn eq(&self, other: &Self) -> bool { - #[cfg(feature="ip")] if self.addr != other.addr { - return false - } - self.method == other.method && unsafe {self.path.normalized_bytes() == other.path.normalized_bytes()} && self.query == other.query && diff --git a/ohkami/src/request/path.rs b/ohkami/src/request/path.rs index 81c3df1b..002eed11 100644 --- a/ohkami/src/request/path.rs +++ b/ohkami/src/request/path.rs @@ -74,7 +74,7 @@ const _: () = { } }; -#[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] +#[cfg(feature="__rt__")] const _: () = { impl Params { #[inline(always)] @@ -139,14 +139,15 @@ const _: () = { self.0.assume_init_ref().raw.as_bytes() } } -}; - -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] -#[cfg(test)] impl Path { - pub(crate) fn from_literal(literal: &'static str) -> Self { - Self(MaybeUninit::new(PathInner { - raw: Slice::from_bytes(literal.as_bytes()), - params: Params::init(), - })) + + #[cfg(test)] + impl Path { + pub fn from_literal(literal: &'static str) -> Self { + Self(MaybeUninit::new(PathInner { + raw: Slice::from_bytes(literal.as_bytes()), + params: Params::init(), + })) + } } -} +}; + \ No newline at end of file diff --git a/ohkami/src/request/queries.rs b/ohkami/src/request/query.rs similarity index 94% rename from ohkami/src/request/queries.rs rename to ohkami/src/request/query.rs index 0df44bd7..90cc9d0c 100644 --- a/ohkami/src/request/queries.rs +++ b/ohkami/src/request/query.rs @@ -12,7 +12,7 @@ pub struct QueryParams( ); impl QueryParams { - #[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] + #[cfg(feature="__rt__")] #[inline(always)] pub(crate) fn new(bytes: &[u8]) -> Self { Self(Slice::from_bytes(bytes)) } @@ -46,7 +46,7 @@ impl QueryParams { } } -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] #[cfg(test)] const _: () = { impl From<[(&'static str, &'static str); N]> for QueryParams { diff --git a/ohkami/src/response/content.rs b/ohkami/src/response/content.rs index ee60bf34..1ea47a79 100644 --- a/ohkami/src/response/content.rs +++ b/ohkami/src/response/content.rs @@ -3,7 +3,7 @@ use ohkami_lib::CowSlice; #[cfg(feature="sse")] use ohkami_lib::Stream; -#[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] +#[cfg(all(feature="ws", feature="__rt_native__"))] use crate::ws::{Config, Handler}; @@ -15,7 +15,7 @@ pub enum Content { #[cfg(feature="sse")] Stream(std::pin::Pin> + Send>>), - #[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] + #[cfg(all(feature="ws", feature="__rt_native__"))] WebSocket((Config, Handler)), } const _: () = { impl Default for Content { @@ -46,7 +46,7 @@ pub enum Content { #[cfg(feature="sse")] Self::Stream(_) => f.write_str("{stream}"), - #[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] + #[cfg(all(feature="ws", feature="__rt_native__"))] Self::WebSocket(_) => f.write_str("{websocket}"), } } diff --git a/ohkami/src/response/headers.rs b/ohkami/src/response/headers.rs index 0670eb49..5207ec10 100644 --- a/ohkami/src/response/headers.rs +++ b/ohkami/src/response/headers.rs @@ -434,7 +434,7 @@ impl Headers { } #[cfg(any( - feature="rt_tokio",feature="rt_async-std", + feature="__rt_native__", feature="DEBUG" ))] /// SAFETY: `buf` has remaining capacity of at least `self.size` diff --git a/ohkami/src/response/mod.rs b/ohkami/src/response/mod.rs index 457f95b2..ad84e7c1 100644 --- a/ohkami/src/response/mod.rs +++ b/ohkami/src/response/mod.rs @@ -4,7 +4,7 @@ pub use status::Status; mod headers; pub use headers::{Headers as ResponseHeaders, SetHeaders}; #[cfg(any(feature="testing", feature="DEBUG"))] -#[cfg(any(feature="rt_tokio",feature="rt_async-std",feature="rt_worker"))] +#[cfg(any(feature="__rt__"))] pub use headers::Header as ResponseHeader; mod content; @@ -19,7 +19,7 @@ pub use into_response::IntoResponse; use std::borrow::Cow; use ohkami_lib::{CowSlice, Slice}; -#[cfg(any(feature="rt_tokio", feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] use crate::__rt__::AsyncWriter; #[cfg(feature="sse")] use crate::utils::StreamExt; @@ -148,27 +148,27 @@ impl Response { .ContentLength(None); } - #[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] + #[cfg(all(feature="ws", feature="__rt_native__"))] Content::WebSocket(_) => (), }; } } -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] pub(super) enum Upgrade { None, - #[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] + #[cfg(all(feature="ws", feature="__rt_native__"))] WebSocket((crate::ws::Config, crate::ws::Handler)), } -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] impl Upgrade { #[inline(always)] pub(super) const fn is_none(&self) -> bool { matches!(self, Self::None) } } -#[cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#[cfg(feature="__rt_native__")] impl Response { #[cfg_attr(not(feature="sse"), inline)] pub(crate) async fn send(mut self, @@ -258,7 +258,7 @@ impl Response { Upgrade::None } - #[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] + #[cfg(all(feature="ws", feature="__rt_native__"))] Content::WebSocket((config, handler)) => { let mut buf = Vec::::with_capacity( self.status.line().len() + @@ -412,7 +412,7 @@ impl Response { } } -#[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] +#[cfg(all(feature="ws", feature="__rt_native__"))] impl Response { pub(crate) fn with_websocket(mut self, config: crate::ws::Config, @@ -446,7 +446,7 @@ const _: () = { DummyStream })), - #[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] + #[cfg(all(feature="ws", feature="__rt_native__"))] Content::WebSocket(_) => Content::WebSocket(( crate::ws::Config::default(), Box::new(|_| Box::pin(async {/* dummy handler */})) diff --git a/ohkami/src/response/status.rs b/ohkami/src/response/status.rs index df9375f2..5778d77b 100644 --- a/ohkami/src/response/status.rs +++ b/ohkami/src/response/status.rs @@ -24,7 +24,7 @@ macro_rules! status { $( Self::$name => $message, )* } } - #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] + #[cfg(feature="__rt_native__")] #[inline(always)] pub(crate) const fn line(&self) -> &'static [u8] { match self { $( Self::$name => concat!("HTTP/1.1 ", $message, "\r\n").as_bytes(), )* diff --git a/ohkami/src/session/mod.rs b/ohkami/src/session/mod.rs index f9b86216..23530304 100644 --- a/ohkami/src/session/mod.rs +++ b/ohkami/src/session/mod.rs @@ -1,4 +1,4 @@ -#![cfg(any(feature="rt_tokio",feature="rt_async-std"))] +#![cfg(feature="__rt_native__")] use std::{any::Any, pin::Pin, sync::Arc, time::Duration}; use std::panic::{AssertUnwindSafe, catch_unwind}; @@ -14,7 +14,6 @@ mod env { use std::sync::OnceLock; - #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] pub(crate) fn OHKAMI_KEEPALIVE_TIMEOUT() -> u64 { static OHKAMI_KEEPALIVE_TIMEOUT: OnceLock = OnceLock::new(); *OHKAMI_KEEPALIVE_TIMEOUT.get_or_init(|| { @@ -24,7 +23,7 @@ mod env { }) } - #[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] + #[cfg(feature="ws")] pub(crate) fn OHKAMI_WEBSOCKET_TIMEOUT() -> u64 { static OHKAMI_WEBSOCKET_TIMEOUT: OnceLock = OnceLock::new(); *OHKAMI_WEBSOCKET_TIMEOUT.get_or_init(|| { @@ -102,7 +101,7 @@ impl Session { crate::DEBUG!("about to shutdown connection"); } - #[cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] + #[cfg(feature="ws")] Some(Upgrade::WebSocket((config, handler))) => { use crate::ws::{Connection, Message, CloseFrame, CloseCode}; diff --git a/ohkami/src/ws/connection.rs b/ohkami/src/ws/connection.rs index f147675e..e21b0d01 100644 --- a/ohkami/src/ws/connection.rs +++ b/ohkami/src/ws/connection.rs @@ -5,7 +5,7 @@ use crate::__rt__::{AsyncWriter, AsyncReader}; /// WebSocket connection -pub struct Connection { +pub struct Connection { conn: Arc>, config: Config, n_buffered: usize, @@ -15,10 +15,10 @@ pub struct Connection { enum State { Alive, Closed } const _: () = { + #[cfg(any(feature="rt_tokio",feature="rt_async-std"))] unsafe impl Send for Connection {} - unsafe impl Sync for Connection {} - impl std::fmt::Debug for Connection { + impl std::fmt::Debug for Connection { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let (state, underlying) = unsafe {&*self.conn.get()}; f.debug_struct("Connection") @@ -29,7 +29,7 @@ const _: () = { .finish() } } - impl Clone for Connection { + impl Clone for Connection { fn clone(&self) -> Self { Connection { conn: Arc::clone(&self.conn), @@ -39,7 +39,7 @@ const _: () = { } } - impl Connection { + impl Connection { pub(crate) fn new(conn: Conn, config: Config) -> Self { let conn = Arc::new(UnsafeCell::new((State::Alive, conn))); Self { conn, config, n_buffered:0 } @@ -107,7 +107,7 @@ pub(super) async fn flush( } // ============================================================================= -impl Connection { +impl Connection { /// Recieve a WebSocket message. /// /// *note* : this automatically responds to a ping message diff --git a/ohkami/src/ws/mod.rs b/ohkami/src/ws/mod.rs index 5785df17..b9c0e521 100644 --- a/ohkami/src/ws/mod.rs +++ b/ohkami/src/ws/mod.rs @@ -1,4 +1,4 @@ -#![cfg(all(feature="ws", any(feature="rt_tokio",feature="rt_async-std")))] +#![cfg(all(feature="ws", feature="__rt_native__"))] mod connection; mod message;