feat: tcp transport

- add tcp transport
- refactor examples
- improve proc macro
- add benchmark examples
This commit is contained in:
zawz 2026-07-04 11:14:25 +02:00
parent b619f79095
commit bc23b1a9db
13 changed files with 363 additions and 110 deletions

View file

@ -30,6 +30,8 @@ serde = { version = "1.0", features = ["derive"], optional = true }
[lib] [lib]
# [profile.release]
# debug = true
[[example]] [[example]]
name = "channel_sync" name = "channel_sync"
@ -39,6 +41,18 @@ required-features = ["channel"]
name = "channel_async" name = "channel_async"
required-features = ["channel"] required-features = ["channel"]
[[example]]
name = "channel_sync_benchmark"
required-features = ["channel"]
[[example]]
name = "channel_async_benchmark"
required-features = ["channel"]
[[example]] [[example]]
name = "tcp" name = "tcp"
required-features = ["serde"] required-features = ["serde"]
[[example]]
name = "tcp_benchmark"
required-features = ["serde"]

View file

@ -14,7 +14,10 @@ The Server implements read-write locking, there can be many reads at once, but o
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.
Currently only implements local thread messaging. Serialized TCP transport is unfinished. Current status:
- channel_sync : Implementation OK
- channel_async : Implementation OK, but beware of performance bottlenecks. If you are making lots of small calls, channel_sync is more fitting
- tcp : Functional, but server close handling uninmplemented yet
Example: Example:
```rs ```rs

View file

@ -16,23 +16,16 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}); });
let client = TestDataClient::new(c); let client = TestDataClient::new(c);
let clientref = &client;
let start_time = std::time::Instant::now();
let job1 = async { let job1 = async {
let now = std::time::Instant::now(); let now = std::time::Instant::now();
assert_eq!(DATASIZE, client.len().await.unwrap()); assert_eq!(267914296, client.fib(42).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())); println!("fib1: {}", dur_to_str(now.elapsed()));
}; };
let job2 = async { 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(); 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())); println!("calc: {}", dur_to_str(now.elapsed()));
@ -47,7 +40,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("fib2: {}", dur_to_str(now.elapsed())); println!("fib2: {}", dur_to_str(now.elapsed()));
let now = std::time::Instant::now(); let now = std::time::Instant::now();
clientref.push((false, TestEnum::NoValue)).await.unwrap(); assert_eq!(DATASIZE, client.len().await.unwrap());
println!("len: {}", dur_to_str(now.elapsed()));
let now = std::time::Instant::now();
client.push((false, TestEnum::NoValue)).await.unwrap();
println!("push: {}", dur_to_str(now.elapsed())); println!("push: {}", dur_to_str(now.elapsed()));
let now = std::time::Instant::now(); let now = std::time::Instant::now();
@ -56,6 +53,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}; };
join!(job1, job2); join!(job1, job2);
println!("total: {}", dur_to_str(start_time.elapsed()));
client.stop().await.unwrap(); client.stop().await.unwrap();
srv_thread.await.unwrap().unwrap(); srv_thread.await.unwrap().unwrap();

View file

@ -0,0 +1,39 @@
use futures::{stream::FuturesUnordered, StreamExt};
use rspc_dev_utilities::test_data::{
dur_to_str, make_test_data, TestData, TestDataClient, TestDataServer, CALLS_PER_THREAD,
DATASIZE, THREADS,
};
use rspc::transport;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
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 now = std::time::Instant::now();
{
let set = FuturesUnordered::new();
for _ in 0..THREADS {
set.push(async {
for _ in 0..CALLS_PER_THREAD {
client.heavy_calc().await.unwrap();
}
});
}
let _: Vec<_> = set.collect().await;
}
println!("time: {}", dur_to_str(now.elapsed()));
client.stop().await.unwrap();
srv_thread.await.unwrap().unwrap();
Ok(())
}

View file

