chore: code cleanup and folder restructuring

This commit is contained in:
zawz 2026-05-02 15:37:01 +02:00
parent a9d09e30f8
commit b619f79095
19 changed files with 438 additions and 1610 deletions

202
Cargo.lock generated
View file

@ -1,21 +1,6 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 4
[[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]] [[package]]
name = "aho-corasick" name = "aho-corasick"
@ -127,17 +112,6 @@ version = "4.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" 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]] [[package]]
name = "atomic-waker" name = "atomic-waker"
version = "1.1.2" version = "1.1.2"
@ -150,21 +124,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 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]] [[package]]
name = "bincode" name = "bincode"
version = "1.3.3" version = "1.3.3"
@ -263,7 +222,7 @@ dependencies = [
"num-traits", "num-traits",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.38", "syn 2.0.117",
] ]
[[package]] [[package]]
@ -273,7 +232,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
@ -368,7 +327,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.38", "syn 2.0.117",
] ]
[[package]] [[package]]
@ -414,12 +373,6 @@ dependencies = [
"windows", "windows",
] ]
[[package]]
name = "gimli"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]] [[package]]
name = "gloo-timers" name = "gloo-timers"
version = "0.2.6" version = "0.2.6"
@ -455,7 +408,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [ dependencies = [
"hermit-abi", "hermit-abi",
"libc", "libc",
"windows-sys", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
@ -490,9 +443,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.148" version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
@ -548,24 +501,15 @@ version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "miniz_oxide"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.8.8" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1"
dependencies = [ dependencies = [
"libc", "libc",
"wasi", "wasi",
"windows-sys", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@ -608,25 +552,6 @@ dependencies = [
"autocfg", "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]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.18.0" version = "1.18.0"
@ -694,7 +619,7 @@ checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.38", "syn 2.0.117",
] ]
[[package]] [[package]]
@ -733,23 +658,23 @@ dependencies = [
"libc", "libc",
"log", "log",
"pin-project-lite", "pin-project-lite",
"windows-sys", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.67" version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.33" version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -811,35 +736,35 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
name = "rspc" name = "rspc"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-std",
"async-trait",
"futures", "futures",
"oneshot", "oneshot",
"pin-project", "rspc_dev_utilities",
"rspc_macros", "rspc_macros",
"serde", "serde",
"serde_json",
"syn 2.0.38",
"thiserror", "thiserror",
"tokio", "tokio",
"tokio-serde", "tokio-serde",
"tokio-util", "tokio-util",
] ]
[[package]]
name = "rspc_dev_utilities"
version = "0.1.0"
dependencies = [
"async-std",
"rspc",
"serde",
"tokio",
]
[[package]] [[package]]
name = "rspc_macros" name = "rspc_macros"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"quote", "quote",
"syn 2.0.38", "syn 2.0.117",
] ]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.37.25" version = "0.37.25"
@ -851,7 +776,7 @@ dependencies = [
"io-lifetimes", "io-lifetimes",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
"windows-sys", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
@ -880,22 +805,32 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.189" version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" 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"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.189" version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.38", "syn 2.0.117",
] ]
[[package]] [[package]]
@ -954,12 +889,12 @@ dependencies = [
[[package]] [[package]]
name = "socket2" name = "socket2"
version = "0.5.4" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
@ -975,9 +910,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.38" version = "2.0.117"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1001,7 +936,7 @@ checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.38", "syn 2.0.117",
] ]
[[package]] [[package]]
@ -1016,32 +951,30 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.32.0" version = "1.52.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6"
dependencies = [ dependencies = [
"backtrace",
"bytes", "bytes",
"libc", "libc",
"mio", "mio",
"num_cpus",
"parking_lot", "parking_lot",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"socket2 0.5.4", "socket2 0.6.3",
"tokio-macros", "tokio-macros",
"windows-sys", "windows-sys 0.61.2",
] ]
[[package]] [[package]]
name = "tokio-macros" name = "tokio-macros"
version = "2.1.0" version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.38", "syn 2.0.117",
] ]
[[package]] [[package]]
@ -1093,7 +1026,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.38", "syn 2.0.117",
] ]
[[package]] [[package]]
@ -1186,7 +1119,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.38", "syn 2.0.117",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -1220,7 +1153,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.38", "syn 2.0.117",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -1272,6 +1205,12 @@ dependencies = [
"windows-targets", "windows-targets",
] ]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.48.0" version = "0.48.0"
@ -1281,6 +1220,15 @@ dependencies = [
"windows-targets", "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]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.48.5" version = "0.48.5"

View file

@ -1,22 +1,44 @@
[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] [package]
name = "rspc" name = "rspc"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
include = ["/src"]
[dependencies] [dependencies]
serde = { version = "1.0", features = ["derive"] }
futures = "0.3"
tokio = { version = "1.0", features = ["full"] }
syn = { version = "2.0", features = ["full"] }
rspc_macros = { path = "macros", version = "0.1" } rspc_macros = { path = "macros", version = "0.1" }
# necessary dependencies
futures = "0.3"
thiserror = "1.0.49" thiserror = "1.0.49"
async-trait = "0.1.73" tokio = { version = "1.0", features = ["full"] }
async-std = "1.12.0"
tokio-serde = { version = "0.8.0", features=["json","bincode"] } tokio-serde = { version = "0.8.0", features=["json","bincode"] }
pin-project = "1.1.3"
tokio-util = { version = "0.7.10", features=["codec"] } tokio-util = { version = "0.7.10", features=["codec"] }
serde_json = "1.0.108" oneshot = { version = "0.1.6", features=["std"], optional = true }
oneshot = { version = "0.1.6", features=["std"] } serde = { version = "1.0", features = ["derive"], optional = true }
[lib] [lib]
[[example]]
name = "channel_sync"
required-features = ["channel"]
[[example]]
name = "channel_async"
required-features = ["channel"]
[[example]]
name = "tcp"
required-features = ["serde"]

View file

@ -3,12 +3,14 @@
Proof of concept RPC framework focused on ease of use. Proof of concept RPC framework focused on ease of use.
It works by calling the macro `#[rspc::service]` on an impl block, It works by calling the macro `#[rspc::service]` on an impl block,
and code is generated for the resulting Server and Client objects. 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 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 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. 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.
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 Client object cannot be cloned. Instead all function calls are immutable, so a reference can be shared to all. The Client object cannot be cloned. Instead all function calls are immutable, so a reference can be shared to all.
@ -17,7 +19,6 @@ Currently only implements local thread messaging. Serialized TCP transport is un
Example: Example:
```rs ```rs
use rspc::transport::{channel, ClientTransporter,ServerTransporter}; use rspc::transport::{channel, ClientTransporter,ServerTransporter};
use rspc::service;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -26,7 +27,8 @@ pub struct MyStruct {
my_vec: Vec<String>, my_vec: Vec<String>,
} }
#[service] // Functions to instanciate as RPC
#[rspc::service]
impl MyStruct impl MyStruct
{ {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
@ -44,9 +46,11 @@ impl MyStruct
#[tokio::test] #[tokio::test]
async fn test() { async fn test() {
// Create the server data structure
let my_data = MyStruct { let my_data = MyStruct {
my_vec: Vec::new(), my_vec: Vec::new(),
}; };
// Instanciate a client and server
let (c,s) = channel::new_async(); let (c,s) = channel::new_async();
let srv_thread = tokio::spawn(async move { let srv_thread = tokio::spawn(async move {
@ -65,3 +69,10 @@ async fn test() {
``` ```
See [example](example) for an more detailed example usage 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

File diff suppressed because it is too large Load diff

View file

@ -1,21 +1,12 @@
pub mod data; use rspc_dev_utilities::test_data::{
use data::{
dur_to_str, make_test_data, TestData, TestDataClient, TestDataServer, TestEnum, DATASIZE, dur_to_str, make_test_data, TestData, TestDataClient, TestDataServer, TestEnum, DATASIZE,
}; };
use tokio::join; use tokio::join;
use rspc::transport::serde::TcpClient;
use rspc::transport; use rspc::transport;
#[tokio::main] #[tokio::main]
async fn main() -> anyhow::Result<()> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 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 (c, s) = transport::channel::new_async();
let data: TestData = make_test_data(DATASIZE); let data: TestData = make_test_data(DATASIZE);

63
examples/channel_sync.rs Normal file
View file

@ -0,0 +1,63 @@
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(())
}

62
examples/tcp.rs Normal file
View file

@ -0,0 +1,62 @@
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 Normal file
View file

@ -0,0 +1,46 @@
# 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"

View file

@ -5,6 +5,10 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
full = ["serde"]
serde = []
[dependencies] [dependencies]
#anyhow = "1.0" #anyhow = "1.0"
#futures = "0.3" #futures = "0.3"

View file

@ -48,7 +48,7 @@ fn snake_to_upper_camel(ident_str: &str) -> String {
} }
struct RpcMethod { struct RpcMethod {
pub attrs: Vec<Attribute>, pub _attrs: Vec<Attribute>,
pub sig: Signature, pub sig: Signature,
pub reciever: Option<Receiver>, pub reciever: Option<Receiver>,
pub args: Vec<PatType>, pub args: Vec<PatType>,
@ -57,8 +57,8 @@ struct RpcMethod {
struct Service { struct Service {
pub ident: Ident, pub ident: Ident,
pub rpcs: Vec<RpcMethod>, pub rpcs: Vec<RpcMethod>,
pub item: ItemImpl, pub _item: ItemImpl,
pub types: Vec<ImplItemType>, pub _types: Vec<ImplItemType>,
} }
impl TryFrom<ImplItemFn> for RpcMethod { impl TryFrom<ImplItemFn> for RpcMethod {
@ -93,7 +93,7 @@ impl TryFrom<ImplItemFn> for RpcMethod {
} }
Ok(RpcMethod { Ok(RpcMethod {
attrs: value.attrs, _attrs: value.attrs,
sig: value.sig, sig: value.sig,
reciever, reciever,
args, args,
@ -178,8 +178,8 @@ impl Parse for Service {
Ok(Self { Ok(Self {
ident, ident,
rpcs, rpcs,
item, _item: item,
types: typeitems, _types: typeitems,
}) })
} }
} }
@ -191,8 +191,8 @@ pub fn service(_attr: TokenStream, mut input: TokenStream) -> TokenStream {
let Service { let Service {
ident, ident,
rpcs, rpcs,
item: _, _item: _,
types: _, _types: _,
} = parse_macro_input!(inputclone as Service); } = parse_macro_input!(inputclone as Service);
let transport_request = &format_ident!("{}TransportRequest", ident); let transport_request = &format_ident!("{}TransportRequest", ident);
@ -269,15 +269,21 @@ pub fn service(_attr: TokenStream, mut input: TokenStream) -> TokenStream {
}) })
.collect(); .collect();
let serde_derives = if cfg!(feature = "serde") {
quote! { serde::Serialize, serde::Deserialize }
} else {
quote! {}
};
let t = quote! { let t = quote! {
#[derive(PartialEq,Debug,Serialize,Deserialize)] #[derive(PartialEq, Debug, #serde_derives)]
pub enum #transport_request { pub enum #transport_request {
#( #fn_names_camel(#arg_types) ),* , #( #fn_names_camel(#arg_types) ),* ,
Stop, Stop,
} }
#[derive(PartialEq,Debug,Serialize,Deserialize)] #[derive(PartialEq, Debug, #serde_derives)]
pub enum #transport_response { pub enum #transport_response {
#( #fn_names_camel(#outs) ),* , #( #fn_names_camel(#outs) ),* ,
Stop, Stop,
@ -296,13 +302,13 @@ pub fn service(_attr: TokenStream, mut input: TokenStream) -> TokenStream {
} }
pub struct #server { pub struct #server {
obj: std::sync::Arc<async_std::sync::RwLock<#ident>>, obj: std::sync::Arc<tokio::sync::RwLock<#ident>>,
} }
impl From<#ident> for #server { impl From<#ident> for #server {
fn from(obj: #ident) -> Self { fn from(obj: #ident) -> Self {
Self { Self {
obj: std::sync::Arc::new(async_std::sync::RwLock::new(obj)), obj: std::sync::Arc::new(tokio::sync::RwLock::new(obj)),
} }
} }
} }

View file

@ -1,55 +1,2 @@
pub mod transport; pub mod transport;
pub use rspc_macros::service; 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();
}
}

View file

@ -7,8 +7,6 @@ use thiserror::Error;
use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender}; use tokio::sync::mpsc::{self, UnboundedReceiver, UnboundedSender};
use tokio::sync::oneshot; use tokio::sync::oneshot;
use async_trait::async_trait;
use super::{ClientTransporter, ServerTransporter}; use super::{ClientTransporter, ServerTransporter};
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -29,25 +27,24 @@ pub struct ChannelClient<T, R> {
channel: UnboundedSender<(T, oneshot::Sender<R>)>, channel: UnboundedSender<(T, oneshot::Sender<R>)>,
} }
/// Server endpoint of a synchronous channel /// Server endpoint of a synchronous channel.
///
/// Synchronous channels can only process one job at a time. If you want job concurrency refer to [new_async](new_async) and [AsyncChannelServer](AsyncChannelServer)
///
/// 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> { pub struct SyncChannelServer<T, R> {
channel: UnboundedReceiver<(T, oneshot::Sender<R>)>, channel: UnboundedReceiver<(T, oneshot::Sender<R>)>,
} }
/// Create a new synchronous channel client/server instance. /// Create a new synchronous channel client/server instance. See [SyncChannelServer](SyncChannelServer)
/// ///
/// Synchronous channels can only process one job at a time. /// Synchronous channels can only process one job at a time. If you want job concurrency refer to [new_async](new_async) and [AsyncChannelServer](AsyncChannelServer)
/// 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.
/// ///
/// Example: /// Example:
/// ```no_run /// ```no_run
/// use serde::{Serialize,Deserialize};
/// use rspc::transport::{channel, ClientTransporter,ServerTransporter}; /// use rspc::transport::{channel, ClientTransporter,ServerTransporter};
/// ///
/// #[derive(Serialize,Deserialize)]
/// pub struct MyStruct; /// pub struct MyStruct;
/// ///
/// #[rspc::service] /// #[rspc::service]
@ -72,12 +69,14 @@ pub fn new_sync<T, R>() -> (ChannelClient<T, R>, SyncChannelServer<T, R>) {
) )
} }
impl<T, R> ChannelClient<T, R> impl<T, R> ClientTransporter<T, R> for ChannelClient<T, R>
where where
T: Send + Sync, T: Send + Sync,
R: Send + Sync, R: Send + Sync,
{ {
pub async fn internal_request(&self, data: T) -> Result<R, Error> { type Error = Error;
async fn request(&self, data: T) -> Result<R, Self::Error> {
let (t, r) = oneshot::channel(); let (t, r) = oneshot::channel();
self.channel self.channel
.send((data, t)) .send((data, t))
@ -87,20 +86,6 @@ where
} }
} }
#[async_trait]
impl<T, R> ClientTransporter<T, R> for ChannelClient<T, R>
where
T: Send + Sync,
R: Send + Sync,
{
type Error = 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> impl<T, R> ServerTransporter<T, R> for SyncChannelServer<T, R>
where where
T: Send + Sync, T: Send + Sync,
@ -134,23 +119,21 @@ where
} }
} }
pub struct AsyncChannelServer<T, R> { /// Server endpoint of an asynchronous channel.
channel: UnboundedReceiver<(T, oneshot::Sender<R>)>,
}
/// Create a new asynchronous channel client/server instance.
///
/// Can process any number of jobs in parallel. /// 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. /// 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. /// 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: /// Example:
/// ```no_run /// ```no_run
/// use serde::{Serialize,Deserialize};
/// use rspc::transport::{channel, ClientTransporter,ServerTransporter}; /// use rspc::transport::{channel, ClientTransporter,ServerTransporter};
/// ///
/// #[derive(Serialize,Deserialize)]
/// pub struct MyStruct; /// pub struct MyStruct;
/// ///
/// #[rspc::service] /// #[rspc::service]
@ -234,7 +217,6 @@ where
} }
} }
#[async_trait]
impl<T, R> ServerTransporter<T, R> for AsyncChannelServer<T, R> impl<T, R> ServerTransporter<T, R> for AsyncChannelServer<T, R>
where where
T: Send + Sync, T: Send + Sync,

