# rspc
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.
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 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.
Example:
```rs
use rspc::transport::{channel, ClientTransporter,ServerTransporter};
use serde::{Deserialize, Serialize};
#[derive(Serialize,Deserialize)]
pub struct MyStruct {
my_vec: Vec,
}
// Functions to instanciate as RPC
#[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 {
self.my_vec.pop()
}
}
#[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 {
let mut server = MyDataServer::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();
}
```
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