@ -1,7 +1,7 @@
use futures::{stream::FuturesUnordered, StreamExt};
use rspc_dev_utilities::test_data::{ use rspc_dev_utilities::test_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 rspc::transport; use rspc::transport;
@ -16,46 +16,54 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}); });
let client = TestDataClient::new(c); let client = TestDataClient::new(c);
let clientref = &client;
let job1 = async { let start_time = std::time::Instant::now();
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(); let now = std::time::Instant::now();
assert_eq!(267914296, clientref.fib(42).await.unwrap()); assert_eq!(DATASIZE, client.len().await.unwrap());
println!("fib1: {}", dur_to_str(now.elapsed())); println!("len: {}", dur_to_str(now.elapsed()));
};
let job2 = async { let now = std::time::Instant::now();
let now = std::time::Instant::now(); client.push((false, TestEnum::NoValue)).await.unwrap();
assert_eq!(DATASIZE, client.len().await.unwrap()); println!("push: {}", dur_to_str(now.elapsed()));
println!("len: {}", dur_to_str(now.elapsed()));
let now = std::time::Instant::now(); let now = std::time::Instant::now();
assert_eq!(4, client.calc().await.unwrap().unwrap_or(0)); assert_eq!(DATASIZE + 1, client.len().await.unwrap());
println!("calc: {}", dur_to_str(now.elapsed())); println!("len: {}", dur_to_str(now.elapsed()));
let cdat = make_test_data(DATASIZE); let now = std::time::Instant::now();
let now = std::time::Instant::now(); assert_eq!(267914296, client.fib(42).await.unwrap());
assert_eq!(8, client.calc_add(cdat).await.unwrap().unwrap_or(0)); println!("fib1: {}", dur_to_str(now.elapsed()));
println!("calc_add: {}", dur_to_str(now.elapsed()));
let now = std::time::Instant::now(); let now = std::time::Instant::now();
assert_eq!(267914296, client.fib(42).await.unwrap()); assert_eq!(267914296, client.fib(42).await.unwrap());
println!("fib2: {}", dur_to_str(now.elapsed())); println!("fib2: {}", dur_to_str(now.elapsed()));
let now = std::time::Instant::now(); let now = std::time::Instant::now();
clientref.push((false, TestEnum::NoValue)).await.unwrap(); assert_eq!(4, client.calc().await.unwrap().unwrap_or(0));
println!("push: {}", dur_to_str(now.elapsed())); println!("calc: {}", dur_to_str(now.elapsed()));
let now = std::time::Instant::now(); let cdat = make_test_data(DATASIZE);
assert_eq!(DATASIZE + 1, client.len().await.unwrap()); let now = std::time::Instant::now();
println!("len: {}", dur_to_str(now.elapsed())); 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();
{
let set = FuturesUnordered::new();
for _ in 0..128 {
set.push(async {
for _ in 0..100000 {
client.calc().await.unwrap();
}
});
}
let _: Vec<_> = set.collect().await;
}
println!("benchmark: {}", dur_to_str(now.elapsed()));
println!("total: {}", dur_to_str(start_time.elapsed()));
join!(job1, job2);
client.stop().await.unwrap(); client.stop().await.unwrap();
srv_thread.await.unwrap().unwrap(); srv_thread.await.unwrap().unwrap();

View file

@ -0,0 +1,39 @@
use futures::{stream::FuturesUnordered, StreamExt};
use rspc_dev_utilities::test_data::{
dur_to_str, make_test_data, TestData, TestDataClient, TestDataServer, CALLS_PER_THREAD,
DATASIZE, THREADS,
};
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 now = std::time::Instant::now();
{
let set = FuturesUnordered::new();
for _ in 0..THREADS {
set.push(async {
for _ in 0..CALLS_PER_THREAD {
client.heavy_calc().await.unwrap();
}
});
}
let _: Vec<_> = set.collect().await;
}
println!("time: {}", dur_to_str(now.elapsed()));
client.stop().await.unwrap();
srv_thread.await.unwrap().unwrap();
Ok(())
}

View file