View file

@ -1,7 +1,8 @@
use async_trait::async_trait;
use futures::{future::BoxFuture, stream::FuturesUnordered, Future, StreamExt}; use futures::{future::BoxFuture, stream::FuturesUnordered, Future, StreamExt};
#[cfg(feature = "channel")]
pub mod channel; pub mod channel;
#[cfg(feature = "serde")]
pub mod serde; pub mod serde;
/// Definition of a client transporter for RSPC. /// Definition of a client transporter for RSPC.
@ -10,10 +11,9 @@ pub mod serde;
/// - ClientTransporter is a producer object, can be single-producer or multi-producer. /// - ClientTransporter is a producer object, can be single-producer or multi-producer.
/// - ClientTransporter must be immutable. If a client implementation requires self mutability, /// - ClientTransporter must be immutable. If a client implementation requires self mutability,
/// use Mutex, RwLock, or similar tools to mutate values without requiring self mutability /// use Mutex, RwLock, or similar tools to mutate values without requiring self mutability
#[async_trait]
pub trait ClientTransporter<T, R> { pub trait ClientTransporter<T, R> {
type Error: std::fmt::Debug; type Error: std::fmt::Debug;
async fn request(&self, data: T) -> Result<R, Self::Error>; fn request(&self, data: T) -> impl std::future::Future<Output = Result<R, Self::Error>> + Send;
} }
/// Definition of a server transporter for RSPC. /// Definition of a server transporter for RSPC.
@ -22,15 +22,14 @@ pub trait ClientTransporter<T, R> {
/// - ServerTransporter is a single-consumer object /// - 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. /// - 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. /// Finishing and responding to pending jobs is optional.
#[async_trait]
pub trait ServerTransporter<T, R> { pub trait ServerTransporter<T, R> {
type Error: std::fmt::Debug; type Error: std::fmt::Debug;
async fn listen<F, FR, D>( fn listen<F, FR, D>(
&mut self, &mut self,
handler: F, handler: F,
stop_response: Option<R>, stop_response: Option<R>,
userdata: D, userdata: D,
) -> Result<(), Self::Error> ) -> impl std::future::Future<Output = Result<(), Self::Error>> + Send
where where
FR: Future<Output = Option<R>> + Send + 'static, FR: Future<Output = Option<R>> + Send + 'static,
F: Fn(T, &D) -> FR + Send + Sync + Copy + 'static, F: Fn(T, &D) -> FR + Send + Sync + Copy + 'static,

View file

@ -1,4 +1,3 @@
use async_trait::async_trait;
use futures::future::BoxFuture; use futures::future::BoxFuture;
use futures::prelude::*; use futures::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -162,7 +161,6 @@ where
} }
} }
#[async_trait]
impl<T, R> ServerTransporter<T, R> for TcpServer<T, R> impl<T, R> ServerTransporter<T, R> for TcpServer<T, R>
where where
T: for<'a> Deserialize<'a> + Serialize + Send + Sync + Unpin, T: for<'a> Deserialize<'a> + Serialize + Send + Sync + Unpin,

