Browse Source

[xitca-web] add bench for async orm (#9287)

* [xitca-web] add bench for async orm

* dep fix

* use release build of xitca-postgres

* fix framework naming

* dep update

* fix build

* add unrealistic db impl

* dedup

* improve compile time

* update to pre-release version of xitca-web
fakeshadow 10 months ago
parent
commit
8d4f5ed1ed

+ 274 - 302
frameworks/Rust/xitca-web/Cargo.lock

@@ -1,12 +1,12 @@
 # This file is automatically @generated by Cargo.
 # It is not intended for manual editing.
-version = 3
+version = 4
 
 [[package]]
 name = "addr2line"
-version = "0.24.1"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
+checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
 dependencies = [
  "gimli",
 ]
@@ -19,9 +19,9 @@ checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
 
 [[package]]
 name = "async-trait"
-version = "0.1.82"
+version = "0.1.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
+checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -39,59 +39,9 @@ dependencies = [
 
 [[package]]
 name = "autocfg"
-version = "1.3.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
-
-[[package]]
-name = "axum"
-version = "0.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf"
-dependencies = [
- "async-trait",
- "axum-core",
- "bytes",
- "futures-util",
- "http",
- "http-body",
- "http-body-util",
- "itoa",
- "matchit",
- "memchr",
- "mime",
- "percent-encoding",
- "pin-project-lite",
- "rustversion",
- "serde",
- "serde_json",
- "serde_path_to_error",
- "serde_urlencoded",
- "sync_wrapper 1.0.1",
- "tower",
- "tower-layer",
- "tower-service",
-]
-
-[[package]]
-name = "axum-core"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3"
-dependencies = [
- "async-trait",
- "bytes",
- "futures-util",
- "http",
- "http-body",
- "http-body-util",
- "mime",
- "pin-project-lite",
- "rustversion",
- "sync_wrapper 0.1.2",
- "tower-layer",
- "tower-service",
-]
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
 
 [[package]]
 name = "backtrace"
@@ -114,6 +64,18 @@ version = "0.22.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
 
+[[package]]
+name = "bb8"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b10cf871f3ff2ce56432fddc2615ac7acc3aa22ca321f8fea800846fbb32f188"
+dependencies = [
+ "async-trait",
+ "futures-util",
+ "parking_lot",
+ "tokio",
+]
+
 [[package]]
 name = "bitflags"
 version = "1.3.2"
@@ -135,6 +97,12 @@ dependencies = [
  "generic-array",
 ]
 
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
 [[package]]
 name = "byteorder"
 version = "1.5.0"
@@ -143,15 +111,15 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
-version = "1.7.1"
+version = "1.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
+checksum = "428d9aa8fbc0670b7b8d6030a7fadd0f86151cae55e4dbbece15f3780a3dfaf3"
 
 [[package]]
 name = "cc"
-version = "1.1.18"
+version = "1.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
+checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938"
 dependencies = [
  "shlex",
 ]
@@ -230,6 +198,20 @@ dependencies = [
  "r2d2",
 ]
 
+[[package]]
+name = "diesel-async"
+version = "0.5.0"
+source = "git+https://github.com/weiznich/diesel_async?rev=5b8262b#5b8262b86d8ed0e13adbbc4aee39500b9931ef8d"
+dependencies = [
+ "async-trait",
+ "bb8",
+ "diesel",
+ "futures-util",
+ "scoped-futures",
+ "tokio",
+ "tokio-postgres",
+]
+
 [[package]]
 name = "diesel_derives"
 version = "2.2.3"
@@ -289,18 +271,6 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
 
-[[package]]
-name = "filetime"
-version = "0.2.25"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586"
-dependencies = [
- "cfg-if",
- "libc",
- "libredox",
- "windows-sys 0.59.0",
-]
-
 [[package]]
 name = "fnv"
 version = "1.0.7"
@@ -316,12 +286,39 @@ dependencies = [
  "percent-encoding",
 ]
 
+[[package]]
+name = "futures-channel"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
 [[package]]
 name = "futures-core"
 version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
 
+[[package]]
+name = "futures-macro"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+
 [[package]]
 name = "futures-task"
 version = "0.3.30"
@@ -335,6 +332,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
 dependencies = [
  "futures-core",
+ "futures-macro",
+ "futures-sink",
  "futures-task",
  "pin-project-lite",
  "pin-utils",
@@ -364,9 +363,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.31.0"
+version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
+checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
 
 [[package]]
 name = "heck"
@@ -389,15 +388,6 @@ dependencies = [
  "digest",
 ]
 
-[[package]]
-name = "home"
-version = "0.5.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
-dependencies = [
- "windows-sys 0.52.0",
-]
-
 [[package]]
 name = "http"
 version = "1.1.0"
@@ -409,34 +399,11 @@ dependencies = [
  "itoa",
 ]
 
-[[package]]
-name = "http-body"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
-dependencies = [
- "bytes",
- "http",
-]
-
-[[package]]
-name = "http-body-util"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
-dependencies = [
- "bytes",
- "futures-util",
- "http",
- "http-body",
- "pin-project-lite",
-]
-
 [[package]]
 name = "httparse"
-version = "1.9.4"
+version = "1.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9"
+checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
 
 [[package]]
 name = "httpdate"
@@ -472,11 +439,20 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8"
 
+[[package]]
+name = "js-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+dependencies = [
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "libc"
-version = "0.2.158"
+version = "0.2.159"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
+checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
 
 [[package]]
 name = "libmimalloc-sys"
@@ -488,17 +464,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "libredox"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
-dependencies = [
- "bitflags 2.6.0",
- "libc",
- "redox_syscall",
-]
-
 [[package]]
 name = "lock_api"
 version = "0.4.12"
@@ -515,12 +480,6 @@ version = "0.4.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
 
-[[package]]
-name = "matchit"
-version = "0.7.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
-
 [[package]]
 name = "md-5"
 version = "0.10.6"
@@ -546,12 +505,6 @@ dependencies = [
  "libmimalloc-sys",
 ]
 
-[[package]]
-name = "mime"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
-
 [[package]]
 name = "miniz_oxide"
 version = "0.8.0"
@@ -569,7 +522,7 @@ dependencies = [
  "hermit-abi",
  "libc",
  "wasi",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -583,18 +536,21 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.36.4"
+version = "0.36.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
+checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.19.0"
+version = "1.20.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "82881c4be219ab5faaf2ad5e5e5ecdff8c66bd7402ca3160975c93b24961afd1"
+dependencies = [
+ "portable-atomic",
+]
 
 [[package]]
 name = "parking_lot"
@@ -643,26 +599,6 @@ dependencies = [
  "siphasher",
 ]
 
-[[package]]
-name = "pin-project"
-version = "1.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
-dependencies = [
- "pin-project-internal",
-]
-
-[[package]]
-name = "pin-project-internal"
-version = "1.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
 [[package]]
 name = "pin-project-lite"
 version = "0.2.14"
@@ -675,6 +611,12 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
+[[package]]
+name = "portable-atomic"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
+
 [[package]]
 name = "postgres-protocol"
 version = "0.6.7"
@@ -695,9 +637,9 @@ dependencies = [
 
 [[package]]
 name = "postgres-types"
-version = "0.2.7"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02048d9e032fb3cc3413bbf7b83a15d84a5d419778e2628751896d856498eee9"
+checksum = "f66ea23a2d0e5734297357705193335e0a957696f34bed2f2faefacb2fec336f"
 dependencies = [
  "bytes",
  "fallible-iterator",
@@ -715,9 +657,9 @@ dependencies = [
 
 [[package]]
 name = "pq-sys"
-version = "0.6.2"
+version = "0.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a92c30dd81695321846d4dfe348da67b1752ebb61cd1549d203a7b57e323c435"
+checksum = "f6cc05d7ea95200187117196eee9edd0644424911821aeb28a18ce60ea0b8793"
 dependencies = [
  "vcpkg",
 ]
@@ -783,9 +725,9 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.4"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
+checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
 dependencies = [
  "bitflags 2.6.0",
 ]
@@ -796,12 +738,6 @@ version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
-[[package]]
-name = "rustversion"
-version = "1.0.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
-
 [[package]]
 name = "ryu"
 version = "1.0.18"
@@ -816,41 +752,26 @@ checksum = "d4d5cd6d4f24f3ab107e949ab424738cf55b03deddce3b184c46985d7b1394ef"
 dependencies = [
  "itoap",
  "ryu",
- "sailfish-macros",
  "version_check",
 ]
 
 [[package]]
-name = "sailfish-compiler"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7254ec7b3651f7f723a9073153f5dcddc1f2bf1bf8d1b23ac71c236ef6360d2b"
-dependencies = [
- "filetime",
- "home",
- "memchr",
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "sailfish-macros"
-version = "0.9.0"
+name = "scheduled-thread-pool"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00812289fe1891c191cc2d9db461352fc410619e07ec2bb748faaa06412619d0"
+checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19"
 dependencies = [
- "proc-macro2",
- "sailfish-compiler",
+ "parking_lot",
 ]
 
 [[package]]
-name = "scheduled-thread-pool"
-version = "0.2.7"
+name = "scoped-futures"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19"
+checksum = "b1473e24c637950c9bd38763220bea91ec3e095a89f672bbd7a10d03e77ba467"
 dependencies = [
- "parking_lot",
+ "cfg-if",
+ "pin-utils",
 ]
 
 [[package]]
@@ -891,16 +812,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "serde_path_to_error"
-version = "0.1.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6"
-dependencies = [
- "itoa",
- "serde",
-]
-
 [[package]]
 name = "serde_urlencoded"
 version = "0.7.1"
@@ -977,7 +888,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys",
 ]
 
 [[package]]
@@ -1005,27 +916,15 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
 
 [[package]]
 name = "syn"
-version = "2.0.77"
+version = "2.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
+checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-ident",
 ]
 
-[[package]]
-name = "sync_wrapper"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
-
-[[package]]
-name = "sync_wrapper"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394"
-
 [[package]]
 name = "tinyvec"
 version = "1.8.0"
@@ -1048,13 +947,40 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
 dependencies = [
  "backtrace",
+ "bytes",
  "libc",
  "mio",
  "parking_lot",
  "pin-project-lite",
  "signal-hook-registry",
  "socket2 0.5.7",
- "windows-sys 0.52.0",
+ "windows-sys",
+]
+
+[[package]]
+name = "tokio-postgres"
+version = "0.7.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b5d3742945bc7d7f210693b0c58ae542c6fd47b17adbbda0885f3dcb34a6bdb"
+dependencies = [
+ "async-trait",
+ "byteorder",
+ "bytes",
+ "fallible-iterator",
+ "futures-channel",
+ "futures-util",
+ "log",
+ "parking_lot",
+ "percent-encoding",
+ "phf",
+ "pin-project-lite",
+ "postgres-protocol",
+ "postgres-types",
+ "rand",
+ "socket2 0.5.7",
+ "tokio",
+ "tokio-util",
+ "whoami",
 ]
 
 [[package]]
@@ -1073,55 +999,24 @@ dependencies = [
 ]
 
 [[package]]
-name = "tower"
-version = "0.4.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
-dependencies = [
- "futures-core",
- "futures-util",
- "pin-project",
- "pin-project-lite",
- "tower-layer",
- "tower-service",
- "tracing",
-]
-
-[[package]]
-name = "tower-http"
-version = "0.5.2"
+name = "tokio-util"
+version = "0.7.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
+checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
 dependencies = [
- "bitflags 2.6.0",
  "bytes",
- "http",
- "http-body",
- "http-body-util",
+ "futures-core",
+ "futures-sink",
  "pin-project-lite",
- "tower-layer",
- "tower-service",
+ "tokio",
 ]
 
-[[package]]
-name = "tower-layer"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
-
-[[package]]
-name = "tower-service"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
-
 [[package]]
 name = "tracing"
 version = "0.1.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
 dependencies = [
- "log",
  "pin-project-lite",
  "tracing-core",
 ]
@@ -1131,9 +1026,6 @@ name = "tracing-core"
 version = "0.1.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
-dependencies = [
- "once_cell",
-]
 
 [[package]]
 name = "typenum"
@@ -1143,9 +1035,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.15"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
 
 [[package]]
 name = "unicode-ident"
@@ -1155,18 +1047,18 @@ checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
 
 [[package]]
 name = "unicode-normalization"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
+checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
 dependencies = [
  "tinyvec",
 ]
 
 [[package]]
 name = "unicode-properties"
-version = "0.1.2"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524"
+checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
 
 [[package]]
 name = "vcpkg"
@@ -1186,6 +1078,88 @@ version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
+[[package]]
+name = "wasite"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.93"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+
+[[package]]
+name = "web-sys"
+version = "0.3.70"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "whoami"
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d"
+dependencies = [
+ "redox_syscall",
+ "wasite",
+ "web-sys",
+]
+
 [[package]]
 name = "winapi"
 version = "0.3.9"
@@ -1217,15 +1191,6 @@ dependencies = [
  "windows-targets",
 ]
 
-[[package]]
-name = "windows-sys"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-dependencies = [
- "windows-targets",
-]
-
 [[package]]
 name = "windows-targets"
 version = "0.52.6"
@@ -1292,9 +1257,8 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "xitca-codegen"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "336b646a30e6d44093beaae1bbe5dda664e8466d387663fc9d61c55fb2d78424"
+version = "0.4.0"
+source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6"
 dependencies = [
  "quote",
  "syn",
@@ -1302,9 +1266,8 @@ dependencies = [
 
 [[package]]
 name = "xitca-http"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47b5b036e32261c69d4f0e81bcb28c2e058ed569518959336fd75fc086208d3f"
+version = "0.7.0"
+source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6"
 dependencies = [
  "futures-core",
  "http",
@@ -1336,12 +1299,13 @@ dependencies = [
 
 [[package]]
 name = "xitca-postgres"
-version = "0.1.0"
-source = "git+https://github.com/HFQR/xitca-web.git?rev=0cda225#0cda2254f98b40f21bc3170dd8983f16444f0bd0"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46046cb7a3d4fcfb5c858bab0651c73bb45c0c5f9f0f53dd4eb991f2d6e5d6f4"
 dependencies = [
  "fallible-iterator",
+ "futures-core",
  "percent-encoding",
- "phf",
  "postgres-protocol",
  "postgres-types",
  "tokio",
@@ -1350,6 +1314,19 @@ dependencies = [
  "xitca-unsafe-collection",
 ]
 
+[[package]]
+name = "xitca-postgres-diesel"
+version = "0.1.0"
+source = "git+https://github.com/fakeshadow/xitca-postgres-diesel?rev=ae93ee9#ae93ee95277e281fb87b351c42bfc2fc5a56703a"
+dependencies = [
+ "diesel",
+ "diesel-async",
+ "futures-core",
+ "scoped-futures",
+ "tokio",
+ "xitca-postgres",
+]
+
 [[package]]
 name = "xitca-router"
 version = "0.3.0"
@@ -1361,9 +1338,8 @@ dependencies = [
 
 [[package]]
 name = "xitca-server"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a40a05f18780f1de843c5077583e4650b08d0518fcf9cf7948e28bc92e489736"
+version = "0.5.0"
+source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6"
 dependencies = [
  "socket2 0.5.7",
  "tokio",
@@ -1376,9 +1352,8 @@ dependencies = [
 
 [[package]]
 name = "xitca-service"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74b093ca75b264924773d53e445de08a937100bf1cbe4f62d4dc2c0d04a3ba4b"
+version = "0.3.0"
+source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6"
 
 [[package]]
 name = "xitca-unsafe-collection"
@@ -1394,42 +1369,39 @@ name = "xitca-web"
 version = "0.1.0"
 dependencies = [
  "atoi",
- "axum",
  "diesel",
+ "diesel-async",
  "futures-core",
- "http-body",
+ "futures-util",
+ "httparse",
  "mimalloc",
  "rand",
  "sailfish",
  "serde",
  "serde_json",
  "tokio",
- "tower",
- "tower-http",
+ "tokio-uring",
  "xitca-http",
  "xitca-io",
  "xitca-postgres",
+ "xitca-postgres-diesel",
  "xitca-server",
  "xitca-service",
  "xitca-unsafe-collection",
- "xitca-web 0.6.2",
+ "xitca-web 0.7.0",
 ]
 
 [[package]]
 name = "xitca-web"
-version = "0.6.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd4f8f16791ea2a8845f617f1e87887f917835e0603d01f03a51e638b9613d0c"
+version = "0.7.0"
+source = "git+http://github.com/HFQR/xitca-web?rev=d3066ba#d3066ba5fc65e89c8a20890dd529f05818c853d6"
 dependencies = [
  "futures-core",
- "http-body",
  "pin-project-lite",
  "serde",
  "serde_json",
  "serde_urlencoded",
  "tokio",
- "tower-layer",
- "tower-service",
  "xitca-codegen",
  "xitca-http",
  "xitca-server",

+ 35 - 26
frameworks/Rust/xitca-web/Cargo.toml

@@ -19,9 +19,9 @@ path = "./src/main_wasm.rs"
 required-features = ["web"]
 
 [[bin]]
-name = "xitca-web-axum"
-path = "./src/main_axum.rs"
-required-features = ["axum", "io-uring", "perf", "pg-sync", "template"]
+name = "xitca-web-orm"
+path = "./src/main_orm.rs"
+required-features = ["pg-orm-async", "template", "web-codegen"]
 
 [[bin]]
 name = "xitca-web-sync"
@@ -29,55 +29,56 @@ path = "./src/main_sync.rs"
 required-features = ["pg-orm", "template", "web-codegen"]
 
 [features]
-# pg optional
+# pg client optional
 pg = ["dep:xitca-postgres"]
-# pg send/sync optional
-pg-sync = ["dep:xitca-postgres"]
-# pg orm optional
-pg-orm = ["dep:diesel"]
+# diesel orm optional
+pg-orm = ["diesel/r2d2"]
+# diesel async orm optional
+pg-orm-async = ["dep:diesel", "dep:diesel-async", "dep:xitca-postgres-diesel", "futures-util"]
 # http router optional
 router = ["xitca-http/router"]
 # web optional
 web = ["dep:xitca-web"]
-# web codegen optional
+# web with macros optional
 web-codegen = ["xitca-web/codegen", "xitca-web/urlencoded"]
 # template optional
 template = ["dep:sailfish"]
 # io-uring optional
-io-uring = ["xitca-http/io-uring", "xitca-server/io-uring"]
-# axum optional
-axum = ["dep:axum", "dep:http-body", "dep:tower", "dep:tower-http", "xitca-web/tower-http-compat" ]
+io-uring = ["dep:tokio-uring", "xitca-http/io-uring", "xitca-server/io-uring"]
 # unrealistic performance optimization
 perf = ["dep:mimalloc", "tokio/parking_lot"]
 
 [dependencies]
-xitca-http = "0.6"
-xitca-io = "0.4"
-xitca-server = "0.4"
-xitca-service = "0.2"
+xitca-http = "0.7"
+xitca-io = "0.4.1"
+xitca-server = "0.5"
+xitca-service = "0.3"
 xitca-unsafe-collection = "0.2"
 
 atoi = "2"
+httparse = "1"
 serde = { version = "1" }
 serde_json = { version = "1" }
 
 # web optional
-xitca-web = { version = "0.6", features = ["json"], optional = true }
+xitca-web = { version = "0.7", features = ["json"], optional = true }
 
 # raw-pg optional
-xitca-postgres = { version = "0.1", optional = true }
+xitca-postgres = { version = "0.2", optional = true }
 
 # orm optional
-diesel = { version = "2", features = ["postgres", "r2d2"], optional = true }
+diesel = { version = "2", features = ["postgres"], optional = true }
+
+# orm async optional
+diesel-async = { version = "0.5", features = ["bb8", "postgres"], optional = true }
+xitca-postgres-diesel = { version = "0.1", optional = true }
+futures-util = { version = "0.3", default-features = false, optional = true }
 
 # template optional
-sailfish = { version = "0.9", default-features = false, features = ["derive", "perf-inline"], optional = true }
+sailfish = { version = "0.9", default-features = false, features = ["perf-inline"], optional = true }
 
-# axum optional
-axum = { version = "0.7", optional = true, default-features = false, features = ["json", "query"] }
-http-body = { version = "1", optional = true }
-tower = { version = "0.4", optional = true }
-tower-http = { version = "0.5", features = ["set-header"], optional = true }
+# io-uring optional
+tokio-uring = { version = "0.5", optional = true }
 
 # perf optional
 mimalloc = { version = "0.1", default-features = false, optional = true }
@@ -95,5 +96,13 @@ codegen-units = 1
 panic = "abort"
 
 [patch.crates-io]
-xitca-postgres = { git = "https://github.com/HFQR/xitca-web.git", rev = "0cda225" }
+xitca-postgres-diesel = { git = "https://github.com/fakeshadow/xitca-postgres-diesel", rev = "ae93ee9" }
+
+diesel-async = { git = "https://github.com/weiznich/diesel_async", rev = "5b8262b" }
 mio = { git = "https://github.com/fakeshadow/mio", rev = "9bae6012b7ecfc6083350785f71a5e8265358178" }
+
+xitca-codegen = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" }
+xitca-http = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" }
+xitca-server = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" }
+xitca-service = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" }
+xitca-web = { git = "http://github.com/HFQR/xitca-web", rev = "d3066ba" }

+ 9 - 9
frameworks/Rust/xitca-web/benchmark_config.json

@@ -35,14 +35,14 @@
         "approach": "Stripped",
         "classification": "Platform",
         "database": "Postgres",
-        "framework": "xitca-web [unrealistic]",
+        "framework": "xitca-web",
         "language": "Rust",
         "orm": "Raw",
         "platform": "None",
         "webserver": "xitca-server",
         "os": "Linux",
         "database_os": "Linux",
-        "display_name": "xitca-web [unrealistic]",
+        "display_name": "xitca-web [iou]",
         "notes": "",
         "versus": ""
       },
@@ -53,7 +53,7 @@
         "approach": "Realistic",
         "classification": "Micro",
         "database": "none",
-        "framework": "xitca-web [wasm]",
+        "framework": "xitca-web",
         "language": "rust",
         "orm": "raw",
         "platform": "none",
@@ -64,7 +64,7 @@
         "notes": "",
         "versus": ""
       },
-      "axum": {
+      "orm": {
         "json_url": "/json",
         "plaintext_url": "/plaintext",
         "db_url": "/db",
@@ -73,16 +73,16 @@
         "update_url": "/updates?q=",
         "port": 8080,
         "approach": "realistic",
-        "classification": "micro",
+        "classification": "fullstack",
         "database": "postgres",
-        "framework": "axum [xitca]",
+        "framework": "xitca-web",
         "language": "rust",
-        "orm": "raw",
+        "orm": "full",
         "platform": "none",
         "webserver": "xitca-server",
         "os": "linux",
         "database_os": "linux",
-        "display_name": "axum [xitca]",
+        "display_name": "xitca-web [orm]",
         "notes": "",
         "versus": ""
       },
@@ -97,7 +97,7 @@
         "approach": "realistic",
         "classification": "micro",
         "database": "postgres",
-        "framework": "xitca-web [sync]",
+        "framework": "xitca-web",
         "language": "rust",
         "orm": "full",
         "platform": "none",

+ 37 - 106
frameworks/Rust/xitca-web/src/db.rs

@@ -1,101 +1,63 @@
-// clippy is dumb and have no idea what should be lazy or not
-#![allow(clippy::unnecessary_lazy_evaluations)]
+#[path = "./db_util.rs"]
+mod db_util;
 
-use xitca_io::bytes::BytesMut;
-use xitca_postgres::{pipeline::Pipeline, pool::Pool, AsyncLendingIterator, Type};
+use std::cell::RefCell;
+
+use xitca_postgres::{
+    iter::AsyncLendingIterator, pipeline::Pipeline, pool::Pool, statement::Statement, Execute, ExecuteMut,
+};
 
 use super::{
     ser::{Fortune, Fortunes, World},
-    util::{bulk_update_gen, HandleResult, Rand, DB_URL},
+    util::{HandleResult, DB_URL},
 };
 
+use db_util::{sort_update_params, update_query, Shared, FORTUNE_STMT, WORLD_STMT};
+
 pub struct Client {
     pool: Pool,
-    #[cfg(not(feature = "pg-sync"))]
-    shared: std::cell::RefCell<Shared>,
-    #[cfg(feature = "pg-sync")]
-    shared: std::sync::Mutex<Shared>,
+    shared: RefCell<Shared>,
     updates: Box<[Box<str>]>,
 }
 
-type Shared = (Rand, BytesMut);
-
-const FORTUNE_SQL: &str = "SELECT * FROM fortune";
-
-const FORTUNE_SQL_TYPES: &[Type] = &[];
-
-const WORLD_SQL: &str = "SELECT * FROM world WHERE id=$1";
-
-const WORLD_SQL_TYPES: &[Type] = &[Type::INT4];
-
-fn update_query(num: usize) -> Box<str> {
-    bulk_update_gen(|query| {
-        use std::fmt::Write;
-        (1..=num).fold((1, query), |(idx, query), _| {
-            write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap();
-            (idx + 2, query)
-        });
-    })
-    .into_boxed_str()
-}
-
 pub async fn create() -> HandleResult<Client> {
-    let pool = Pool::builder(DB_URL).capacity(1).build()?;
-
-    let shared = (Rand::default(), BytesMut::new());
-
-    let updates = core::iter::once(Box::from(""))
-        .chain((1..=500).map(update_query))
-        .collect();
-
     Ok(Client {
-        pool,
-        #[cfg(not(feature = "pg-sync"))]
-        shared: std::cell::RefCell::new(shared),
-        #[cfg(feature = "pg-sync")]
-        shared: std::sync::Mutex::new(shared),
-        updates,
+        pool: Pool::builder(DB_URL).capacity(1).build()?,
+        shared: Default::default(),
+        updates: core::iter::once(Box::from(""))
+            .chain((1..=500).map(update_query))
+            .collect(),
     })
 }
 
 impl Client {
-    #[cfg(not(feature = "pg-sync"))]
-    fn shared(&self) -> std::cell::RefMut<'_, Shared> {
-        self.shared.borrow_mut()
-    }
-
-    #[cfg(feature = "pg-sync")]
-    fn shared(&self) -> std::sync::MutexGuard<'_, Shared> {
-        self.shared.lock().unwrap()
-    }
-
     pub async fn get_world(&self) -> HandleResult<World> {
         let mut conn = self.pool.get().await?;
-        let stmt = conn.prepare(WORLD_SQL, WORLD_SQL_TYPES).await?;
-        let id = self.shared().0.gen_id();
-        let mut res = conn.consume().query_raw(&stmt, [id])?;
-        let row = res.try_next().await?.ok_or_else(|| "World does not exist")?;
-        Ok(World::new(row.get_raw(0), row.get_raw(1)))
+        let stmt = WORLD_STMT.execute_mut(&mut conn).await?;
+        let id = self.shared.borrow_mut().0.gen_id();
+        let mut res = stmt.bind([id]).query(&conn.consume()).await?;
+        let row = res.try_next().await?.ok_or("request World does not exist")?;
+        Ok(World::new(row.get(0), row.get(1)))
     }
 
     pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
         let len = num as usize;
 
         let mut conn = self.pool.get().await?;
-        let stmt = conn.prepare(WORLD_SQL, WORLD_SQL_TYPES).await?;
+        let stmt = WORLD_STMT.execute_mut(&mut conn).await?;
 
         let mut res = {
-            let (ref mut rng, ref mut buf) = *self.shared();
+            let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
             let mut pipe = Pipeline::with_capacity_from_buf(len, buf);
-            (0..num).try_for_each(|_| pipe.query_raw(&stmt, [rng.gen_id()]))?;
-            conn.consume().pipeline(pipe)?
+            (0..num).try_for_each(|_| stmt.bind([rng.gen_id()]).query_mut(&mut pipe))?;
+            pipe.query(&conn.consume())?
         };
 
         let mut worlds = Vec::with_capacity(len);
 
         while let Some(mut item) = res.try_next().await? {
             while let Some(row) = item.try_next().await? {
-                worlds.push(World::new(row.get_raw(0), row.get_raw(1)))
+                worlds.push(World::new(row.get(0), row.get(1)))
             }
         }
 
@@ -105,25 +67,24 @@ impl Client {
     pub async fn update(&self, num: u16) -> HandleResult<Vec<World>> {
         let len = num as usize;
 
-        let update = self.updates.get(len).ok_or_else(|| "num out of bound")?;
-
+        let update = self.updates.get(len).ok_or("request num is out of range")?;
         let mut conn = self.pool.get().await?;
-        let world_stmt = conn.prepare(WORLD_SQL, WORLD_SQL_TYPES).await?;
-        let update_stmt = conn.prepare(update, &[]).await?;
+        let world_stmt = WORLD_STMT.execute_mut(&mut conn).await?;
+        let update_stmt = Statement::named(update, &[]).execute_mut(&mut conn).await?;
 
         let mut params = Vec::with_capacity(len);
 
         let mut res = {
-            let (ref mut rng, ref mut buf) = *self.shared();
+            let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
             let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf);
             (0..num).try_for_each(|_| {
                 let w_id = rng.gen_id();
                 let r_id = rng.gen_id();
                 params.push([w_id, r_id]);
-                pipe.query_raw(&world_stmt, [w_id])
+                world_stmt.bind([w_id]).query_mut(&mut pipe)
             })?;
-            pipe.query_raw(&update_stmt, sort_update_params(&params))?;
-            conn.consume().pipeline(pipe)?
+            update_stmt.bind(sort_update_params(&params)).query_mut(&mut pipe)?;
+            pipe.query(&conn.consume())?
         };
 
         let mut worlds = Vec::with_capacity(len);
@@ -133,7 +94,7 @@ impl Client {
         while let Some(mut item) = res.try_next().await? {
             while let Some(row) = item.try_next().await? {
                 let r_id = r_ids.next().unwrap()[1];
-                worlds.push(World::new(row.get_raw(0), r_id))
+                worlds.push(World::new(row.get(0), r_id))
             }
         }
 
@@ -145,11 +106,11 @@ impl Client {
         items.push(Fortune::new(0, "Additional fortune added at request time."));
 
         let mut conn = self.pool.get().await?;
-        let stmt = conn.prepare(FORTUNE_SQL, FORTUNE_SQL_TYPES).await?;
-        let mut res = conn.consume().query_raw::<[i32; 0]>(&stmt, [])?;
+        let stmt = FORTUNE_STMT.execute_mut(&mut conn).await?;
+        let mut res = stmt.query(&conn.consume()).await?;
 
         while let Some(row) = res.try_next().await? {
-            items.push(Fortune::new(row.get_raw(0), row.get_raw::<String>(1)));
+            items.push(Fortune::new(row.get(0), row.get::<String>(1)));
         }
 
         items.sort_by(|it, next| it.message.cmp(&next.message));
@@ -157,33 +118,3 @@ impl Client {
         Ok(Fortunes::new(items))
     }
 }
-
-fn sort_update_params(params: &[[i32; 2]]) -> impl ExactSizeIterator<Item = i32> {
-    let mut params = params.to_owned();
-    params.sort_by(|a, b| a[0].cmp(&b[0]));
-
-    struct ParamIter<I>(I);
-
-    impl<I> Iterator for ParamIter<I>
-    where
-        I: Iterator,
-    {
-        type Item = I::Item;
-
-        #[inline]
-        fn next(&mut self) -> Option<Self::Item> {
-            self.0.next()
-        }
-
-        #[inline]
-        fn size_hint(&self) -> (usize, Option<usize>) {
-            self.0.size_hint()
-        }
-    }
-
-    // impl depends on compiler optimization to flat Vec<[T]> to Vec<T> when inferring
-    // it's size hint. possible to cause runtime panic.
-    impl<I> ExactSizeIterator for ParamIter<I> where I: Iterator {}
-
-    ParamIter(params.into_iter().flatten())
-}

+ 153 - 0
frameworks/Rust/xitca-web/src/db_diesel_async.rs

@@ -0,0 +1,153 @@
+use std::{
+    io,
+    sync::{Arc, Mutex},
+};
+
+use diesel::prelude::*;
+use diesel_async::{
+    pooled_connection::{bb8, AsyncDieselConnectionManager},
+    RunQueryDsl,
+};
+use futures_util::{
+    future::join,
+    stream::{FuturesUnordered, TryStreamExt},
+};
+use xitca_postgres_diesel::AsyncPgConnection;
+
+use crate::{
+    ser::{Fortune, Fortunes, World},
+    util::{bulk_update_gen, Error, HandleResult, Rand, DB_URL},
+};
+
+pub type Pool = Arc<_Pool>;
+
+pub struct _Pool {
+    pool: bb8::Pool<AsyncPgConnection>,
+    rng: Mutex<Rand>,
+}
+
+pub async fn create() -> io::Result<Arc<_Pool>> {
+    bb8::Pool::builder()
+        .max_size(1)
+        .min_idle(Some(1))
+        .test_on_check_out(false)
+        .build(AsyncDieselConnectionManager::new(DB_URL))
+        .await
+        .map_err(io::Error::other)
+        .map(|pool| {
+            Arc::new(_Pool {
+                pool,
+                rng: Mutex::new(Rand::default()),
+            })
+        })
+}
+
+#[cold]
+#[inline(never)]
+fn not_found() -> Error {
+    "world not found".into()
+}
+
+impl _Pool {
+    pub async fn get_world(&self) -> HandleResult<World> {
+        use crate::schema::world::dsl::*;
+        {
+            let w_id = self.rng.lock().unwrap().gen_id();
+            let mut conn = self.pool.get().await?;
+            world.filter(id.eq(w_id)).load(&mut conn)
+        }
+        .await?
+        .pop()
+        .ok_or_else(not_found)
+    }
+
+    pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
+        use crate::schema::world::dsl::*;
+        {
+            let mut conn = self.pool.get().await?;
+            let mut rng = self.rng.lock().unwrap();
+            (0..num)
+                .map(|_| {
+                    let w_id = rng.gen_id();
+                    let fut = world.filter(id.eq(w_id)).load::<World>(&mut conn);
+                    async { fut.await?.pop().ok_or_else(not_found) }
+                })
+                .collect::<FuturesUnordered<_>>()
+        }
+        .try_collect()
+        .await
+    }
+
+    pub async fn update(&self, num: u16) -> HandleResult<Vec<World>> {
+        use crate::schema::world::dsl::*;
+
+        let mut rngs = Vec::with_capacity(num as _);
+
+        let (select_res, update_res) = {
+            let mut conn = self.pool.get().await?;
+
+            let mut rng = self.rng.lock().unwrap();
+
+            let select = (0..num)
+                .map(|_| {
+                    let w_id = rng.gen_id();
+                    let num = rng.gen_id();
+
+                    rngs.push((w_id, num));
+
+                    let fut = world.filter(id.eq(w_id)).load::<World>(&mut conn);
+
+                    async move {
+                        fut.await?
+                            .pop()
+                            .map(|mut w| {
+                                w.randomnumber = num;
+                                w
+                            })
+                            .ok_or_else(not_found)
+                    }
+                })
+                .collect::<FuturesUnordered<_>>();
+
+            rngs.sort_by(|(a, _), (b, _)| a.cmp(b));
+
+            let update = diesel::sql_query(update_query(&rngs)).execute(&mut conn);
+
+            join(select.try_collect::<Vec<_>>(), update)
+        }
+        .await;
+
+        update_res?;
+        let mut worlds = select_res?;
+
+        worlds.sort_by_key(|w| w.id);
+
+        Ok(worlds)
+    }
+
+    pub async fn tell_fortune(&self) -> HandleResult<Fortunes> {
+        use crate::schema::fortune::dsl::*;
+
+        let mut items = {
+            let mut conn = self.pool.get().await?;
+            fortune.load::<Fortune>(&mut conn)
+        }
+        .await?;
+
+        items.push(Fortune::new(0, "Additional fortune added at request time."));
+        items.sort_by(|it, next| it.message.cmp(&next.message));
+
+        Ok(Fortunes::new(items))
+    }
+}
+
+// diesel does not support high level bulk update api. use raw sql to bypass the limitation.
+// relate discussion: https://github.com/diesel-rs/diesel/discussions/2879
+fn update_query(ids: &[(i32, i32)]) -> String {
+    bulk_update_gen(|query| {
+        use std::fmt::Write;
+        ids.iter().for_each(|(w_id, num)| {
+            write!(query, "({}::int,{}::int),", w_id, num).unwrap();
+        });
+    })
+}

+ 130 - 0
frameworks/Rust/xitca-web/src/db_unrealistic.rs

@@ -0,0 +1,130 @@
+//! this module is unrealistic. related issue:
+//! https://github.com/TechEmpower/FrameworkBenchmarks/issues/8790
+
+#[path = "./db_util.rs"]
+mod db_util;
+
+use std::cell::RefCell;
+
+use xitca_postgres::{iter::AsyncLendingIterator, pipeline::Pipeline, statement::Statement, Execute, ExecuteMut};
+
+use super::{
+    ser::{Fortune, Fortunes, World},
+    util::{HandleResult, DB_URL},
+};
+
+use db_util::{sort_update_params, update_query, Shared, FORTUNE_STMT, WORLD_STMT};
+
+pub struct Client {
+    cli: xitca_postgres::Client,
+    shared: RefCell<Shared>,
+    fortune: Statement,
+    world: Statement,
+    updates: Box<[Statement]>,
+}
+
+pub async fn create() -> HandleResult<Client> {
+    let (cli, mut drv) = xitca_postgres::Postgres::new(DB_URL).connect().await?;
+
+    tokio::task::spawn(tokio::task::unconstrained(async move {
+        while drv.try_next().await?.is_some() {}
+        HandleResult::Ok(())
+    }));
+
+    let world = WORLD_STMT.execute(&cli).await?.leak();
+    let fortune = FORTUNE_STMT.execute(&cli).await?.leak();
+
+    let mut updates = vec![Statement::default()];
+
+    for update in (1..=500).map(update_query).into_iter() {
+        let stmt = Statement::named(&update, &[]).execute(&cli).await?.leak();
+        updates.push(stmt);
+    }
+
+    Ok(Client {
+        cli,
+        shared: Default::default(),
+        world,
+        fortune,
+        updates: updates.into_boxed_slice(),
+    })
+}
+
+impl Client {
+    pub async fn get_world(&self) -> HandleResult<World> {
+        let id = self.shared.borrow_mut().0.gen_id();
+        let mut res = self.world.bind([id]).query(&self.cli).await?;
+        let row = res.try_next().await?.ok_or("request World does not exist")?;
+        Ok(World::new(row.get(0), row.get(1)))
+    }
+
+    pub async fn get_worlds(&self, num: u16) -> HandleResult<Vec<World>> {
+        let len = num as usize;
+
+        let mut res = {
+            let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
+            let mut pipe = Pipeline::with_capacity_from_buf(len, buf);
+            (0..num).try_for_each(|_| self.world.bind([rng.gen_id()]).query_mut(&mut pipe))?;
+            pipe.query(&self.cli)?
+        };
+
+        let mut worlds = Vec::with_capacity(len);
+
+        while let Some(mut item) = res.try_next().await? {
+            while let Some(row) = item.try_next().await? {
+                worlds.push(World::new(row.get(0), row.get(1)))
+            }
+        }
+
+        Ok(worlds)
+    }
+
+    pub async fn update(&self, num: u16) -> HandleResult<Vec<World>> {
+        let len = num as usize;
+
+        let mut params = Vec::with_capacity(len);
+
+        let mut res = {
+            let (ref mut rng, ref mut buf) = *self.shared.borrow_mut();
+            let mut pipe = Pipeline::with_capacity_from_buf(len + 1, buf);
+            (0..num).try_for_each(|_| {
+                let w_id = rng.gen_id();
+                let r_id = rng.gen_id();
+                params.push([w_id, r_id]);
+                self.world.bind([w_id]).query_mut(&mut pipe)
+            })?;
+            self.updates[len]
+                .bind(sort_update_params(&params))
+                .query_mut(&mut pipe)?;
+            pipe.query(&self.cli)?
+        };
+
+        let mut worlds = Vec::with_capacity(len);
+
+        let mut r_ids = params.into_iter();
+
+        while let Some(mut item) = res.try_next().await? {
+            while let Some(row) = item.try_next().await? {
+                let r_id = r_ids.next().unwrap()[1];
+                worlds.push(World::new(row.get(0), r_id))
+            }
+        }
+
+        Ok(worlds)
+    }
+
+    pub async fn tell_fortune(&self) -> HandleResult<Fortunes> {
+        let mut items = Vec::with_capacity(32);
+        items.push(Fortune::new(0, "Additional fortune added at request time."));
+
+        let mut res = self.fortune.query(&self.cli).await?;
+
+        while let Some(row) = res.try_next().await? {
+            items.push(Fortune::new(row.get(0), row.get::<String>(1)));
+        }
+
+        items.sort_by(|it, next| it.message.cmp(&next.message));
+
+        Ok(Fortunes::new(items))
+    }
+}

+ 53 - 0
frameworks/Rust/xitca-web/src/db_util.rs

@@ -0,0 +1,53 @@
+use xitca_io::bytes::BytesMut;
+use xitca_postgres::{
+    statement::{Statement, StatementNamed},
+    types::Type,
+};
+
+use crate::util::{bulk_update_gen, Rand};
+
+pub(super) type Shared = (Rand, BytesMut);
+
+pub(super) const FORTUNE_STMT: StatementNamed = Statement::named("SELECT * FROM fortune", &[]);
+pub(super) const WORLD_STMT: StatementNamed = Statement::named("SELECT * FROM world WHERE id=$1", &[Type::INT4]);
+
+pub(super) fn update_query(num: usize) -> Box<str> {
+    bulk_update_gen(|query| {
+        use std::fmt::Write;
+        (1..=num).fold((1, query), |(idx, query), _| {
+            write!(query, "(${}::int,${}::int),", idx, idx + 1).unwrap();
+            (idx + 2, query)
+        });
+    })
+    .into_boxed_str()
+}
+
+pub(super) fn sort_update_params(params: &[[i32; 2]]) -> impl ExactSizeIterator<Item = i32> {
+    let mut params = params.to_owned();
+    params.sort_by(|a, b| a[0].cmp(&b[0]));
+
+    struct ParamIter<I>(I);
+
+    impl<I> Iterator for ParamIter<I>
+    where
+        I: Iterator,
+    {
+        type Item = I::Item;
+
+        #[inline]
+        fn next(&mut self) -> Option<Self::Item> {
+            self.0.next()
+        }
+
+        #[inline]
+        fn size_hint(&self) -> (usize, Option<usize>) {
+            self.0.size_hint()
+        }
+    }
+
+    // impl depends on compiler optimization to flat Vec<[T]> to Vec<T> when inferring
+    // it's size hint. possible to cause runtime panic.
+    impl<I> ExactSizeIterator for ParamIter<I> where I: Iterator {}
+
+    ParamIter(params.into_iter().flatten())
+}

+ 10 - 6
frameworks/Rust/xitca-web/src/main.rs

@@ -5,18 +5,22 @@ mod util;
 use xitca_http::{
     h1::RequestBody,
     http::{header::SERVER, StatusCode},
-    util::service::{
-        route::get,
-        router::{Router, RouterError},
+    util::{
+        middleware::context::{Context, ContextBuilder},
+        service::{
+            route::get,
+            router::{Router, RouterError},
+        },
     },
     HttpServiceBuilder,
 };
 use xitca_service::{fn_service, Service, ServiceExt};
 
+use db::Client;
 use ser::{error_response, IntoResponse, Message, Request, Response};
-use util::{context_mw, HandleResult, QueryParse, SERVER_HEADER_VALUE};
+use util::{HandleResult, QueryParse, State, SERVER_HEADER_VALUE};
 
-type Ctx<'a> = util::Ctx<'a, Request<RequestBody>>;
+type Ctx<'a> = Context<'a, Request<RequestBody>, State<Client>>;
 
 fn main() -> std::io::Result<()> {
     let service = Router::new()
@@ -27,7 +31,7 @@ fn main() -> std::io::Result<()> {
         .insert("/queries", get(fn_service(queries)))
         .insert("/updates", get(fn_service(updates)))
         .enclosed_fn(middleware)
-        .enclosed(context_mw())
+        .enclosed(ContextBuilder::new(|| async { db::create().await.map(State::new) }))
         .enclosed(HttpServiceBuilder::h1().io_uring());
     xitca_server::Builder::new()
         .bind("xitca-web", "0.0.0.0:8080", service)?

+ 0 - 150
frameworks/Rust/xitca-web/src/main_axum.rs

@@ -1,150 +0,0 @@
-//! show case of axum running on proper thread per core server with io-uring enabled.
-
-#[global_allocator]
-static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
-
-mod db;
-mod ser;
-mod util;
-
-use std::sync::Arc;
-
-use axum::{
-    extract::{Json, Query, State},
-    http::{
-        header::{HeaderValue, SERVER},
-        StatusCode,
-    },
-    response::{Html, IntoResponse, Response},
-    routing::{get, Router},
-};
-use tower_http::set_header::SetResponseHeaderLayer;
-
-use crate::{db::Client, ser::Num, tower_compat::TowerHttp};
-
-fn main() -> std::io::Result<()> {
-    let service = TowerHttp::service(|| async {
-        let cli = db::create().await?;
-        let service = Router::new()
-            .route("/plaintext", get(plain_text))
-            .route("/json", get(json))
-            .route("/db", get(db))
-            .route("/fortunes", get(fortunes))
-            .route("/queries", get(queries))
-            .route("/updates", get(updates))
-            .with_state(Arc::new(cli))
-            .layer(SetResponseHeaderLayer::if_not_present(
-                SERVER,
-                HeaderValue::from_static("A"),
-            ));
-        Ok(service)
-    });
-    xitca_server::Builder::new()
-        .bind("xitca-axum", "0.0.0.0:8080", service)?
-        .build()
-        .wait()
-}
-
-async fn plain_text() -> &'static str {
-    "Hello, World!"
-}
-
-async fn json() -> impl IntoResponse {
-    Json(ser::Message::new())
-}
-
-async fn db(State(cli): State<Arc<Client>>) -> impl IntoResponse {
-    cli.get_world().await.map(Json).map_err(Error)
-}
-
-async fn fortunes(State(cli): State<Arc<Client>>) -> impl IntoResponse {
-    use sailfish::TemplateOnce;
-    cli.tell_fortune()
-        .await
-        .map_err(Error)?
-        .render_once()
-        .map(Html)
-        .map_err(|e| Error(Box::new(e)))
-}
-
-async fn queries(State(cli): State<Arc<Client>>, Query(Num(num)): Query<Num>) -> impl IntoResponse {
-    cli.get_worlds(num).await.map(Json).map_err(Error)
-}
-
-async fn updates(State(cli): State<Arc<Client>>, Query(Num(num)): Query<Num>) -> impl IntoResponse {
-    cli.update(num).await.map(Json).map_err(Error)
-}
-
-struct Error(util::Error);
-
-impl IntoResponse for Error {
-    fn into_response(self) -> Response {
-        let mut res = self.0.to_string().into_response();
-        *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
-        res
-    }
-}
-
-// compat module between xitca-http and axum.
-mod tower_compat {
-    use core::{cell::RefCell, fmt, future::Future, marker::PhantomData};
-
-    use std::net::SocketAddr;
-
-    use http_body::Body;
-    use xitca_http::{
-        bytes::Bytes,
-        h1::RequestBody,
-        http::{Request, RequestExt, Response},
-        HttpServiceBuilder,
-    };
-    use xitca_io::net::io_uring::TcpStream;
-    use xitca_service::{fn_build, middleware::UncheckedReady, ready::ReadyService, Service, ServiceExt};
-    use xitca_web::service::tower_http_compat::{CompatReqBody, CompatResBody};
-
-    pub struct TowerHttp<S, B> {
-        service: RefCell<S>,
-        _p: PhantomData<fn(B)>,
-    }
-
-    impl<S, B> TowerHttp<S, B> {
-        pub fn service<F, Fut>(
-            func: F,
-        ) -> impl Service<Response = impl ReadyService + Service<(TcpStream, SocketAddr)>, Error = impl fmt::Debug>
-        where
-            F: Fn() -> Fut + Send + Sync + Clone,
-            Fut: Future<Output = Result<S, crate::util::Error>>,
-            S: tower::Service<Request<CompatReqBody<RequestExt<RequestBody>, ()>>, Response = Response<B>>,
-            S::Error: fmt::Debug,
-            B: Body<Data = Bytes> + Send + 'static,
-        {
-            fn_build(move |_| {
-                let func = func.clone();
-                async move {
-                    func().await.map(|service| TowerHttp {
-                        service: RefCell::new(service),
-                        _p: PhantomData,
-                    })
-                }
-            })
-            .enclosed(UncheckedReady)
-            .enclosed(HttpServiceBuilder::h1().io_uring())
-        }
-    }
-
-    impl<S, B> Service<Request<RequestExt<RequestBody>>> for TowerHttp<S, B>
-    where
-        S: tower::Service<Request<CompatReqBody<RequestExt<RequestBody>, ()>>, Response = Response<B>>,
-    {
-        type Response = Response<CompatResBody<B>>;
-        type Error = S::Error;
-
-        async fn call(&self, req: Request<RequestExt<RequestBody>>) -> Result<Self::Response, Self::Error> {
-            let (parts, ext) = req.into_parts();
-            let req = Request::from_parts(parts, CompatReqBody::new(ext, ()));
-            let fut = self.service.borrow_mut().call(req);
-            let (parts, body) = fut.await?.into_parts();
-            Ok(Response::from_parts(parts, CompatResBody::new(body)))
-        }
-    }
-}

+ 125 - 37
frameworks/Rust/xitca-web/src/main_iou.rs

@@ -1,9 +1,12 @@
-// used as reference of if/how moving from epoll to io-uring(or mixture of the two) make sense for
-// network io.
+// reference of if/how moving from epoll to io-uring(or mixture of the two) make sense for network io.
+// with comment on explaining why some practice are unrealistic
 
+// custom global memory allocator don't affect real world performance in noticeable amount.
+// in real world they should be used for reason like security, debug/profiling capability etc.
 #[global_allocator]
 static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
 
+#[path = "db_unrealistic.rs"]
 mod db;
 mod ser;
 mod util;
@@ -11,53 +14,138 @@ mod util;
 use std::{convert::Infallible, io};
 
 use xitca_http::{
-    body::ResponseBody,
-    http::{self, header::SERVER, StatusCode},
-    HttpServiceBuilder,
+    bytes::BufMutWriter,
+    h1::dispatcher_uring_unreal::{Dispatcher, Request, Response},
+    http::StatusCode,
 };
-use xitca_service::{fn_service, ServiceExt};
+use xitca_io::net::io_uring::TcpStream;
+use xitca_service::Service;
 
-use self::{
-    ser::{error_response, IntoResponse, Message, Request},
-    util::{context_mw, Ctx, QueryParse, SERVER_HEADER_VALUE},
-};
+use self::{ser::Message, util::State};
 
 fn main() -> io::Result<()> {
-    let service = fn_service(handler)
-        .enclosed(context_mw())
-        .enclosed(HttpServiceBuilder::h1().io_uring());
-    xitca_server::Builder::new()
-        .bind("xitca-iou", "0.0.0.0:8080", service)?
-        .build()
-        .wait()
+    let addr = "0.0.0.0:8080".parse().unwrap();
+
+    let cores = std::thread::available_parallelism().map(|num| num.get()).unwrap_or(56);
+
+    let handle = core::iter::repeat_with(|| {
+        std::thread::spawn(move || {
+            tokio_uring::start(async {
+                let socket = tokio::net::TcpSocket::new_v4()?;
+                socket.set_reuseaddr(true)?;
+                // unrealistic due to following reason:
+                // 1. this only works good on unix system.
+                // 2. no resource distribution adjustment between sockets on different threads. causing uneven workload
+                // where some threads are idle while others busy. resulting in overall increased latency
+                socket.set_reuseport(true)?;
+                socket.bind(addr)?;
+                let listener = socket.listen(1024)?;
+
+                let client = db::create().await.unwrap();
+
+                // unrealistic http dispatcher. no spec check. no security feature.
+                let service = Dispatcher::new(handler, State::new(client));
+
+                loop {
+                    match listener.accept().await {
+                        Ok((stream, _)) => {
+                            let stream = stream.into_std()?;
+                            let stream = TcpStream::from_std(stream);
+                            let service = service.clone();
+                            tokio::task::spawn_local(async move {
+                                let _ = service.call(stream).await;
+                            });
+                        }
+                        Err(e) => return Err(e),
+                    };
+                }
+            })
+        })
+    })
+    .take(cores)
+    .collect::<Vec<_>>();
+
+    // unrealistic due to no signal handling, not shutdown handling. when killing this process all resources that
+    // need clean async shutdown will be leaked.
+    for handle in handle {
+        handle.join().unwrap()?;
+    }
+
+    Ok(())
 }
 
-async fn handler<B>(ctx: Ctx<'_, Request<B>>) -> Result<http::Response<ResponseBody>, Infallible> {
-    let (req, state) = ctx.into_parts();
-    let mut res = match req.uri().path() {
-        "/plaintext" => req.text_response().unwrap(),
-        "/json" => req.json_response(state, &Message::new()).unwrap(),
+async fn handler<'h>(req: Request<'h, '_>, res: Response<'h>, state: &State<db::Client>) -> Response<'h, 3> {
+    // unrealistic due to no http method check
+    match req.path.unwrap_or("404") {
+        // unrealistic due to no dynamic path matching
+        "/plaintext" => {
+            // unrealistic due to no body streaming and no post processing. violating middleware feature of xitca-web
+            res.status(StatusCode::OK)
+                .header("content-type", "text/plain")
+                .header("server", "X")
+                // unrealistic content length header.
+                .header("content-length", "13")
+                .body_writer(|buf| Ok::<_, Infallible>(buf.extend_from_slice(b"Hello, World!")))
+                .unwrap()
+        }
+        "/json" => res
+            .status(StatusCode::OK)
+            .header("content-type", "application/json")
+            .header("server", "X")
+            // unrealistic content length header.
+            .header("content-length", "27")
+            .body_writer(|buf| serde_json::to_writer(BufMutWriter(buf), &Message::new()))
+            .unwrap(),
+        // all database related categories are unrealistic. please reference db_unrealistic module for detail.
+        "/fortunes" => {
+            use sailfish::TemplateOnce;
+            let fortunes = state.client.tell_fortune().await.unwrap().render_once().unwrap();
+            res.status(StatusCode::OK)
+                .header("content-type", "text/html; charset=utf-8")
+                .header("server", "X")
+                .body(fortunes.as_bytes())
+        }
         "/db" => {
+            // unrealistic due to no error handling. any db/serialization error will cause process crash.
+            // the same goes for all following unwraps on database related functions.
             let world = state.client.get_world().await.unwrap();
-            req.json_response(state, &world).unwrap()
+            json_response(res, state, &world)
         }
-        "/queries" => {
-            let num = req.uri().query().parse_query();
+        p if p.starts_with("/queries") => {
+            let num = path_param(p);
             let worlds = state.client.get_worlds(num).await.unwrap();
-            req.json_response(state, &worlds).unwrap()
+            json_response(res, state, &worlds)
         }
-        "/updates" => {
-            let num = req.uri().query().parse_query();
+        p if p.starts_with("/updates") => {
+            let num = path_param(p);
             let worlds = state.client.update(num).await.unwrap();
-            req.json_response(state, &worlds).unwrap()
-        }
-        "/fortunes" => {
-            use sailfish::TemplateOnce;
-            let fortunes = state.client.tell_fortune().await.unwrap().render_once().unwrap();
-            req.html_response(fortunes).unwrap()
+            json_response(res, state, &worlds)
         }
-        _ => error_response(StatusCode::NOT_FOUND),
+        _ => res.status(StatusCode::NOT_FOUND).header("server", "X").body(&[]),
+    }
+}
+
+fn json_response<'r, DB, T>(res: Response<'r>, state: &State<DB>, val: &T) -> Response<'r, 3>
+where
+    T: serde::Serialize,
+{
+    let buf = &mut *state.write_buf.borrow_mut();
+    serde_json::to_writer(BufMutWriter(buf), val).unwrap();
+    let res = res
+        .status(StatusCode::OK)
+        .header("content-type", "application/json")
+        .header("server", "X")
+        .body(buf.as_ref());
+    buf.clear();
+    res
+}
+
+fn path_param(query: &str) -> u16 {
+    use atoi::FromRadix10;
+    let q = if let Some(pos) = query.find("?q") {
+        u16::from_radix_10(query.split_at(pos + 3).1.as_ref()).0
+    } else {
+        1
     };
-    res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE);
-    Ok(res.map(Into::into))
+    q.clamp(1, 500)
 }

+ 67 - 0
frameworks/Rust/xitca-web/src/main_orm.rs

@@ -0,0 +1,67 @@
+mod db_diesel_async;
+mod schema;
+mod ser;
+mod util;
+
+use serde::Serialize;
+use xitca_web::{
+    codegen::route,
+    handler::{html::Html, json::Json, query::Query, state::StateRef, text::Text},
+    http::{header::SERVER, WebResponse},
+    route::get,
+    App,
+};
+
+use db_diesel_async::Pool;
+use ser::Num;
+use util::{HandleResult, SERVER_HEADER_VALUE};
+
+fn main() -> std::io::Result<()> {
+    App::new()
+        .with_async_state(db_diesel_async::create)
+        .at("/plaintext", get(Text("Hello, World!")))
+        .at("/json", get(Json(ser::Message::new())))
+        .at_typed(db)
+        .at_typed(fortunes)
+        .at_typed(queries)
+        .at_typed(updates)
+        .map(header)
+        .serve()
+        .disable_vectored_write()
+        .bind("0.0.0.0:8080")?
+        .run()
+        .wait()
+}
+
+fn header(mut res: WebResponse) -> WebResponse {
+    res.headers_mut().insert(SERVER, SERVER_HEADER_VALUE);
+    res
+}
+
+#[route("/db", method = get)]
+async fn db(StateRef(pool): StateRef<'_, Pool>) -> HandleResult<Json<impl Serialize>> {
+    pool.get_world().await.map(Json)
+}
+
+#[route("/fortunes", method = get)]
+async fn fortunes(StateRef(pool): StateRef<'_, Pool>) -> HandleResult<Html<String>> {
+    use sailfish::TemplateOnce;
+    let html = pool.tell_fortune().await?.render_once()?;
+    Ok(Html(html))
+}
+
+#[route("/queries", method = get)]
+async fn queries(
+    Query(Num(num)): Query<Num>,
+    StateRef(pool): StateRef<'_, Pool>,
+) -> HandleResult<Json<impl Serialize>> {
+    pool.get_worlds(num).await.map(Json)
+}
+
+#[route("/updates", method = get)]
+async fn updates(
+    Query(Num(num)): Query<Num>,
+    StateRef(pool): StateRef<'_, Pool>,
+) -> HandleResult<Json<impl Serialize>> {
+    pool.update(num).await.map(Json)
+}

+ 33 - 8
frameworks/Rust/xitca-web/src/ser.rs

@@ -33,7 +33,7 @@ impl Message {
 
 pub struct Num(pub u16);
 
-#[cfg_attr(feature = "pg-orm", derive(diesel::Queryable))]
+#[cfg_attr(any(feature = "pg-orm", feature = "pg-orm-async"), derive(diesel::Queryable))]
 pub struct World {
     pub id: i32,
     pub randomnumber: i32,
@@ -46,7 +46,7 @@ impl World {
     }
 }
 
-#[cfg_attr(feature = "pg-orm", derive(diesel::Queryable))]
+#[cfg_attr(any(feature = "pg-orm", feature = "pg-orm-async"), derive(diesel::Queryable))]
 pub struct Fortune {
     pub id: i32,
     pub message: Cow<'static, str>,
@@ -62,16 +62,41 @@ impl Fortune {
     }
 }
 
-// TODO: use another template engine with faster compile time.(preferably with no proc macro)
-#[cfg_attr(
-    feature = "template",
-    derive(sailfish::TemplateOnce),
-    template(path = "fortune.stpl", rm_whitespace = true)
-)]
 pub struct Fortunes {
     items: Vec<Fortune>,
 }
 
+// this is roughly the code generated by sailfish::TemplateOnce macro.
+// using the macro does not have any perf cost and this piece of code is expanded manually to speed up compile time of
+// bench to reduce resource usage of bench runner
+#[cfg(feature = "template")]
+impl sailfish::TemplateOnce for Fortunes {
+    fn render_once(self) -> sailfish::RenderResult {
+        use sailfish::runtime::{Buffer, Render};
+
+        const PREFIX: &str = "<!DOCTYPE html>\n<html>\n<head><title>Fortunes</title></head>\n<body>\n<table>\n<tr><th>id</th><th>message</th></tr>\n";
+        const SUFFIX: &str = "\n</table>\n</body>\n</html>";
+
+        let mut buf = Buffer::with_capacity(1236);
+
+        buf.push_str(PREFIX);
+        for item in self.items {
+            buf.push_str("<tr><td>");
+            Render::render_escaped(&item.id, &mut buf)?;
+            buf.push_str("</td><td>");
+            Render::render_escaped(&item.message, &mut buf)?;
+            buf.push_str("</td></tr>");
+        }
+        buf.push_str(SUFFIX);
+
+        Ok(buf.into_string())
+    }
+
+    fn render_once_to(self, _: &mut sailfish::runtime::Buffer) -> Result<(), sailfish::runtime::RenderError> {
+        unimplemented!("")
+    }
+}
+
 impl Fortunes {
     #[inline]
     pub const fn new(items: Vec<Fortune>) -> Self {

+ 9 - 31
frameworks/Rust/xitca-web/src/util.rs

@@ -54,6 +54,15 @@ pub struct State<DB> {
     pub write_buf: RefCell<BytesMut>,
 }
 
+impl<DB> State<DB> {
+    pub fn new(client: DB) -> Self {
+        Self {
+            client,
+            write_buf: Default::default(),
+        }
+    }
+}
+
 #[cfg(not(target_arch = "wasm32"))]
 mod non_wasm {
     use rand::{rngs::SmallRng, Rng, SeedableRng};
@@ -72,37 +81,6 @@ mod non_wasm {
             self.0.gen_range(1..=10000)
         }
     }
-
-    #[cfg(feature = "pg")]
-    mod pg_state {
-        use core::{cell::RefCell, future::Future, pin::Pin};
-
-        use xitca_http::{
-            bytes::BytesMut,
-            util::middleware::context::{Context, ContextBuilder},
-        };
-
-        use crate::{
-            db::{self, Client},
-            util::{HandleResult, State},
-        };
-
-        pub type Ctx<'a, Req> = Context<'a, Req, State<Client>>;
-
-        pub fn context_mw() -> ContextBuilder<impl Fn() -> Pin<Box<dyn Future<Output = HandleResult<State<Client>>>>>> {
-            ContextBuilder::new(|| {
-                Box::pin(async {
-                    db::create().await.map(|client| State {
-                        client,
-                        write_buf: RefCell::new(BytesMut::new()),
-                    })
-                }) as _
-            })
-        }
-    }
-
-    #[cfg(feature = "pg")]
-    pub use pg_state::*;
 }
 
 #[cfg(not(target_arch = "wasm32"))]

+ 0 - 10
frameworks/Rust/xitca-web/xitca-web-axum.dockerfile

@@ -1,10 +0,0 @@
-FROM rust:1.81
-
-ADD ./ /xitca-web
-WORKDIR /xitca-web
-
-RUN cargo build --release --bin xitca-web-axum --features axum,io-uring,perf,pg-sync,template
-
-EXPOSE 8080
-
-CMD ./target/release/xitca-web-axum

+ 10 - 0
frameworks/Rust/xitca-web/xitca-web-orm.dockerfile

@@ -0,0 +1,10 @@
+FROM rust:1.81
+
+ADD ./ /xitca-web
+WORKDIR /xitca-web
+
+RUN cargo build --release --bin xitca-web-orm --features pg-orm-async,template,web-codegen
+
+EXPOSE 8080
+
+CMD ./target/release/xitca-web-orm