@ -1,38 +1,33 @@
use futures::{stream::FuturesUnordered, StreamExt};
use rspc_dev_utilities::test_data::{ use rspc_dev_utilities::test_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::serde::{TcpClient, TcpServer};
use rspc::transport;
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> { async fn main() -> Result<(), Box<dyn std::error::Error>> {
let data: TestData = make_test_data(DATASIZE);
let mut server = TestDataServer::from(data);
let t = TcpServer::new(&"127.0.0.1:6543").await.unwrap();
let srv_thread = tokio::spawn(async move { server.listen(t).await });
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
let t = TcpClient::connect("127.0.0.1:6543").await.unwrap(); let t = TcpClient::connect("127.0.0.1:6543").await.unwrap();
let client = t.spawn().await; let client = t.spawn().await;
// todo : server
let client = TestDataClient::new(client); let client = TestDataClient::new(client);
let clientref = &client; let start_time = std::time::Instant::now();
let job1 = async { let job1 = async {
let now = std::time::Instant::now(); let now = std::time::Instant::now();
assert_eq!(DATASIZE, client.len().await.unwrap()); assert_eq!(267914296, client.fib(42).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())); println!("fib1: {}", dur_to_str(now.elapsed()));
}; };
let job2 = async { 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(); 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())); println!("calc: {}", dur_to_str(now.elapsed()));
@ -47,7 +42,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("fib2: {}", dur_to_str(now.elapsed())); println!("fib2: {}", dur_to_str(now.elapsed()));
let now = std::time::Instant::now(); let now = std::time::Instant::now();
clientref.push((false, TestEnum::NoValue)).await.unwrap(); assert_eq!(DATASIZE, client.len().await.unwrap());
println!("len: {}", dur_to_str(now.elapsed()));
let now = std::time::Instant::now();
client.push((false, TestEnum::NoValue)).await.unwrap();
println!("push: {}", dur_to_str(now.elapsed())); println!("push: {}", dur_to_str(now.elapsed()));
let now = std::time::Instant::now(); let now = std::time::Instant::now();
@ -56,7 +55,27 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}; };
join!(job1, job2); join!(job1, job2);
let now = std::time::Instant::now();
{
let set = FuturesUnordered::new();
for _ in 0..128 {
set.push(async {
for _ in 0..100000 {
client.calc().await.unwrap();
}
});
}
let _: Vec<_> = set.collect().await;
}
println!("benchmark: {}", dur_to_str(now.elapsed()));
println!("total: {}", dur_to_str(start_time.elapsed()));
client.stop().await.unwrap(); client.stop().await.unwrap();
// todo : server stop
srv_thread.await;
Ok(()) Ok(())
} }

40
examples/tcp_benchmark.rs Normal file
View file

@ -0,0 +1,40 @@
use futures::{stream::FuturesUnordered, StreamExt};
use rspc_dev_utilities::test_data::{
dur_to_str, make_test_data, TestData, TestDataClient, TestDataServer, CALLS_PER_THREAD,
DATASIZE, THREADS,
};
use rspc::transport::serde::{TcpClient, TcpServer};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let data: TestData = make_test_data(DATASIZE);
let mut server = TestDataServer::from(data);
let t = TcpServer::new(&"127.0.0.1:6543").await.unwrap();
let srv_thread = tokio::spawn(async move { server.listen(t).await });
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
let t = TcpClient::connect("127.0.0.1:6543").await.unwrap();
let client = t.spawn().await;
let client = TestDataClient::new(client);
let now = std::time::Instant::now();
{
let set = FuturesUnordered::new();
for _ in 0..THREADS {
set.push(async {
for _ in 0..CALLS_PER_THREAD {
client.heavy_calc().await.unwrap();
}
});
}
let _: Vec<_> = set.collect().await;
}
println!("time: {}", dur_to_str(now.elapsed()));
client.stop().await.unwrap();
srv_thread.await.unwrap().unwrap();
Ok(())
}

View file