46
tests/channel_async.rs Normal file
View file

@ -0,0 +1,46 @@
#[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();
}
}

46
tests/channel_sync.rs Normal file
View file

@ -0,0 +1,46 @@
#[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();
}
}

View file

@ -1,13 +1,12 @@
[package] [package]
name = "rspc_example" name = "rspc_dev_utilities"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
anyhow = "1.0.86"
async-std = "1.12.0"
rspc = { path = ".." } rspc = { path = ".." }
serde = "1.0.203" serde = { version = "1.0", features = ["derive"] }
tokio = "1.38.0" async-std = "1.12.0"
tokio = { version = "1.0", features = ["full"] }

1
utilities/src/lib.rs Normal file
View file

@ -0,0 +1 @@
pub mod test_data;

View file

@ -1,8 +1,8 @@
use std::time::Duration; use std::time::Duration;
use serde::{Deserialize, Serialize}; use rspc::transport::{ClientTransporter, ServerTransporter};
pub type RetData = (usize, Option<usize>); use serde::{Deserialize, Serialize};
pub fn dur_to_num(dur: Duration) -> (u128, &'static str) { pub fn dur_to_num(dur: Duration) -> (u128, &'static str) {
if dur.as_nanos() < 10000 { if dur.as_nanos() < 10000 {
@ -21,14 +21,6 @@ pub fn dur_to_str(dur: Duration) -> String {
n.to_string() + " " + s 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; pub const DATASIZE: usize = 1000000;
const TEST_STRINGS: [&str; 4] = ["toto", "tata", "titi", "tutu"]; const TEST_STRINGS: [&str; 4] = ["toto", "tata", "titi", "tutu"];
@ -45,8 +37,6 @@ pub struct TestData {
vec: Vec<(bool, TestEnum)>, vec: Vec<(bool, TestEnum)>,
} }
use crate::transport::{ClientTransporter, ServerTransporter};
#[rspc::service] #[rspc::service]
impl TestData { impl TestData {
pub fn len(&self) -> usize { pub fn len(&self) -> usize {