Skip to content

Commit

Permalink
rpc-rs docs
Browse files Browse the repository at this point in the history
  • Loading branch information
RedstoneWizard08 committed Jul 10, 2024
1 parent ed8c3f4 commit 0d15141
Show file tree
Hide file tree
Showing 15 changed files with 129 additions and 4 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/rpc-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rpc-rs"
version.workspace = true
version = "0.1.0"
edition.workspace = true
license.workspace = true
repository.workspace = true
Expand Down
9 changes: 9 additions & 0 deletions crates/rpc-rs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
//! # rpc-rs
//!
//! A simple IPC/RPC framework for Rust and TypeScript,
//! built for Tauri and web apps.
#![warn(missing_docs)]
#![feature(associated_type_defaults, trait_alias, async_closure)]

pub mod macros;
pub mod module;
pub mod proc;
pub mod router;
pub mod util;

pub use router::{Router, Method};
pub use module::{Module, ModuleBuilder};
2 changes: 2 additions & 0 deletions crates/rpc-rs/src/macros.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! Macros for `rpc-rs`.
/// A macro to create a module for a prisma-client-rust module.
/// Your client must be an `Arc<...>`, as the state of the router.
///
Expand Down
13 changes: 13 additions & 0 deletions crates/rpc-rs/src/module/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@ use crate::{proc::GenericProcedure, util::TripleS};

use super::module::Module;

/// A builder for a [`Module`].
pub struct ModuleBuilder<Cx: TripleS + Clone> {
/// The handler for [`rpc_rs::Method::Create`] calls.
pub(crate) create: Option<Box<dyn GenericProcedure<Cx> + TripleS>>,

/// The handler for [`rpc_rs::Method::Read`] calls.
pub(crate) read: Option<Box<dyn GenericProcedure<Cx> + TripleS>>,

/// The handler for [`rpc_rs::Method::Update`] calls.
pub(crate) update: Option<Box<dyn GenericProcedure<Cx> + TripleS>>,

/// The handler for [`rpc_rs::Method::Delete`] calls.
pub(crate) delete: Option<Box<dyn GenericProcedure<Cx> + TripleS>>,
}

Expand All @@ -21,26 +29,31 @@ impl<Cx: TripleS + Clone> Default for ModuleBuilder<Cx> {
}

