pu-239
pu-239 allows you to write server-side functions directly within your client-side code. It simplifies client-server communication by automating the serialization and transmission of function calls and their responses, as well as keeps relevant code closer together in an isomorphic applicaiton.
Probably most useful for small projects or prototyping.
Usage
Add pu-239, postcard and anyhow to your Cargo.toml:
[]
= "*"
= { = "1", = ["use-std"] }
= "1"
Defining Server-Side Functions in Client Code
In your client code, annotate functions with #[pu_239::server] (do not import or rename the pu_239::server macro or the server end won't be able to find these). These functions will be replaced with a shim that serializes (with postcard) the arguments and sends to crate::api::dispatch (see below). It will have the same visibility as your server's api module, which is where the body will be eventually pasted.
pub async
// ----- crate::api module -----
// totally free to swap out reqwest with any other http client
pub async
Generating the Server API Dispatcher
On the server, route requests to a service of your choosing, then call pu239::build_api! to generate the deserialize_api_match function.
// e.g. with actix-web
new
.run.await?;
// ----- crate::api module -----
build_api!;
pub async
Making sure server rebuilds when client code changes
For example, using change-detection, specify a build.rs for your server to track changes in the client code. If you don't do this - the pu_239::build_api! macro won't rerun if any of your client-defined serverside functions change.
Calling Functions from Client Code
Call the server-side functions from your client code as if they were local async functions.
let result = some_serverside_fn.await;
How It Works
- The
#[pu_239::server]macro on the client transforms the function into a stub that serializes the arguments and sends them to the server. - On the server,
pu_239::build_api!crawls client source code to find all#[pu_239::server]functions, copy-pastes their bodies (preserving module structure) and generatesdeserialize_api_match.
pub async
// turns into
pub async
// on the server
pub async
async
Limitations
- Compile errors in
#[pu_239::server]will point atpu239::build_api!instead of the actual function - Serverside functions in
include!("some/path/foo.rs")or#[path = "foo.rs"] mod c;will not work - Functions are distinguished by body hashes so changing any tokens in it will change the hash
TODO:
- Remove dependency on
anyhow - Fix serverside fn compile error spans? not sure if possible
- Allow users to pick their own serialization library (not just postcard)
- Have actual examples that actually compile
- Macro parameters that can change client-side module/function path, server-side deserialize fn name, etc
- Alternative hashing strategies so server compiled with a different body but same signature can still match, at least sometimes?