Compare commits
No commits in common. "b619f79095773d53d23c996b5652ae8da22e5376" and "25bb724961de3993c74f827f25d454b4cb3bb247" have entirely different histories.
b619f79095
...
25bb724961
19 changed files with 1861 additions and 744 deletions
204
Cargo.lock
generated
204
Cargo.lock
generated
|
|
@ -1,6 +1,21 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
|
|
@ -112,6 +127,17 @@ version = "4.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.73"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
|
|
@ -124,6 +150,21 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
|
|
@ -222,7 +263,7 @@ dependencies = [
|
|||
"num-traits",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -232,7 +273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -327,7 +368,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -373,6 +414,12 @@ dependencies = [
|
|||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.28.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
||||
|
||||
[[package]]
|
||||
name = "gloo-timers"
|
||||
version = "0.2.6"
|
||||
|
|
@ -408,7 +455,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
|||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -443,9 +490,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.186"
|
||||
version = "0.2.148"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
|
|
@ -502,14 +549,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.2.0"
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.8.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -552,6 +608,25 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.18.0"
|
||||
|
|
@ -619,7 +694,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -658,23 +733,23 @@ dependencies = [
|
|||
"libc",
|
||||
"log",
|
||||
"pin-project-lite",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
version = "1.0.67"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
|
@ -736,35 +811,35 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
|||
name = "rspc"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"async-trait",
|
||||
"futures",
|
||||
"oneshot",
|
||||
"rspc_dev_utilities",
|
||||
"pin-project",
|
||||
"rspc_macros",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"syn 2.0.38",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"tokio-serde",
|
||||
"tokio-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rspc_dev_utilities"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"rspc",
|
||||
"serde",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rspc_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.25"
|
||||
|
|
@ -776,7 +851,7 @@ dependencies = [
|
|||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -805,32 +880,22 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
version = "1.0.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
version = "1.0.189"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -889,12 +954,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.3"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
|
||||
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -910,9 +975,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
version = "2.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -936,7 +1001,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -951,30 +1016,32 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.52.1"
|
||||
version = "1.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
|
||||
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
"libc",
|
||||
"mio",
|
||||
"num_cpus",
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2 0.6.3",
|
||||
"socket2 0.5.4",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.7.0"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
|
||||
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1026,7 +1093,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1119,7 +1186,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"syn 2.0.38",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
|
@ -1153,7 +1220,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"syn 2.0.38",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
|
@ -1205,12 +1272,6 @@ dependencies = [
|
|||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.48.0"
|
||||
|
|
@ -1220,15 +1281,6 @@ dependencies = [
|
|||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.48.5"
|
||||
|
|
|
|||
40
Cargo.toml
40
Cargo.toml
|
|
@ -1,44 +1,22 @@
|
|||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["utilities"]
|
||||
|
||||
[dev-dependencies]
|
||||
rspc_dev_utilities = { path = "utilities" }
|
||||
|
||||
[features]
|
||||
default = ["full"]
|
||||
full = ["serde","channel"]
|
||||
channel = ["dep:oneshot"]
|
||||
serde = ["dep:serde", "rspc_macros/serde"]
|
||||
|
||||
[package]
|
||||
name = "rspc"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
include = ["/src"]
|
||||
|
||||
[dependencies]
|
||||
rspc_macros = { path = "macros", version = "0.1" }
|
||||
# necessary dependencies
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
futures = "0.3"
|
||||
thiserror = "1.0.49"
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
syn = { version = "2.0", features = ["full"] }
|
||||
rspc_macros = { path = "macros", version = "0.1" }
|
||||
thiserror = "1.0.49"
|
||||
async-trait = "0.1.73"
|
||||
async-std = "1.12.0"
|
||||
tokio-serde = { version = "0.8.0", features=["json","bincode"] }
|
||||
pin-project = "1.1.3"
|
||||
tokio-util = { version = "0.7.10", features=["codec"] }
|
||||
oneshot = { version = "0.1.6", features=["std"], optional = true }
|
||||
serde = { version = "1.0", features = ["derive"], optional = true }
|
||||
serde_json = "1.0.108"
|
||||
oneshot = { version = "0.1.6", features=["std"] }
|
||||
|
||||
[lib]
|
||||
|
||||
|
||||
[[example]]
|
||||
name = "channel_sync"
|
||||
required-features = ["channel"]
|
||||
|
||||
[[example]]
|
||||
name = "channel_async"
|
||||
required-features = ["channel"]
|
||||
|
||||
[[example]]
|
||||
name = "tcp"
|
||||
required-features = ["serde"]
|
||||
|
|
|
|||
19
README.md
19
README.md
|
|
@ -3,14 +3,12 @@
|
|||
Proof of concept RPC framework focused on ease of use.
|
||||
It works by calling the macro `#[rspc::service]` on an impl block,
|
||||
and code is generated for the resulting Server and Client objects.
|
||||
You can then instantiate a Server/Client on the desired transporter.
|
||||
|
||||
The Server objects own the original struct data and implements listen functions.<br>
|
||||
The Client objects must be provided a connection, and replicates all the functions of the impl block where the macro was called.
|
||||
|
||||
The Server implements read-write locking, there can be many reads at once, but only one write. Requests are not errored upon write-lock, but instead waited for.
|
||||
|
||||
> If you wish to implement parallel writes, you must implement it with internal parallelism as you would in normal rust, for instance with immutable functions and internal read-write locks
|
||||
The Server implements read-write locking, there can be many reads at once, but only one write.
|
||||
Requests are not errored upon write-lock, but instead waited for.
|
||||
|
||||
The Client object cannot be cloned. Instead all function calls are immutable, so a reference can be shared to all.
|
||||
|
||||
|
|
@ -19,6 +17,7 @@ Currently only implements local thread messaging. Serialized TCP transport is un
|
|||
Example:
|
||||
```rs
|
||||
use rspc::transport::{channel, ClientTransporter,ServerTransporter};
|
||||
use rspc::service;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
|
@ -27,8 +26,7 @@ pub struct MyStruct {
|
|||
my_vec: Vec<String>,
|
||||
}
|
||||
|
||||
// Functions to instanciate as RPC
|
||||
#[rspc::service]
|
||||
#[service]
|
||||
impl MyStruct
|
||||
{
|
||||
pub fn len(&self) -> usize {
|
||||
|
|
@ -46,11 +44,9 @@ impl MyStruct
|
|||
|
||||
#[tokio::test]
|
||||
async fn test() {
|
||||
// Create the server data structure
|
||||
let my_data = MyStruct {
|
||||
my_vec: Vec::new(),
|
||||
};
|
||||
// Instanciate a client and server
|
||||
let (c,s) = channel::new_async();
|
||||
|
||||
let srv_thread = tokio::spawn(async move {
|
||||
|
|
@ -69,10 +65,3 @@ async fn test() {
|
|||
```
|
||||
|
||||
See [example](example) for an more detailed example usage
|
||||
|
||||
### Internal logic and determinism
|
||||
|
||||
RSPC is built on rust logic and works with type determinism rather than serializing.
|
||||
Serializing is used for transports that require it (such as TCP with serde), but is otherwise unused in code logic.
|
||||
|
||||
Determinism is achieved through enum autogeneration by the macro `rscp::service`, which is used for internal transport logic
|
||||
|
|
|
|||
1333
example/Cargo.lock
generated
Normal file
1333
example/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,12 +1,13 @@
|
|||
[package]
|
||||
name = "rspc_dev_utilities"
|
||||
name = "rspc_example"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rspc = { path = ".." }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
anyhow = "1.0.86"
|
||||
async-std = "1.12.0"
|
||||
tokio = { version = "1.0", features = ["full"] }
|
||||
rspc = { path = ".." }
|
||||
serde = "1.0.203"
|
||||
tokio = "1.38.0"
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use rspc::transport::{ClientTransporter, ServerTransporter};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub type RetData = (usize,Option<usize>);
|
||||
|
||||
pub fn dur_to_num(dur: Duration) -> (u128, &'static str) {
|
||||
if dur.as_nanos() < 10000 {
|
||||
|
|
@ -17,13 +17,26 @@ pub fn dur_to_num(dur: Duration) -> (u128, &'static str) {
|
|||
}
|
||||
|
||||
pub fn dur_to_str(dur: Duration) -> String {
|
||||
let (n, s) = dur_to_num(dur);
|
||||
n.to_string() + " " + s
|
||||
let (n,s) = dur_to_num(dur);
|
||||
n.to_string() +" "+ s
|
||||
}
|
||||
|
||||
pub fn process_data(dat: TestData) -> RetData {
|
||||
(dat.len(), dat.calc())
|
||||
}
|
||||
|
||||
pub fn process_data_ref(dat: &TestData) -> RetData {
|
||||
(dat.len(), dat.calc())
|
||||
}
|
||||
|
||||
pub const DATASIZE: usize = 1000000;
|
||||
|
||||
const TEST_STRINGS: [&str; 4] = ["toto", "tata", "titi", "tutu"];
|
||||
const TEST_STRINGS: [&str; 4] = [
|
||||
"toto",
|
||||
"tata",
|
||||
"titi",
|
||||
"tutu"
|
||||
];
|
||||
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub enum TestEnum {
|
||||
|
|
@ -37,8 +50,11 @@ pub struct TestData {
|
|||
vec: Vec<(bool, TestEnum)>,
|
||||
}
|
||||
|
||||
use crate::transport::{ClientTransporter,ServerTransporter};
|
||||
|
||||
#[rspc::service]
|
||||
impl TestData {
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.vec.len()
|
||||
}
|
||||
|
|
@ -61,7 +77,7 @@ impl TestData {
|
|||
if n <= 1 {
|
||||
n
|
||||
} else {
|
||||
Self::internal_fib(n - 1) + Self::internal_fib(n - 2)
|
||||
Self::internal_fib(n-1) + Self::internal_fib(n-2)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,11 +86,11 @@ impl TestData {
|
|||
}
|
||||
|
||||
pub fn add(&self, a: usize, b: usize) -> usize {
|
||||
return a + b;
|
||||
return a+b;
|
||||
}
|
||||
|
||||
pub fn calc_add(&self, data: TestData) -> Option<usize> {
|
||||
return self.calc().and_then(|a| data.calc().map(|b| a + b));
|
||||
return self.calc().and_then(|a| data.calc().map(|b| a+b));
|
||||
}
|
||||
|
||||
pub fn push(&mut self, u: (bool, TestEnum)) {
|
||||
|
|
@ -86,16 +102,16 @@ pub fn make_test_data(n: usize) -> TestData {
|
|||
let mut v = Vec::with_capacity(n);
|
||||
let mut b = true;
|
||||
for i in 0..n {
|
||||
v.push((
|
||||
b,
|
||||
match i % 3 {
|
||||
v.push(( b ,
|
||||
match i%3 {
|
||||
0 => TestEnum::NoValue,
|
||||
1 => TestEnum::Num(i),
|
||||
2 => TestEnum::Str(TEST_STRINGS[i % 4].to_string()),
|
||||
2 => TestEnum::Str(TEST_STRINGS[i%4].to_string()),
|
||||
_ => panic!("unexpected error"),
|
||||
},
|
||||
));
|
||||
}));
|
||||
b = !b;
|
||||
}
|
||||
TestData { vec: v }
|
||||
TestData {
|
||||
vec: v,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +1,28 @@
|
|||
use rspc_dev_utilities::test_data::{
|
||||
dur_to_str, make_test_data, TestData, TestDataClient, TestDataServer, TestEnum, DATASIZE,
|
||||
};
|
||||
|
||||
pub mod data;
|
||||
|
||||
use data::{make_test_data,dur_to_str,TestData,TestEnum,TestDataClient,TestDataServer,DATASIZE};
|
||||
use tokio::join;
|
||||
|
||||
use rspc::transport::serde::TcpClient;
|
||||
|
||||
use rspc::transport;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let (c, s) = transport::channel::new_async();
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
|
||||
// let t = TcpClient::connect("127.0.0.1:3306").await.unwrap();
|
||||
// let client = t.spawn().await;
|
||||
|
||||
// let client = TestDataClient::new(client);
|
||||
|
||||
let (c,s) = transport::channel::new_async();
|
||||
let data: TestData = make_test_data(DATASIZE);
|
||||
|
||||
let srv_thread = tokio::spawn(async move {
|
||||
let mut server = TestDataServer::from(data);
|
||||
server.listen(s).await
|
||||
});
|
||||
} );
|
||||
|
||||
let client = TestDataClient::new(c);
|
||||
let clientref = &client;
|
||||
|
|
@ -34,7 +43,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
println!("len: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(4, client.calc().await.unwrap().unwrap_or(0));
|
||||
assert_eq!(4, client.calc().await.unwrap().unwrap_or(0) );
|
||||
println!("calc: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let cdat = make_test_data(DATASIZE);
|
||||
|
|
@ -51,8 +60,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
println!("push: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(DATASIZE + 1, client.len().await.unwrap());
|
||||
assert_eq!(DATASIZE+1, client.len().await.unwrap());
|
||||
println!("len: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
};
|
||||
|
||||
join!(job1, job2);
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
use rspc_dev_utilities::test_data::{
|
||||
dur_to_str, make_test_data, TestData, TestDataClient, TestDataServer, TestEnum, DATASIZE,
|
||||
};
|
||||
use tokio::join;
|
||||
|
||||
use rspc::transport;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let (c, s) = transport::channel::new_sync();
|
||||
let data: TestData = make_test_data(DATASIZE);
|
||||
|
||||
let srv_thread = tokio::spawn(async move {
|
||||
let mut server = TestDataServer::from(data);
|
||||
server.listen(s).await
|
||||
});
|
||||
|
||||
let client = TestDataClient::new(c);
|
||||
let clientref = &client;
|
||||
|
||||
let job1 = async {
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(DATASIZE, client.len().await.unwrap());
|
||||
println!("len: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(267914296, clientref.fib(42).await.unwrap());
|
||||
println!("fib1: {}", dur_to_str(now.elapsed()));
|
||||
};
|
||||
|
||||
let job2 = async {
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(DATASIZE, client.len().await.unwrap());
|
||||
println!("len: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(4, client.calc().await.unwrap().unwrap_or(0));
|
||||
println!("calc: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let cdat = make_test_data(DATASIZE);
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(8, client.calc_add(cdat).await.unwrap().unwrap_or(0));
|
||||
println!("calc_add: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(267914296, client.fib(42).await.unwrap());
|
||||
println!("fib2: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
clientref.push((false, TestEnum::NoValue)).await.unwrap();
|
||||
println!("push: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(DATASIZE + 1, client.len().await.unwrap());
|
||||
println!("len: {}", dur_to_str(now.elapsed()));
|
||||
};
|
||||
|
||||
join!(job1, job2);
|
||||
client.stop().await.unwrap();
|
||||
srv_thread.await.unwrap().unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
use rspc_dev_utilities::test_data::{
|
||||
dur_to_str, make_test_data, TestData, TestDataClient, TestDataServer, TestEnum, DATASIZE,
|
||||
};
|
||||
use tokio::join;
|
||||
|
||||
use rspc::transport::serde::TcpClient;
|
||||
|
||||
use rspc::transport;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let t = TcpClient::connect("127.0.0.1:6543").await.unwrap();
|
||||
let client = t.spawn().await;
|
||||
|
||||
// todo : server
|
||||
|
||||
let client = TestDataClient::new(client);
|
||||
|
||||
let clientref = &client;
|
||||
|
||||
let job1 = async {
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(DATASIZE, client.len().await.unwrap());
|
||||
println!("len: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(267914296, clientref.fib(42).await.unwrap());
|
||||
println!("fib1: {}", dur_to_str(now.elapsed()));
|
||||
};
|
||||
|
||||
let job2 = async {
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(DATASIZE, client.len().await.unwrap());
|
||||
println!("len: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(4, client.calc().await.unwrap().unwrap_or(0));
|
||||
println!("calc: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let cdat = make_test_data(DATASIZE);
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(8, client.calc_add(cdat).await.unwrap().unwrap_or(0));
|
||||
println!("calc_add: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(267914296, client.fib(42).await.unwrap());
|
||||
println!("fib2: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
clientref.push((false, TestEnum::NoValue)).await.unwrap();
|
||||
println!("push: {}", dur_to_str(now.elapsed()));
|
||||
|
||||
let now = std::time::Instant::now();
|
||||
assert_eq!(DATASIZE + 1, client.len().await.unwrap());
|
||||
println!("len: {}", dur_to_str(now.elapsed()));
|
||||
};
|
||||
|
||||
join!(job1, job2);
|
||||
client.stop().await.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
46
macros/Cargo.lock
generated
46
macros/Cargo.lock
generated
|
|
@ -1,46 +0,0 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rspc_macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
|
@ -5,10 +5,6 @@ edition = "2021"
|
|||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[features]
|
||||
full = ["serde"]
|
||||
serde = []
|
||||
|
||||
[dependencies]
|
||||
#anyhow = "1.0"
|
||||
#futures = "0.3"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
extern crate proc_macro;
|
||||
extern crate quote;
|
||||
|
||||
|
|
@ -8,8 +9,8 @@ use syn::{
|
|||
parse::{Parse, ParseStream},
|
||||
parse_macro_input,
|
||||
spanned::Spanned,
|
||||
Attribute, FnArg, Ident, ImplItemFn, ImplItemType, ItemImpl, Pat, PatType, Receiver,
|
||||
ReturnType, Signature, Visibility,
|
||||
FnArg, Ident,
|
||||
Pat, PatType, ReturnType, Visibility, Receiver, ItemImpl, ImplItemFn, ImplItemType, Signature, Attribute,
|
||||
};
|
||||
|
||||
use quote::{format_ident, quote};
|
||||
|
|
@ -48,7 +49,7 @@ fn snake_to_upper_camel(ident_str: &str) -> String {
|
|||
}
|
||||
|
||||
struct RpcMethod {
|
||||
pub _attrs: Vec<Attribute>,
|
||||
pub attrs: Vec<Attribute>,
|
||||
pub sig: Signature,
|
||||
pub reciever: Option<Receiver>,
|
||||
pub args: Vec<PatType>,
|
||||
|
|
@ -57,34 +58,30 @@ struct RpcMethod {
|
|||
struct Service {
|
||||
pub ident: Ident,
|
||||
pub rpcs: Vec<RpcMethod>,
|
||||
pub _item: ItemImpl,
|
||||
pub _types: Vec<ImplItemType>,
|
||||
pub item: ItemImpl,
|
||||
pub types: Vec<ImplItemType>,
|
||||
}
|
||||
|
||||
impl TryFrom<ImplItemFn> for RpcMethod {
|
||||
|
||||
type Error = syn::Error;
|
||||
|
||||
fn try_from(value: ImplItemFn) -> Result<Self, Self::Error> {
|
||||
|
||||
let mut reciever = None;
|
||||
let mut args = vec![];
|
||||
let mut args = vec!();
|
||||
|
||||
for arg in &value.sig.inputs {
|
||||
match arg {
|
||||
FnArg::Typed(captured) if matches!(&*captured.pat, Pat::Ident(_)) => {
|
||||
args.push(captured.clone());
|
||||
}
|
||||
},
|
||||
FnArg::Typed(captured) => {
|
||||
return Err(syn::Error::new(
|
||||
captured.pat.span(),
|
||||
"patterns aren't allowed in RPC args",
|
||||
));
|
||||
}
|
||||
return Err(syn::Error::new(captured.pat.span(), "patterns aren't allowed in RPC args"));
|
||||
},
|
||||
FnArg::Receiver(v) => {
|
||||
if matches!(v.reference, None) {
|
||||
return Err(syn::Error::new(
|
||||
v.span(),
|
||||
"self cannot be consumed in RPC method",
|
||||
));
|
||||
return Err(syn::Error::new(v.span(), "self cannot be consumed in RPC method"));
|
||||
} else {
|
||||
reciever = Some(v.clone());
|
||||
}
|
||||
|
|
@ -93,7 +90,7 @@ impl TryFrom<ImplItemFn> for RpcMethod {
|
|||
}
|
||||
|
||||
Ok(RpcMethod {
|
||||
_attrs: value.attrs,
|
||||
attrs: value.attrs,
|
||||
sig: value.sig,
|
||||
reciever,
|
||||
args,
|
||||
|
|
@ -108,48 +105,37 @@ impl Parse for Service {
|
|||
|
||||
let mut errors = Ok(());
|
||||
|
||||
let mut typeitems: Vec<ImplItemType> = vec![];
|
||||
let fns: Vec<&ImplItemFn> = item
|
||||
.items
|
||||
.iter()
|
||||
.filter(|x| match x {
|
||||
let mut typeitems: Vec<ImplItemType> = vec!();
|
||||
let fns: Vec<&ImplItemFn> = item.items.iter().filter(|x| {
|
||||
match x {
|
||||
syn::ImplItem::Fn(fnit) => {
|
||||
matches!(fnit.vis, Visibility::Public(_))
|
||||
}
|
||||
},
|
||||
syn::ImplItem::Type(x) => {
|
||||
typeitems.push(x.clone());
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
})
|
||||
.map(|x| {
|
||||
}
|
||||
}).map(|x|
|
||||
if let syn::ImplItem::Fn(fnit) = x {
|
||||
fnit
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
).collect();
|
||||
|
||||
let ident = match item.self_ty.as_ref() {
|
||||
syn::Type::Path(x) => match x.path.get_ident() {
|
||||
syn::Type::Path(x) => {
|
||||
match x.path.get_ident() {
|
||||
Some(i) => i.clone(),
|
||||
None => {
|
||||
return Err(syn::Error::new(
|
||||
x.span(),
|
||||
"generics and paths are not supported",
|
||||
))
|
||||
None => return Err(syn::Error::new(x.span(), "generics and paths are not supported")),
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
return Err(syn::Error::new(
|
||||
item.self_ty.span(),
|
||||
"unsupported self type",
|
||||
))
|
||||
}
|
||||
_ => return Err(syn::Error::new(item.self_ty.span(), "unsupported self type")),
|
||||
};
|
||||
|
||||
let mut rpcs = vec![];
|
||||
let mut rpcs = vec!();
|
||||
for one_fn in fns {
|
||||
match RpcMethod::try_from(one_fn.clone()) {
|
||||
Ok(v) => rpcs.push(v),
|
||||
|
|
@ -171,6 +157,7 @@ impl Parse for Service {
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
errors?;
|
||||
|
|
@ -178,12 +165,13 @@ impl Parse for Service {
|
|||
Ok(Self {
|
||||
ident,
|
||||
rpcs,
|
||||
_item: item,
|
||||
_types: typeitems,
|
||||
item,
|
||||
types: typeitems,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Macro used to generate the RSPC Server and Client objects.
|
||||
#[proc_macro_attribute]
|
||||
pub fn service(_attr: TokenStream, mut input: TokenStream) -> TokenStream {
|
||||
|
|
@ -191,8 +179,8 @@ pub fn service(_attr: TokenStream, mut input: TokenStream) -> TokenStream {
|
|||
let Service {
|
||||
ident,
|
||||
rpcs,
|
||||
_item: _,
|
||||
_types: _,
|
||||
item: _,
|
||||
types: _,
|
||||
} = parse_macro_input!(inputclone as Service);
|
||||
|
||||
let transport_request = &format_ident!("{}TransportRequest", ident);
|
||||
|
|
@ -200,90 +188,72 @@ pub fn service(_attr: TokenStream, mut input: TokenStream) -> TokenStream {
|
|||
let server = &format_ident!("{}Server", ident);
|
||||
let client = &format_ident!("{}Client", ident);
|
||||
|
||||
let fn_names: Vec<_> = rpcs.iter().map(|x| &x.sig.ident).collect();
|
||||
let fn_names: Vec<_> = rpcs.iter().map(|x| {
|
||||
&x.sig.ident
|
||||
}).collect();
|
||||
|
||||
let fn_names_camel: Vec<_> = fn_names
|
||||
.iter()
|
||||
.map(|x| Ident::new(&snake_to_upper_camel(&x.unraw().to_string()), x.span()))
|
||||
.collect();
|
||||
let fn_names_camel: Vec<_> = fn_names.iter().map(|x| {
|
||||
Ident::new(&snake_to_upper_camel(&x.unraw().to_string()), x.span())
|
||||
}).collect();
|
||||
|
||||
let fn_locks: Vec<_> = rpcs
|
||||
.iter()
|
||||
.map(|x| match x.reciever.as_ref() {
|
||||
let fn_locks: Vec<_> = rpcs.iter().map(|x| {
|
||||
match x.reciever.as_ref() {
|
||||
Some(rcv) => match &rcv.mutability {
|
||||
Some(_) => quote!(write()),
|
||||
None => quote!(read()),
|
||||
},
|
||||
None => quote!(read()),
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let fn_mut: Vec<_> = rpcs
|
||||
.iter()
|
||||
.map(|x| match x.reciever.as_ref() {
|
||||
let fn_mut: Vec<_> = rpcs.iter().map(|x| {
|
||||
match x.reciever.as_ref() {
|
||||
Some(rcv) => match &rcv.mutability {
|
||||
Some(_) => quote!(mut),
|
||||
None => quote!(),
|
||||
},
|
||||
None => quote!(),
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let fn_await: Vec<_> = rpcs
|
||||
.iter()
|
||||
.map(|x| match &x.sig.asyncness {
|
||||
let fn_await: Vec<_> = rpcs.iter().map(|x| {
|
||||
match &x.sig.asyncness {
|
||||
Some(_) => quote!(.await),
|
||||
None => quote!(),
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let args: Vec<_> = rpcs
|
||||
.iter()
|
||||
.map(|x| {
|
||||
let args: Vec<_> = rpcs.iter().map(|x| {
|
||||
let args = &x.args;
|
||||
quote! { #(#args),* }
|
||||
})
|
||||
.collect();
|
||||
quote!{ #(#args),* }
|
||||
}).collect();
|
||||
|
||||
let arg_types: Vec<_> = rpcs
|
||||
.iter()
|
||||
.map(|x| {
|
||||
let arg_types: Vec<_> = rpcs.iter().map(|x| {
|
||||
let args = x.args.iter().map(|a| &a.ty);
|
||||
quote! { #(#args),* }
|
||||
})
|
||||
.collect();
|
||||
quote!{ #(#args),* }
|
||||
}).collect();
|
||||
|
||||
let arg_idents: Vec<_> = rpcs
|
||||
.iter()
|
||||
.map(|x| {
|
||||
let arg_idents: Vec<_> = rpcs.iter().map(|x| {
|
||||
let args = x.args.iter().map(|a| &a.pat);
|
||||
quote! { #(#args),* }
|
||||
})
|
||||
.collect();
|
||||
quote!{ #(#args),* }
|
||||
}).collect();
|
||||
|
||||
let outs: Vec<_> = rpcs
|
||||
.iter()
|
||||
.map(|x| match &x.sig.output {
|
||||
ReturnType::Default => quote! {()},
|
||||
ReturnType::Type(_, t) => quote! {#t},
|
||||
})
|
||||
.collect();
|
||||
|
||||
let serde_derives = if cfg!(feature = "serde") {
|
||||
quote! { serde::Serialize, serde::Deserialize }
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
let outs: Vec<_> = rpcs.iter().map(|x| {
|
||||
match &x.sig.output {
|
||||
ReturnType::Default => quote!{()},
|
||||
ReturnType::Type(_, t) => quote!{#t},
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let t = quote! {
|
||||
|
||||
#[derive(PartialEq, Debug, #serde_derives)]
|
||||
#[derive(PartialEq,Debug,Serialize,Deserialize)]
|
||||
pub enum #transport_request {
|
||||
#( #fn_names_camel(#arg_types) ),* ,
|
||||
Stop,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, #serde_derives)]
|
||||
#[derive(PartialEq,Debug,Serialize,Deserialize)]
|
||||
pub enum #transport_response {
|
||||
#( #fn_names_camel(#outs) ),* ,
|
||||
Stop,
|
||||
|
|
@ -302,13 +272,13 @@ pub fn service(_attr: TokenStream, mut input: TokenStream) -> TokenStream {
|
|||
}
|
||||
|
||||
pub struct #server {
|
||||
obj: std::sync::Arc<tokio::sync::RwLock<#ident>>,
|
||||
obj: std::sync::Arc<async_std::sync::RwLock<#ident>>,
|
||||
}
|
||||
|
||||
impl From<#ident> for #server {
|
||||
fn from(obj: #ident) -> Self {
|
||||
Self {
|
||||
obj: std::sync::Arc::new(tokio::sync::RwLock::new(obj)),
|
||||
obj: std::sync::Arc::new(async_std::sync::RwLock::new(obj)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
53
src/lib.rs
53
src/lib.rs
|
|
@ -1,2 +1,55 @@
|
|||
|
||||
pub mod transport;
|
||||
pub use rspc_macros::service;
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::transport::{channel, ClientTransporter,ServerTransporter};
|
||||
use super::service;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
// use rspc::transport::{ClientTransporter,ServerTransporter};
|
||||
|
||||
#[derive(Serialize,Deserialize)]
|
||||
pub struct MyStruct {
|
||||
my_vec: Vec<String>,
|
||||
}
|
||||
|
||||
#[service]
|
||||
impl MyStruct
|
||||
{
|
||||
pub fn len(&self) -> usize {
|
||||
self.my_vec.len()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, val: String) {
|
||||
self.my_vec.push(val)
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<String> {
|
||||
self.my_vec.pop()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test() {
|
||||
let my_data = MyStruct {
|
||||
my_vec: Vec::new(),
|
||||
};
|
||||
let (c,s) = channel::new_async();
|
||||
|
||||
let srv_thread = tokio::spawn(async move {
|
||||
let mut server = MyStructServer::from(my_data);
|
||||
server.listen(s).await
|
||||
} );
|
||||
|
||||
let client = MyStructClient::new(c);
|
||||
assert_eq!(client.len().await.unwrap(), 0);
|
||||
client.push("Hello world!".to_string()).await.unwrap();
|
||||
assert_eq!(client.len().await.unwrap(), 1);
|
||||
assert_eq!(client.pop().await.unwrap(), Some("Hello world!".to_string()));
|
||||
client.stop().await.unwrap();
|
||||
srv_thread.await.unwrap().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,14 @@ use futures::future::BoxFuture;
|
|||
use futures::stream::FuturesUnordered;
|
||||
use futures::{Future, StreamExt};
|
||||
use thiserror::Error;
|
||||
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||
use tokio::sync::oneshot;
|
||||
use tokio::sync::mpsc::{self, UnboundedSender, UnboundedReceiver};
|
||||
|
||||
use super::{ClientTransporter, ServerTransporter};
|
||||
use async_trait::async_trait;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
use super::{ClientTransporter,ServerTransporter};
|
||||
|
||||
#[derive(Error,Debug)]
|
||||
pub enum Error {
|
||||
#[error("channel recv error")]
|
||||
ChannelRecvError,
|
||||
|
|
@ -21,30 +23,32 @@ pub enum Error {
|
|||
OneshotRecvError(#[from] oneshot::error::RecvError),
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
/// Client endpoint of any channel.
|
||||
pub struct ChannelClient<T, R> {
|
||||
channel: UnboundedSender<(T, oneshot::Sender<R>)>,
|
||||
pub struct ChannelClient<T,R> {
|
||||
channel: UnboundedSender<(T,oneshot::Sender<R>)>,
|
||||
}
|
||||
|
||||
/// Server endpoint of a synchronous channel.
|
||||
/// Server endpoint of a synchronous channel
|
||||
pub struct SyncChannelServer<T,R> {
|
||||
channel: UnboundedReceiver<(T,oneshot::Sender<R>)>,
|
||||
}
|
||||
|
||||
/// Create a new synchronous channel client/server instance.
|
||||
///
|
||||
/// Synchronous channels can only process one job at a time. If you want job concurrency refer to [new_async](new_async) and [AsyncChannelServer](AsyncChannelServer)
|
||||
/// Synchronous channels can only process one job at a time.
|
||||
/// If you want job concurrency refer to new_async() and Asynchronous channels
|
||||
///
|
||||
/// Unpon recieving a stop signal, jobs currently pending recv() will not be processed.
|
||||
/// Said jobs will continue waiting until either the server listens again, or the server is dropped.
|
||||
pub struct SyncChannelServer<T, R> {
|
||||
channel: UnboundedReceiver<(T, oneshot::Sender<R>)>,
|
||||
}
|
||||
|
||||
/// Create a new synchronous channel client/server instance. See [SyncChannelServer](SyncChannelServer)
|
||||
///
|
||||
/// Synchronous channels can only process one job at a time. If you want job concurrency refer to [new_async](new_async) and [AsyncChannelServer](AsyncChannelServer)
|
||||
///
|
||||
/// Example:
|
||||
/// ```no_run
|
||||
/// use serde::{Serialize,Deserialize};
|
||||
/// use rspc::transport::{channel, ClientTransporter,ServerTransporter};
|
||||
///
|
||||
/// #[derive(Serialize,Deserialize)]
|
||||
/// pub struct MyStruct;
|
||||
///
|
||||
/// #[rspc::service]
|
||||
|
|
@ -61,48 +65,56 @@ pub struct SyncChannelServer<T, R> {
|
|||
///
|
||||
/// let client = MyStructClient::new(client_channel);
|
||||
/// ```
|
||||
pub fn new_sync<T, R>() -> (ChannelClient<T, R>, SyncChannelServer<T, R>) {
|
||||
let (c, s) = mpsc::unbounded_channel();
|
||||
pub fn new_sync<T,R>() -> (ChannelClient<T,R>,SyncChannelServer<T,R>) {
|
||||
let (c,s) = mpsc::unbounded_channel();
|
||||
(
|
||||
ChannelClient { channel: c },
|
||||
SyncChannelServer { channel: s },
|
||||
)
|
||||
}
|
||||
|
||||
impl<T, R> ClientTransporter<T, R> for ChannelClient<T, R>
|
||||
impl<T,R> ChannelClient<T,R>
|
||||
where
|
||||
T: Send + Sync,
|
||||
R: Send + Sync,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
async fn request(&self, data: T) -> Result<R, Self::Error> {
|
||||
let (t, r) = oneshot::channel();
|
||||
self.channel
|
||||
.send((data, t))
|
||||
.map_err(|_| Error::ChannelSendError)?;
|
||||
pub async fn internal_request(&self, data: T) -> Result<R, Error> {
|
||||
let (t,r) = oneshot::channel();
|
||||
self.channel.send( (data, t) ).map_err(|_| Error::ChannelSendError)?;
|
||||
let output = r.await?;
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> ServerTransporter<T, R> for SyncChannelServer<T, R>
|
||||
#[async_trait]
|
||||
impl<T,R> ClientTransporter<T,R> for ChannelClient<T,R>
|
||||
where
|
||||
T: Send + Sync,
|
||||
R: Send + Sync,
|
||||
{
|
||||
|
||||
type Error = Error;
|
||||
|
||||
async fn listen<F, FR, D>(
|
||||
&mut self,
|
||||
handler: F,
|
||||
stop_response: Option<R>,
|
||||
userdata: D,
|
||||
) -> Result<(), Self::Error>
|
||||
async fn request(&self, data: T) -> Result<R, Self::Error> {
|
||||
self.internal_request(data).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T,R> ServerTransporter<T,R> for SyncChannelServer<T,R>
|
||||
where
|
||||
T: Send + Sync,
|
||||
R: Send + Sync,
|
||||
{
|
||||
|
||||
type Error = Error;
|
||||
|
||||
async fn listen<F, FR, D>(&mut self, handler: F, stop_response: Option<R>, userdata: D) -> Result<(), Self::Error>
|
||||
where
|
||||
FR: Future<Output = Option<R>> + Send,
|
||||
F: Fn(T, &D) -> FR + Send + Sync,
|
||||
D: Send + Sync,
|
||||
D: Send+Sync,
|
||||
{
|
||||
while let Some(msg) = self.channel.recv().await {
|
||||
match handler(msg.0, &userdata).await {
|
||||
|
|
@ -112,28 +124,30 @@ where
|
|||
msg.1.send(v).map_err(|_| Error::ChannelRespError)?;
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Server endpoint of an asynchronous channel.
|
||||
pub struct AsyncChannelServer<T,R> {
|
||||
channel: UnboundedReceiver<(T,oneshot::Sender<R>)>,
|
||||
}
|
||||
|
||||
/// Create a new asynchronous channel client/server instance.
|
||||
///
|
||||
/// Can process any number of jobs in parallel.
|
||||
///
|
||||
/// Unpon recieving a stop signal, pending jobs are finished and reponded to, but new jobs are not processed.
|
||||
/// Said new jobs will continue waiting until either the server listens again, or the server is dropped.
|
||||
pub struct AsyncChannelServer<T, R> {
|
||||
channel: UnboundedReceiver<(T, oneshot::Sender<R>)>,
|
||||
}
|
||||
|
||||
/// Create a new asynchronous channel client/server instance. See AsyncChannelServer
|
||||
///
|
||||
/// Example:
|
||||
/// ```no_run
|
||||
/// use serde::{Serialize,Deserialize};
|
||||
/// use rspc::transport::{channel, ClientTransporter,ServerTransporter};
|
||||
///
|
||||
/// #[derive(Serialize,Deserialize)]
|
||||
/// pub struct MyStruct;
|
||||
///
|
||||
/// #[rspc::service]
|
||||
|
|
@ -150,25 +164,20 @@ pub struct AsyncChannelServer<T, R> {
|
|||
///
|
||||
/// let client = MyStructClient::new(client_channel);
|
||||
/// ```
|
||||
pub fn new_async<T, R>() -> (ChannelClient<T, R>, AsyncChannelServer<T, R>) {
|
||||
let (c, s) = mpsc::unbounded_channel();
|
||||
pub fn new_async<T,R>() -> (ChannelClient<T,R>,AsyncChannelServer<T,R>) {
|
||||
let (c,s) = mpsc::unbounded_channel();
|
||||
(
|
||||
ChannelClient { channel: c },
|
||||
AsyncChannelServer { channel: s },
|
||||
)
|
||||
}
|
||||
|
||||
impl<T, R> AsyncChannelServer<T, R>
|
||||
impl<T,R> AsyncChannelServer<T,R>
|
||||
where
|
||||
T: Send + Sync,
|
||||
R: Send + Sync + 'static,
|
||||
{
|
||||
async fn internal_listen<F, FR, D>(
|
||||
&mut self,
|
||||
handler: F,
|
||||
stop_response: Option<R>,
|
||||
userdata: D,
|
||||
) -> Result<(), Error>
|
||||
async fn internal_listen<F, FR, D>(&mut self, handler: F, stop_response: Option<R>, userdata: D) -> Result<(), Error>
|
||||
where
|
||||
FR: Future<Output = Option<R>> + Send + 'static,
|
||||
F: Fn(T, &D) -> FR + Send + Sync,
|
||||
|
|
@ -176,7 +185,7 @@ where
|
|||
{
|
||||
let mut pending = FuturesUnordered::new();
|
||||
loop {
|
||||
tokio::select! {
|
||||
tokio::select!{
|
||||
Some(rcv) = self.channel.recv() => {
|
||||
pending.push(
|
||||
async {
|
||||
|
|
@ -203,33 +212,27 @@ where
|
|||
}
|
||||
|
||||
let results: Vec<_> = pending.collect().await;
|
||||
results
|
||||
.into_iter()
|
||||
.map(|r| -> Result<(), Error> {
|
||||
results.into_iter().map(|r| -> Result<(), Error> {
|
||||
match r {
|
||||
(Some(r), sender) => sender.send(r).map_err(|_| Error::ChannelRespError),
|
||||
(Some(r),sender) => sender.send(r).map_err(|_| Error::ChannelRespError),
|
||||
_ => Ok(()),
|
||||
}
|
||||
})
|
||||
.collect::<Result<Vec<_>, Error>>()?;
|
||||
}).collect::<Result<Vec<_>, Error>>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> ServerTransporter<T, R> for AsyncChannelServer<T, R>
|
||||
#[async_trait]
|
||||
impl<T,R> ServerTransporter<T,R> for AsyncChannelServer<T,R>
|
||||
where
|
||||
T: Send + Sync,
|
||||
R: Send + Sync + 'static,
|
||||
{
|
||||
|
||||
type Error = Error;
|
||||
|
||||
async fn listen<F, FR, D>(
|
||||
&mut self,
|
||||
handler: F,
|
||||
stop_response: Option<R>,
|
||||
userdata: D,
|
||||
) -> Result<(), Self::Error>
|
||||
async fn listen<F, FR, D>(&mut self, handler: F, stop_response: Option<R>, userdata: D) -> Result<(), Self::Error>
|
||||
where
|
||||
FR: Future<Output = Option<R>> + Send + 'static,
|
||||
F: Fn(T, &D) -> FR + Send + Sync,
|
||||
|
|
@ -242,16 +245,19 @@ where
|
|||
/// Create a channel multiplexer.
|
||||
///
|
||||
/// This is intended to be used with self-mutable clients to provide immutable clients to it
|
||||
pub fn new_multiplexer<T, R>() -> (ChannelClient<T, R>, Multiplexer<T, R>) {
|
||||
let (c, s) = mpsc::unbounded_channel();
|
||||
(ChannelClient { channel: c }, Multiplexer { channel: s })
|
||||
pub fn new_multiplexer<T,R>() -> (ChannelClient<T,R>,Multiplexer<T,R>) {
|
||||
let (c,s) = mpsc::unbounded_channel();
|
||||
(
|
||||
ChannelClient { channel: c },
|
||||
Multiplexer { channel: s },
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Multiplexer<T, R> {
|
||||
channel: UnboundedReceiver<(T, oneshot::Sender<R>)>,
|
||||
pub struct Multiplexer<T,R> {
|
||||
channel: UnboundedReceiver<(T,oneshot::Sender<R>)>,
|
||||
}
|
||||
|
||||
impl<T, R> Multiplexer<T, R>
|
||||
impl<T,R> Multiplexer<T,R>
|
||||
where
|
||||
T: Send + Sync,
|
||||
R: Send + Sync + 'static,
|
||||
|
|
@ -264,23 +270,17 @@ where
|
|||
/// - The 3rd party must be handling (usize,T) as input and (usize,R) as output
|
||||
/// - sender_send(sender) is the function used to send data to the 3rd party
|
||||
/// - listener_recv(listener) is the function used to recieve data from the 3rd party
|
||||
pub async fn start<S, SF, L, LF>(
|
||||
mut self,
|
||||
mut sender: S,
|
||||
sender_send: SF,
|
||||
mut listener: L,
|
||||
listener_recv: LF,
|
||||
) -> Result<(), Error>
|
||||
pub async fn start<S, SF, L, LF>(mut self, mut sender: S, sender_send: SF, mut listener: L, listener_recv: LF) -> Result<(), Error>
|
||||
where
|
||||
SF: Fn(&mut S, (usize, T)) -> BoxFuture<bool> + Send + Sync + 'static,
|
||||
LF: Fn(&mut L) -> BoxFuture<Option<(usize, R)>> + 'static,
|
||||
SF: Fn(&mut S, (usize,T)) -> BoxFuture<bool> + Send + Sync + 'static,
|
||||
LF: Fn(&mut L) -> BoxFuture<Option<(usize,R)>> + 'static,
|
||||
{
|
||||
let mut pending: BTreeMap<usize, oneshot::Sender<R>> = BTreeMap::new();
|
||||
|
||||
let mut id_counter: usize = 0;
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
tokio::select!{
|
||||
q = self.channel.recv() => {
|
||||
match q {
|
||||
Some(rcv) => {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
use futures::{future::BoxFuture, stream::FuturesUnordered, Future, StreamExt};
|
||||
use async_trait::async_trait;
|
||||
use futures::{Future, future::BoxFuture, stream::FuturesUnordered, StreamExt};
|
||||
|
||||
#[cfg(feature = "channel")]
|
||||
pub mod channel;
|
||||
#[cfg(feature = "serde")]
|
||||
pub mod serde;
|
||||
|
||||
/// Definition of a client transporter for RSPC.
|
||||
|
|
@ -11,9 +10,10 @@ pub mod serde;
|
|||
/// - ClientTransporter is a producer object, can be single-producer or multi-producer.
|
||||
/// - ClientTransporter must be immutable. If a client implementation requires self mutability,
|
||||
/// use Mutex, RwLock, or similar tools to mutate values without requiring self mutability
|
||||
pub trait ClientTransporter<T, R> {
|
||||
#[async_trait]
|
||||
pub trait ClientTransporter<T,R> {
|
||||
type Error: std::fmt::Debug;
|
||||
fn request(&self, data: T) -> impl std::future::Future<Output = Result<R, Self::Error>> + Send;
|
||||
async fn request(&self, data: T) -> Result<R, Self::Error>;
|
||||
}
|
||||
|
||||
/// Definition of a server transporter for RSPC.
|
||||
|
|
@ -22,29 +22,23 @@ pub trait ClientTransporter<T, R> {
|
|||
/// - ServerTransporter is a single-consumer object
|
||||
/// - Upon recieving a stop request (handler function return None), server must respond with stop_response if specified to only this request and none other.
|
||||
/// Finishing and responding to pending jobs is optional.
|
||||
pub trait ServerTransporter<T, R> {
|
||||
#[async_trait]
|
||||
pub trait ServerTransporter<T,R>
|
||||
{
|
||||
type Error: std::fmt::Debug;
|
||||
fn listen<F, FR, D>(
|
||||
&mut self,
|
||||
handler: F,
|
||||
stop_response: Option<R>,
|
||||
userdata: D,
|
||||
) -> impl std::future::Future<Output = Result<(), Self::Error>> + Send
|
||||
async fn listen<F, FR, D>(&mut self, handler: F, stop_response: Option<R>, userdata: D) -> Result<(), Self::Error>
|
||||
where
|
||||
FR: Future<Output = Option<R>> + Send + 'static,
|
||||
F: Fn(T, &D) -> FR + Send + Sync + Copy + 'static,
|
||||
D: Send + Sync + 'static;
|
||||
D: Send + Sync + 'static,
|
||||
;
|
||||
}
|
||||
|
||||
pub async fn async_listener<T, R, C, L, LF, S, SF, F, FR, D, E>(
|
||||
listener: &mut L,
|
||||
listener_recv: LF,
|
||||
sender: &mut S,
|
||||
sender_send: SF,
|
||||
handler: F,
|
||||
stop_response: Option<R>,
|
||||
userdata: &D,
|
||||
) -> Result<(), E>
|
||||
pub
|
||||
async fn async_listener<T, R, C, L, LF, S, SF, F, FR, D, E>(
|
||||
listener: &mut L, listener_recv: LF,
|
||||
sender: &mut S, sender_send: SF,
|
||||
handler: F, stop_response: Option<R>, userdata: &D) -> Result<(), E>
|
||||
where
|
||||
T: Send + Sync,
|
||||
R: Send + Sync + 'static,
|
||||
|
|
@ -52,12 +46,12 @@ where
|
|||
F: Fn(T, &D) -> FR + Send + Sync,
|
||||
D: Send + Sync + 'static,
|
||||
C: Send + Sync + 'static,
|
||||
SF: Fn(&mut S, (C, R)) -> BoxFuture<Result<(), E>> + Send + Sync + 'static,
|
||||
LF: Fn(&mut L) -> BoxFuture<Result<Option<(C, T)>, E>> + 'static,
|
||||
SF: Fn(&mut S, (C,R)) -> BoxFuture<Result<(), E>> + Send + Sync + 'static,
|
||||
LF: Fn(&mut L) -> BoxFuture<Result<Option<(C,T)>, E>> + 'static,
|
||||
{
|
||||
let mut pending = FuturesUnordered::new();
|
||||
loop {
|
||||
tokio::select! {
|
||||
tokio::select!{
|
||||
rcv = listener_recv(listener) => {
|
||||
match rcv? {
|
||||
Some((id, data)) => {
|
||||
|
|
@ -93,9 +87,9 @@ where
|
|||
let results: Vec<_> = pending.collect().await;
|
||||
for it in results {
|
||||
match it {
|
||||
(id, Some(r)) => {
|
||||
sender_send(sender, (id, r)).await?;
|
||||
}
|
||||
(id,Some(r)) => {
|
||||
sender_send(sender, (id,r)).await?;
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
use async_trait::async_trait;
|
||||
use futures::future::BoxFuture;
|
||||
use thiserror::Error;
|
||||
use futures::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::Ipv4Addr;
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use thiserror::Error;
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
//use tokio::net::tcp::{ReadHalf, WriteHalf};
|
||||
use tokio::io::{ReadHalf, WriteHalf};
|
||||
use tokio_serde::formats::*;
|
||||
use tokio::io::{ReadHalf,WriteHalf};
|
||||
use tokio_serde::SymmetricallyFramed;
|
||||
use tokio_serde::formats::*;
|
||||
use tokio_util::codec::{FramedRead, FramedWrite, LengthDelimitedCodec};
|
||||
|
||||
use super::channel::{self, ChannelClient, Multiplexer};
|
||||
use super::{ClientTransporter, ServerTransporter};
|
||||
use super::{ClientTransporter,ServerTransporter};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
|
|
@ -25,22 +26,19 @@ pub enum Error {
|
|||
type SymmetricalReader<T> = SymmetricallyFramed<
|
||||
FramedRead<ReadHalf<TcpStream>, LengthDelimitedCodec>,
|
||||
T,
|
||||
SymmetricalBincode<T>,
|
||||
>;
|
||||
SymmetricalBincode<T>>;
|
||||
|
||||
type SymmetricalWriter<T> = SymmetricallyFramed<
|
||||
FramedWrite<WriteHalf<TcpStream>, LengthDelimitedCodec>,
|
||||
T,
|
||||
SymmetricalBincode<T>,
|
||||
>;
|
||||
SymmetricalBincode<T>>;
|
||||
|
||||
pub struct Receiver<T> {
|
||||
pub reader: SymmetricalReader<T>,
|
||||
}
|
||||
|
||||
impl<T> Receiver<T>
|
||||
where
|
||||
SymmetricalReader<T>: TryStream<Ok = T> + Unpin,
|
||||
impl<T> Receiver<T> where
|
||||
SymmetricalReader<T> : TryStream<Ok=T> + Unpin,
|
||||
{
|
||||
pub async fn recv(&mut self) -> Result<Option<T>, Error> {
|
||||
if let Ok(msg) = self.reader.try_next().await {
|
||||
|
|
@ -55,131 +53,122 @@ pub struct Sender<T> {
|
|||
pub writer: SymmetricalWriter<T>,
|
||||
}
|
||||
|
||||
impl<T> Sender<T>
|
||||
where
|
||||
T: for<'a> Deserialize<'a> + Serialize + Unpin,
|
||||
impl<T> Sender<T> where
|
||||
T: for<'a> Deserialize<'a> + Serialize + Unpin
|
||||
{
|
||||
pub async fn send(&mut self, item: T) -> Result<(), Error> {
|
||||
self.writer.send(item).await.map_err(Error::IO)
|
||||
}
|
||||
}
|
||||
|
||||
async fn split<T, R>(socket: TcpStream) -> (Sender<(usize, T)>, Receiver<(usize, R)>) {
|
||||
|
||||
async fn split<T,R>(socket: TcpStream) -> (Sender<(usize, T)>, Receiver<(usize, R)>) {
|
||||
let (reader, writer) = tokio::io::split(socket);
|
||||
|
||||
let reader: FramedRead<ReadHalf<TcpStream>, LengthDelimitedCodec> =
|
||||
FramedRead::new(reader, LengthDelimitedCodec::new());
|
||||
let reader: SymmetricalReader<(usize, R)> =
|
||||
SymmetricallyFramed::new(reader, SymmetricalBincode::default());
|
||||
let reader: FramedRead<
|
||||
ReadHalf<TcpStream>,
|
||||
LengthDelimitedCodec,
|
||||
> = FramedRead::new(reader, LengthDelimitedCodec::new());
|
||||
let reader: SymmetricalReader<(usize, R)> = SymmetricallyFramed::new(
|
||||
reader, SymmetricalBincode::default());
|
||||
|
||||
let writer: FramedWrite<WriteHalf<TcpStream>, LengthDelimitedCodec> =
|
||||
FramedWrite::new(writer, LengthDelimitedCodec::new());
|
||||
let writer: FramedWrite<
|
||||
WriteHalf<TcpStream>,
|
||||
LengthDelimitedCodec,
|
||||
> = FramedWrite::new(writer, LengthDelimitedCodec::new());
|
||||
|
||||
let writer: SymmetricalWriter<(usize, T)> =
|
||||
SymmetricallyFramed::new(writer, SymmetricalBincode::default());
|
||||
let writer: SymmetricalWriter<(usize, T)> = SymmetricallyFramed::new(
|
||||
writer, SymmetricalBincode::default());
|
||||
|
||||
(Sender { writer }, Receiver { reader })
|
||||
(Sender{ writer }, Receiver{ reader })
|
||||
}
|
||||
|
||||
pub struct TcpClient<T, R> {
|
||||
pub struct TcpClient<T,R> {
|
||||
sender: Sender<(usize, T)>,
|
||||
receiver: Receiver<(usize, R)>,
|
||||
multiplexer: Option<Multiplexer<T, R>>,
|
||||
multiplexer: Option<Multiplexer<T,R>>,
|
||||
req_id: AtomicUsize,
|
||||
ghost: std::marker::PhantomData<(T, R)>,
|
||||
}
|
||||
pub struct TcpServer<T, R> {
|
||||
pub struct TcpServer<T,R> {
|
||||
listener: TcpListener,
|
||||
ghost: std::marker::PhantomData<(T, R)>,
|
||||
}
|
||||
|
||||
impl<T, R> TcpClient<T, R>
|
||||
|
||||
impl<T,R> TcpClient<T,R>
|
||||
where
|
||||
T: for<'a> Deserialize<'a> + Serialize + Send + Sync + Unpin + 'static,
|
||||
R: for<'a> Deserialize<'a> + Serialize + Send + Sync + Unpin + 'static,
|
||||
{
|
||||
pub async fn connect<A>(address: &A) -> Result<TcpClient<T, R>, Error>
|
||||
pub async fn connect<A>(address: &A) ->
|
||||
Result<TcpClient<T, R>, Error>
|
||||
where
|
||||
A: tokio::net::ToSocketAddrs + ?Sized,
|
||||
{
|
||||
let socket = TcpStream::connect(&address).await.map_err(Error::IO)?;
|
||||
|
||||
let (sender, receiver) = split(socket).await;
|
||||
let (sender,receiver) = split(socket).await;
|
||||
|
||||
Ok(TcpClient {
|
||||
sender,
|
||||
receiver,
|
||||
multiplexer: None,
|
||||
req_id: AtomicUsize::new(0),
|
||||
ghost: Default::default(),
|
||||
})
|
||||
Ok(TcpClient{ sender, receiver, multiplexer: None, req_id: AtomicUsize::new(0), ghost: Default::default() })
|
||||
}
|
||||
|
||||
pub async fn multiplex(
|
||||
self,
|
||||
) -> (
|
||||
ChannelClient<T, R>,
|
||||
BoxFuture<'static, Result<(), channel::Error>>,
|
||||
) {
|
||||
let (client, multiplexer) = channel::new_multiplexer::<T, R>();
|
||||
pub async fn multiplex(self) -> (ChannelClient<T,R>, BoxFuture<'static, Result<(), channel::Error>>) {
|
||||
let (client,multiplexer) = channel::new_multiplexer::<T,R>();
|
||||
|
||||
let fut = multiplexer.start(
|
||||
self.sender,
|
||||
|sender, data| Box::pin(async { sender.send(data).await.is_ok() }),
|
||||
|sender, data| { Box::pin(async {sender.send(data).await.is_ok()}) },
|
||||
self.receiver,
|
||||
|receiver| Box::pin(async { receiver.recv().await.map_or_else(|_| None, |x| x) }),
|
||||
|receiver| { Box::pin(async { receiver.recv().await.map_or_else(|_| None, |x| x) }) },
|
||||
);
|
||||
|
||||
(client, Box::pin(fut))
|
||||
}
|
||||
|
||||
pub async fn spawn(self) -> ChannelClient<T, R> {
|
||||
pub async fn spawn(self) -> ChannelClient<T,R> {
|
||||
let (client, job) = self.multiplex().await;
|
||||
tokio::spawn(job);
|
||||
client
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> TcpServer<T, R>
|
||||
where
|
||||
impl<T,R> TcpServer<T,R> where
|
||||
T: for<'a> Deserialize<'a> + Serialize,
|
||||
R: for<'a> Deserialize<'a> + Serialize,
|
||||
{
|
||||
pub async fn new(address: &Ipv4Addr, port: u16) -> Result<TcpServer<T, R>, Error> {
|
||||
|
||||
pub async fn new(address: &Ipv4Addr, port: u16) ->
|
||||
Result<TcpServer<T,R>, Error>
|
||||
{
|
||||
let address = format!("{}:{}", address, port);
|
||||
let listener = TcpListener::bind(&address).await.map_err(Error::IO)?;
|
||||
Ok(TcpServer {
|
||||
listener,
|
||||
ghost: Default::default(),
|
||||
})
|
||||
Ok(TcpServer{ listener, ghost: Default::default() })
|
||||
}
|
||||
|
||||
async fn accept(&mut self) -> Result<TcpStream, Error> {
|
||||
async fn accept(&mut self) -> Result<TcpStream, Error>
|
||||
{
|
||||
let (socket, address) = self.listener.accept().await.map_err(Error::IO)?;
|
||||
println!("connection accepted: {:?}", address);
|
||||
Ok(socket)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, R> ServerTransporter<T, R> for TcpServer<T, R>
|
||||
#[async_trait]
|
||||
impl<T,R> ServerTransporter<T,R> for TcpServer<T,R>
|
||||
where
|
||||
T: for<'a> Deserialize<'a> + Serialize + Send + Sync + Unpin,
|
||||
R: for<'a> Deserialize<'a> + Serialize + Send + Sync + Unpin,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
async fn listen<F, FR, D>(
|
||||
&mut self,
|
||||
handler: F,
|
||||
stop_response: Option<R>,
|
||||
userdata: D,
|
||||
) -> Result<(), Self::Error>
|
||||
async fn listen<F, FR, D>(&mut self, handler: F, stop_response: Option<R>, userdata: D) -> Result<(), Self::Error>
|
||||
where
|
||||
FR: Future<Output = Option<R>> + Send + 'static,
|
||||
F: Fn(T, &D) -> FR + Send + Sync,
|
||||
D: Send + Sync,
|
||||
{
|
||||
let (client, fut) = channel::new_multiplexer::<R, T>();
|
||||
let (client,fut) = channel::new_multiplexer::<R,T>();
|
||||
|
||||
// super::async_listener(
|
||||
// &mut receiver, |_self| { Box::pin(async {
|
||||
|
|
@ -191,7 +180,7 @@ where
|
|||
// handler, stop_response, &userdata);
|
||||
|
||||
while let Ok(mut stream) = self.accept().await {
|
||||
let (sender, receiver) = split::<R, T>(stream).await;
|
||||
let (sender,receiver) = split::<R,T>(stream).await;
|
||||
// tokio::spawn(async move {
|
||||
// super::async_listener(
|
||||
// &mut receiver, |_self| { Box::pin(async {
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
#[cfg(test)]
|
||||
#[cfg(feature = "channel")]
|
||||
mod tests {
|
||||
use rspc::transport::{channel, ClientTransporter, ServerTransporter};
|
||||
|
||||
pub struct MyStruct {
|
||||
my_vec: Vec<String>,
|
||||
}
|
||||
|
||||
#[rspc::service]
|
||||
impl MyStruct {
|
||||
pub fn len(&self) -> usize {
|
||||
self.my_vec.len()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, val: String) {
|
||||
self.my_vec.push(val)
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<String> {
|
||||
self.my_vec.pop()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test() {
|
||||
let my_data = MyStruct { my_vec: Vec::new() };
|
||||
let (c, s) = channel::new_async();
|
||||
|
||||
let srv_thread = tokio::spawn(async move {
|
||||
let mut server = MyStructServer::from(my_data);
|
||||
server.listen(s).await
|
||||
});
|
||||
|
||||
let client = MyStructClient::new(c);
|
||||
assert_eq!(client.len().await.unwrap(), 0);
|
||||
client.push("Hello world!".to_string()).await.unwrap();
|
||||
assert_eq!(client.len().await.unwrap(), 1);
|
||||
assert_eq!(
|
||||
client.pop().await.unwrap(),
|
||||
Some("Hello world!".to_string())
|
||||
);
|
||||
client.stop().await.unwrap();
|
||||
srv_thread.await.unwrap().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
#[cfg(test)]
|
||||
#[cfg(feature = "channel")]
|
||||
mod tests {
|
||||
use rspc::transport::{channel, ClientTransporter, ServerTransporter};
|
||||
|
||||
pub struct MyStruct {
|
||||
my_vec: Vec<String>,
|
||||
}
|
||||
|
||||
#[rspc::service]
|
||||
impl MyStruct {
|
||||
pub fn len(&self) -> usize {
|
||||
self.my_vec.len()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, val: String) {
|
||||
self.my_vec.push(val)
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<String> {
|
||||
self.my_vec.pop()
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test() {
|
||||
let my_data = MyStruct { my_vec: Vec::new() };
|
||||
let (c, s) = channel::new_sync();
|
||||
|
||||
let srv_thread = tokio::spawn(async move {
|
||||
let mut server = MyStructServer::from(my_data);
|
||||
server.listen(s).await
|
||||
});
|
||||
|
||||
let client = MyStructClient::new(c);
|
||||
assert_eq!(client.len().await.unwrap(), 0);
|
||||
client.push("Hello world!".to_string()).await.unwrap();
|
||||
assert_eq!(client.len().await.unwrap(), 1);
|
||||
assert_eq!(
|
||||
client.pop().await.unwrap(),
|
||||
Some("Hello world!".to_string())
|
||||
);
|
||||
client.stop().await.unwrap();
|
||||
srv_thread.await.unwrap().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
pub mod test_data;
|
||||
Loading…
Reference in a new issue