impl<Cx: TripleS + Clone> ModuleBuilder<Cx> {
/// Attach a handler for [`rpc_rs::Method::Create`].
pub fn create<Proc: GenericProcedure<Cx> + TripleS>(mut self, proc: Proc) -> Self {
self.create = Some(Box::new(proc));
self
}

/// Attach a handler for [`rpc_rs::Method::Read`].
pub fn read<Proc: GenericProcedure<Cx> + TripleS>(mut self, proc: Proc) -> Self {
self.read = Some(Box::new(proc));
self
}

/// Attach a handler for [`rpc_rs::Method::Update`].
pub fn update<Proc: GenericProcedure<Cx> + TripleS>(mut self, proc: Proc) -> Self {
self.update = Some(Box::new(proc));
self
}

/// Attach a handler for [`rpc_rs::Method::Delete`].
pub fn delete<Proc: GenericProcedure<Cx> + TripleS>(mut self, proc: Proc) -> Self {
self.delete = Some(Box::new(proc));
self
}

/// Build this [`ModuleBuilder`], converting it into a [`Module`].
pub fn build(self) -> Module<Cx> {
Module::new(self)
}
Expand Down
3 changes: 3 additions & 0 deletions crates/rpc-rs/src/module/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
pub mod builder;
pub mod module;

pub use module::Module;
pub use builder::ModuleBuilder;
12 changes: 12 additions & 0 deletions crates/rpc-rs/src/module/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,24 @@ use crate::{

use super::builder::ModuleBuilder;

/// A module.
#[derive(Clone)]
pub struct Module<Cx: TripleS + Clone> {
/// The handler for [`rpc_rs::Method::Create`] calls.
pub(crate) create: Arc<Box<dyn GenericProcedure<Cx> + TripleS>>,

/// The handler for [`rpc_rs::Method::Read`] calls.
pub(crate) read: Arc<Box<dyn GenericProcedure<Cx> + TripleS>>,

/// The handler for [`rpc_rs::Method::Update`] calls.
pub(crate) update: Arc<Box<dyn GenericProcedure<Cx> + TripleS>>,

/// The handler for [`rpc_rs::Method::Delete`] calls.
pub(crate) delete: Arc<Box<dyn GenericProcedure<Cx> + TripleS>>,
}

impl<Cx: TripleS + Clone> Module<Cx> {
/// Create a new [`Module`] from a [`ModuleBuilder`].
pub(crate) fn new(builder: ModuleBuilder<Cx>) -> Self {
Self {
create: Arc::new(
Expand All @@ -44,10 +53,12 @@ impl<Cx: TripleS + Clone> Module<Cx> {
}
}

/// The default handler for any unhandled call.
pub(crate) async fn error_responder(_cx: Cx, _: ()) -> String {
format!("404 | Route not found")
}

/// Try to have this module handle a request.
pub async fn exec(&self, cx: Cx, method: Method, data: String) -> Result<String, Error> {
match method {
Method::Create => self.create.run(cx, data).await,
Expand All @@ -58,6 +69,7 @@ impl<Cx: TripleS + Clone> Module<Cx> {
}
}

/// Create a new [`ModuleBuilder`].
pub fn builder() -> ModuleBuilder<Cx> {
ModuleBuilder::default()
}
Expand Down
18 changes: 18 additions & 0 deletions crates/rpc-rs/src/proc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! The procedure module.
use std::{borrow::Cow, future::Future};

use async_trait::async_trait;
Expand All @@ -7,9 +9,15 @@ use specta::{function::FunctionDataType, Type, TypeMap};

use crate::util::TripleS;

/// A generic procedure. This is required to allow for any procedure
/// to be used in a [`rpc_rs::Module`].
#[async_trait]
pub trait GenericProcedure<Cx: Send + Sync> {
/// Run this procedure with the context and a JSON-encoded string
/// representing the data required.
async fn run(&self, cx: Cx, data: String) -> Result<String, Error>;

/// Get the [`FunctionDataType`] of this procedure.
fn specta_type(&self, name: Cow<'static, str>, map: &mut TypeMap) -> FunctionDataType;
}

Expand All @@ -33,28 +41,36 @@ impl<
}
}

/// A generic-wrapped [`Procedure`].
///
/// This is necessary so the [`GenericProcedure`] trait can be
/// implemented in an object-safe manner.
pub struct WrappedProcedure<
Cx: TripleS + Clone,
Output: Send + Sync + Serialize + Type,
Arg: Send + Sync + 'static + DeserializeOwned + Type,
>(Box<dyn Procedure<Cx, Output, Arg> + Send + Sync>);

/// A procedure.
#[async_trait]
pub trait Procedure<
Cx: TripleS + Clone,
Output: Send + Sync + Serialize + Type,
Arg: Send + Sync + DeserializeOwned + Type,
>
{
/// Run this procedure with its context and data.
async fn exec(&self, cx: Cx, data: Arg) -> Output;
}

/// A typed extension to [`Procedure`].
pub trait TypedProcedure<
Cx: TripleS + Clone,
Output: Send + Sync + Serialize + Type,
Arg: Send + Sync + DeserializeOwned + Type,
>: Procedure<Cx, Output, Arg>
{
/// Get the [`FunctionDataType`] of this procedure.
fn specta_type(&self, name: Cow<'static, str>, map: &mut TypeMap) -> FunctionDataType;
}

Expand Down Expand Up @@ -91,6 +107,8 @@ impl<
}
}

/// Wrap any [`Procedure`], converting it to a [`WrappedProcedure`]
/// which implements the [`GenericProcedure`] trait.
pub fn wrap<
Cx: TripleS + Clone,
Output: Send + Sync + Serialize + Type,
Expand Down
3 changes: 3 additions & 0 deletions crates/rpc-rs/src/router/axum.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! The [`axum`] support module.
use std::{future::Future, pin::Pin};

use crate::{module::module::Module, util::TripleS};
Expand All @@ -7,6 +9,7 @@ use http_body_util::BodyExt;
use super::{router::Router, Method};

impl<Cx: TripleS + Clone> Router<Cx> {
/// Convert this router into an [`axum::Router`], consuming it.
pub fn axum(self, state: Cx) -> axum::Router<Cx> {
let mut router = axum::Router::new().with_state(state);

Expand Down
5 changes: 5 additions & 0 deletions crates/rpc-rs/src/router/export.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! The [`specta`] export module.
use std::{collections::HashMap, fs, path::PathBuf, sync::Arc};

use specta::ts::{export_named_datatype, Result};
Expand All @@ -9,6 +11,7 @@ pub(crate) const MODULE_STUB: &str = include_str!("./module_stub.ts");
pub(crate) const CORE: &str = include_str!("./core.ts");

impl<Cx: TripleS + Clone> Router<Cx> {
/// Export a function's TypeScript version with [`specta`].
pub(crate) fn export_func(
&mut self,
script: &mut Vec<String>,
Expand Down Expand Up @@ -36,6 +39,8 @@ impl<Cx: TripleS + Clone> Router<Cx> {
Ok(())
}

/// Export the entire router's bindings.
/// Warning: This **does** consume the router!
pub fn export(mut self, route_prefix: impl AsRef<str>, path: impl Into<PathBuf>) -> Result<()> {
let path = path.into();
let route_prefix = route_prefix.as_ref().to_string();
Expand Down
8 changes: 8 additions & 0 deletions crates/rpc-rs/src/router/func.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
//! A custom version of the [`specta::ts::export_function_header`] function.
use specta::{
function::FunctionDataType,
ts::{datatype, ExportConfig, Result},
TypeMap,
};

/// Convert a [FunctionDataType] into a function header like would be used in a `.d.ts` file.
/// If your function requires a function body you can copy this function into your own codebase.
///
/// Eg. `function name()`
///
/// This had to be modified to support async `Promise`s and to not include the final semicolon.
pub fn export_function_header(dt: FunctionDataType, config: &ExportConfig) -> Result<String> {
let type_map = TypeMap::default();
let mut s = String::new();
Expand Down
15 changes: 15 additions & 0 deletions crates/rpc-rs/src/router/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! The core router module.
use serde::{Deserialize, Serialize};

pub mod export;
Expand All @@ -10,16 +12,27 @@ pub mod axum;
#[cfg(feature = "tauri")]
pub mod tauri;

/// A request method.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum Method {
/// Create an object.
Create,

/// Read an object.
Read,

/// Update an object.
Update,

/// Delete an object.
Delete,

/// Only used when an error occurs.
Error,
}

impl Method {
/// Get this [`Method`] as a [`str`].
pub fn as_str(&self) -> &'static str {
match self {
Self::Create => "Create",
Expand All @@ -30,3 +43,5 @@ impl Method {
}
}
}

pub use router::Router;
13 changes: 12 additions & 1 deletion crates/rpc-rs/src/router/router.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! The router.
use std::collections::HashMap;

use specta::{
Expand All @@ -7,19 +9,27 @@ use specta::{

use crate::{module::module::Module, util::TripleS};

#[allow(dead_code)]
/// A router.
#[allow(dead_code)] // It's not actually dead code, generics just make it seem so.
#[derive(Clone, Default)]
pub struct Router<Cx: TripleS + Clone> {
/// A map of IDs to modules.
pub(crate) modules: HashMap<String, Module<Cx>>,

/// The [`TypeMap`] for this router.
pub(crate) type_map: TypeMap,

/// The [`ExportConfig`] for this router.
pub(crate) export_cfg: ExportConfig,
}

impl<Cx: TripleS + Clone> Router<Cx> {
/// Get the default [`ExportConfig`].
pub(crate) fn export_config() -> ExportConfig {
ExportConfig::default().bigint(BigIntExportBehavior::BigInt)
}

/// Create a new [`Router`].
pub fn new() -> Self {
Self {
modules: HashMap::new(),
Expand All @@ -28,6 +38,7 @@ impl<Cx: TripleS + Clone> Router<Cx> {
}
}

/// Mount a [`Module`] with an ID of anything that implements [`AsRef<str>`].
pub fn mount(mut self, name: impl AsRef<str>, module: Module<Cx>) -> Self {
self.modules.insert(name.as_ref().to_string(), module);
self
Expand Down
Loading

0 comments on commit 0d15141

Please sign in to comment.