@ -316,7 +316,7 @@ pub fn service(_attr: TokenStream, mut input: TokenStream) -> TokenStream {
impl #server { impl #server {
pub async fn listen<Tr>(&mut self, mut transport: Tr) -> Result<(), Tr::Error> pub async fn listen<Tr>(&mut self, mut transport: Tr) -> Result<(), Tr::Error>
where where
Tr: ServerTransporter<#transport_request,#transport_response> + Send Tr: ::rspc::transport::ServerTransporter<#transport_request,#transport_response> + Send
{ {
{ {
transport.listen( |v,obj| { transport.listen( |v,obj| {
@ -339,14 +339,14 @@ pub fn service(_attr: TokenStream, mut input: TokenStream) -> TokenStream {
pub struct #client<Tr> pub struct #client<Tr>
where where
Tr: ClientTransporter<#transport_request,#transport_response>, Tr: ::rspc::transport::ClientTransporter<#transport_request,#transport_response>,
{ {
transporter: Tr, transporter: Tr,
} }
impl<Tr> #client<Tr> impl<Tr> #client<Tr>
where where
Tr: ClientTransporter<#transport_request,#transport_response> Tr: ::rspc::transport::ClientTransporter<#transport_request,#transport_response>
{ {
pub fn new(transporter: Tr) -> Self { pub fn new(transporter: Tr) -> Self {
#client { #client {

View file

@ -37,14 +37,14 @@ pub trait ServerTransporter<T, R> {
} }
pub async fn async_listener<T, R, C, L, LF, S, SF, F, FR, D, E>( pub async fn async_listener<T, R, C, L, LF, S, SF, F, FR, D, E>(
listener: &mut L, mut listener: L,
listener_recv: LF, listener_recv: LF,
sender: &mut S, mut sender: S,
sender_send: SF, sender_send: SF,
handler: F, handler: &F,
stop_response: Option<R>, stop_response: &Option<R>,
userdata: &D, userdata: &D,
) -> Result<(), E> ) -> Result<bool, E>
where where
T: Send + Sync, T: Send + Sync,
R: Send + Sync + 'static, R: Send + Sync + 'static,
@ -55,10 +55,11 @@ where
SF: Fn(&mut S, (C, R)) -> BoxFuture<Result<(), E>> + 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, LF: Fn(&mut L) -> BoxFuture<Result<Option<(C, T)>, E>> + 'static,
{ {
let mut stop = false;
let mut pending = FuturesUnordered::new(); let mut pending = FuturesUnordered::new();
loop { loop {
tokio::select! { tokio::select! {
rcv = listener_recv(listener) => { rcv = listener_recv(&mut listener) => {
match rcv? { match rcv? {
Some((id, data)) => { Some((id, data)) => {
pending.push( pending.push(
@ -76,12 +77,14 @@ where
Some(r) = pending.next() => { Some(r) = pending.next() => {
match r { match r {
(id,Some(r)) => { (id,Some(r)) => {
sender_send(sender, (id,r)).await?; sender_send(&mut sender, (id,r)).await?;
}, },
(id,None) => { (id,None) => {
if let Some(v) = stop_response { if let Some(v) = stop_response {
sender_send(sender, (id,v)).await?; todo!() // clone issue on R
// sender_send(&mut sender, (id,v)).await?;
} }
stop = true;
break; break;
}, },
} }
@ -94,11 +97,11 @@ where
for it in results { for it in results {
match it { match it {
(id, Some(r)) => { (id, Some(r)) => {
sender_send(sender, (id, r)).await?; sender_send(&mut sender, (id, r)).await?;
} }
_ => (), _ => (),
} }
} }
Ok(()) Ok(stop)
} }

View file

@ -1,7 +1,7 @@
use futures::future::BoxFuture; use futures::future::BoxFuture;
use futures::prelude::*; use futures::prelude::*;
use futures::stream::FuturesUnordered;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::net::Ipv4Addr;
use std::sync::atomic::AtomicUsize; use std::sync::atomic::AtomicUsize;
use thiserror::Error; use thiserror::Error;
use tokio::net::{TcpListener, TcpStream}; use tokio::net::{TcpListener, TcpStream};
@ -115,6 +115,8 @@ where
}) })
} }
/// Turn the TCP Client into a background process and a channel client multiplexer
#[cfg(feature = "channel")]
pub async fn multiplex( pub async fn multiplex(
self, self,
) -> ( ) -> (
@ -133,6 +135,8 @@ where
(client, Box::pin(fut)) (client, Box::pin(fut))
} }
/// Spawn a background client multiplexer and give a channel client
#[cfg(feature = "channel")]
pub async fn spawn(self) -> ChannelClient<T, R> { pub async fn spawn(self) -> ChannelClient<T, R> {
let (client, job) = self.multiplex().await; let (client, job) = self.multiplex().await;
tokio::spawn(job); tokio::spawn(job);
@ -140,14 +144,28 @@ where
} }
} }
impl<T, R> ClientTransporter<T, R> for TcpClient<T, R>
where
T: for<'a> Deserialize<'a> + Serialize + Send + Sync + Unpin + 'static,
R: for<'a> Deserialize<'a> + Serialize + Send + Sync + Unpin + 'static,
{
type Error = Error;
async fn request(&self, data: T) -> Result<R, Self::Error> {
todo!()
}
}
impl<T, R> TcpServer<T, R> impl<T, R> TcpServer<T, R>
where where
T: for<'a> Deserialize<'a> + Serialize, T: for<'a> Deserialize<'a> + Serialize,
R: 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<A>(address: &A) -> Result<TcpServer<T, R>, Error>
let address = format!("{}:{}", address, port); where
let listener = TcpListener::bind(&address).await.map_err(Error::IO)?; A: tokio::net::ToSocketAddrs + std::fmt::Display,
{
let listener = TcpListener::bind(address).await.map_err(Error::IO)?;
Ok(TcpServer { Ok(TcpServer {
listener, listener,
ghost: Default::default(), ghost: Default::default(),
@ -156,15 +174,14 @@ where
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)?; let (socket, address) = self.listener.accept().await.map_err(Error::IO)?;
println!("connection accepted: {:?}", address);
Ok(socket) Ok(socket)
} }
} }
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 + 'static,
R: for<'a> Deserialize<'a> + Serialize + Send + Sync + Unpin, R: for<'a> Deserialize<'a> + Serialize + Send + Sync + Unpin + 'static,
{ {
type Error = Error; type Error = Error;
@ -176,34 +193,45 @@ where
) -> Result<(), Self::Error> ) -> Result<(), Self::Error>
where where
FR: Future<Output = Option<R>> + Send + 'static, FR: Future<Output = Option<R>> + Send + 'static,
F: Fn(T, &D) -> FR + Send + Sync, F: Fn(T, &D) -> FR + Send + Sync + 'static,
D: Send + Sync, D: Send + Sync + 'static,
{ {
let (client, fut) = channel::new_multiplexer::<R, T>(); let mut connections = FuturesUnordered::new();
loop {
// super::async_listener( tokio::select! {
// &mut receiver, |_self| { Box::pin(async { connect = self.accept() => {
// _self.recv().await match connect {
// }) }, Ok(stream) => {
// &mut sender, |_self, data| { Box::pin(async { let (sender, receiver) = split::<R, T>(stream).await;
// _self.send(data).await let handler = &handler;
// }) }, let stop_response = &stop_response;
// handler, stop_response, &userdata); let userdata = &userdata;
connections.push(async move {
while let Ok(mut stream) = self.accept().await { super::async_listener(
let (sender, receiver) = split::<R, T>(stream).await; receiver,
// tokio::spawn(async move { |_self| Box::pin(async { _self.recv().await }),
// super::async_listener( sender,
// &mut receiver, |_self| { Box::pin(async { |_self, data| Box::pin(async { _self.send(data).await }),
// _self.recv().await handler,
// }) }, stop_response,
// &mut sender, |_self, data| { Box::pin(async { userdata,
// _self.send(data).await ).await
// }) }, });
// handler, stop_response, &userdata) },
// }); Err(e) => {
println!("WARN: connection accept error: {e}");
}
}
},
Some(s) = connections.next() => {
if let Ok(true) = s {
break;
}
// poll connected threads to get them running
}
}
} }
todo!() Ok(())
} }
} }

46
tests/tcp.rs Normal file
View file

@ -0,0 +1,46 @@
#[cfg(test)]
#[cfg(feature = "serde")]
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,7 +1,5 @@
use std::time::Duration; use std::time::Duration;
use rspc::transport::{ClientTransporter, ServerTransporter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub fn dur_to_num(dur: Duration) -> (u128, &'static str) { pub fn dur_to_num(dur: Duration) -> (u128, &'static str) {
@ -21,7 +19,9 @@ pub fn dur_to_str(dur: Duration) -> String {
n.to_string() + " " + s n.to_string() + " " + s
} }
pub const DATASIZE: usize = 1000000; pub const DATASIZE: usize = 10000;
pub const THREADS: usize = 8;
pub const CALLS_PER_THREAD: usize = 1000;
const TEST_STRINGS: [&str; 4] = ["toto", "tata", "titi", "tutu"]; const TEST_STRINGS: [&str; 4] = ["toto", "tata", "titi", "tutu"];
@ -39,6 +39,10 @@ pub struct TestData {
#[rspc::service] #[rspc::service]
impl TestData { impl TestData {
pub fn mem_size(&self) -> usize {
std::mem::size_of_val(&self.vec)
}
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.vec.len() self.vec.len()
} }
@ -52,6 +56,16 @@ impl TestData {
return None; return None;
} }
pub fn heavy_calc(&self) -> usize {
let mut res = 0;
for v in &self.vec {
if let (true, TestEnum::Num(n)) = v {
res += n;
}
}
return res;
}
pub async fn slow_fct(&self) -> Option<usize> { pub async fn slow_fct(&self) -> Option<usize> {
tokio::time::sleep(Duration::from_secs(1)).await; tokio::time::sleep(Duration::from_secs(1)).await;
self.calc() self.calc()