ts-rs complete

This commit is contained in:
Aiden McClelland
2025-11-07 01:47:11 -07:00
parent 9d75ab4610
commit 7667b1adaf
9 changed files with 202 additions and 455 deletions

View File

@@ -216,11 +216,8 @@ where
RemoteHandler: crate::handler::HandlerTS, RemoteHandler: crate::handler::HandlerTS,
Extra: Send + Sync + 'static, Extra: Send + Sync + 'static,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
self.handler.params_ty() self.handler.type_info()
}
fn return_ty(&self) -> Option<String> {
self.handler.return_ty()
} }
} }

View File

@@ -122,11 +122,8 @@ impl<H> crate::handler::HandlerTS for NoCli<H>
where where
H: crate::handler::HandlerTS, H: crate::handler::HandlerTS,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
self.0.params_ty() self.0.type_info()
}
fn return_ty(&self) -> Option<String> {
self.0.return_ty()
} }
} }
impl<Context, H> HandlerFor<Context> for NoCli<H> impl<Context, H> HandlerFor<Context> for NoCli<H>
@@ -216,11 +213,8 @@ impl<H> crate::handler::HandlerTS for NoDisplay<H>
where where
H: crate::handler::HandlerTS, H: crate::handler::HandlerTS,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
self.0.params_ty() self.0.type_info()
}
fn return_ty(&self) -> Option<String> {
self.0.return_ty()
} }
} }
@@ -339,11 +333,8 @@ where
H: crate::handler::HandlerTS, H: crate::handler::HandlerTS,
P: Send + Sync + Clone + 'static, P: Send + Sync + Clone + 'static,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
self.handler.params_ty() self.handler.type_info()
}
fn return_ty(&self) -> Option<String> {
self.handler.return_ty()
} }
} }
@@ -511,11 +502,8 @@ where
F: Send + Sync + Clone + 'static, F: Send + Sync + Clone + 'static,
Context: 'static, Context: 'static,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
self.handler.params_ty() self.handler.type_info()
}
fn return_ty(&self) -> Option<String> {
self.handler.return_ty()
} }
} }
@@ -728,11 +716,8 @@ where
InheritedParams: Send + Sync + 'static, InheritedParams: Send + Sync + 'static,
H: crate::handler::HandlerTS, H: crate::handler::HandlerTS,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
self.handler.params_ty() self.handler.type_info()
}
fn return_ty(&self) -> Option<String> {
self.handler.return_ty()
} }
} }
@@ -859,11 +844,8 @@ where
H: crate::handler::HandlerTS, H: crate::handler::HandlerTS,
M: Clone + Send + Sync + 'static, M: Clone + Send + Sync + 'static,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
self.handler.params_ty() self.handler.type_info()
}
fn return_ty(&self) -> Option<String> {
self.handler.return_ty()
} }
} }
impl<Context, M, H> HandlerFor<Context> for WithAbout<M, H> impl<Context, M, H> HandlerFor<Context> for WithAbout<M, H>

View File

@@ -52,11 +52,12 @@ where
<Self as HandlerTypes>::Params: ts_rs::TS, <Self as HandlerTypes>::Params: ts_rs::TS,
<Self as HandlerTypes>::Ok: ts_rs::TS, <Self as HandlerTypes>::Ok: ts_rs::TS,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
Some(<Self as HandlerTypes>::Params::inline()) Some(format!(
} "{{_PARAMS:{},_RETURN:{}}}",
fn return_ty(&self) -> Option<String> { <Self as HandlerTypes>::Params::inline(),
Some(<Self as HandlerTypes>::Ok::inline()) <Self as HandlerTypes>::Ok::inline(),
))
} }
} }
impl<Context, F, T, E, Args> PrintCliResult<Context> for FromFn<F, T, E, Args> impl<Context, F, T, E, Args> PrintCliResult<Context> for FromFn<F, T, E, Args>
@@ -174,11 +175,12 @@ where
<Self as HandlerTypes>::Params: ts_rs::TS, <Self as HandlerTypes>::Params: ts_rs::TS,
<Self as HandlerTypes>::Ok: ts_rs::TS, <Self as HandlerTypes>::Ok: ts_rs::TS,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
Some(<Self as HandlerTypes>::Params::inline()) Some(format!(
} "{{_PARAMS:{},_RETURN:{}}}",
fn return_ty(&self) -> Option<String> { <Self as HandlerTypes>::Params::inline(),
Some(<Self as HandlerTypes>::Ok::inline()) <Self as HandlerTypes>::Ok::inline(),
))
} }
} }
impl<Context, F, Fut, T, E, Args> PrintCliResult<Context> for FromFnAsync<F, Fut, T, E, Args> impl<Context, F, Fut, T, E, Args> PrintCliResult<Context> for FromFnAsync<F, Fut, T, E, Args>
@@ -283,11 +285,12 @@ where
<Self as HandlerTypes>::Params: ts_rs::TS, <Self as HandlerTypes>::Params: ts_rs::TS,
<Self as HandlerTypes>::Ok: ts_rs::TS, <Self as HandlerTypes>::Ok: ts_rs::TS,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
Some(<Self as HandlerTypes>::Params::inline()) Some(format!(
} "{{_PARAMS:{},_RETURN:{}}}",
fn return_ty(&self) -> Option<String> { <Self as HandlerTypes>::Params::inline(),
Some(<Self as HandlerTypes>::Ok::inline()) <Self as HandlerTypes>::Ok::inline(),
))
} }
} }
impl<Context, F, Fut, T, E, Args> PrintCliResult<Context> for FromFnAsyncLocal<F, Fut, T, E, Args> impl<Context, F, Fut, T, E, Args> PrintCliResult<Context> for FromFnAsyncLocal<F, Fut, T, E, Args>
@@ -711,7 +714,12 @@ where
impl<Context, F, T, E, Params, InheritedParams> HandlerFor<Context> impl<Context, F, T, E, Params, InheritedParams> HandlerFor<Context>
for FromFn<F, T, E, (Context, Params, InheritedParams)> for FromFn<F, T, E, (Context, Params, InheritedParams)>
where where
Self: crate::handler::HandlerRequires<Params = Params, InheritedParams = InheritedParams, Ok = T, Err = E>, Self: crate::handler::HandlerRequires<
Params = Params,
InheritedParams = InheritedParams,
Ok = T,
Err = E,
>,
Context: crate::Context, Context: crate::Context,
F: Fn(Context, Params, InheritedParams) -> Result<T, E> + Send + Sync + Clone + 'static, F: Fn(Context, Params, InheritedParams) -> Result<T, E> + Send + Sync + Clone + 'static,
Params: DeserializeOwned + Send + Sync + 'static, Params: DeserializeOwned + Send + Sync + 'static,
@@ -765,7 +773,12 @@ where
impl<Context, F, Fut, T, E, Params, InheritedParams> HandlerFor<Context> impl<Context, F, Fut, T, E, Params, InheritedParams> HandlerFor<Context>
for FromFnAsync<F, Fut, T, E, (Context, Params, InheritedParams)> for FromFnAsync<F, Fut, T, E, (Context, Params, InheritedParams)>
where where
Self: crate::handler::HandlerRequires<Params = Params, InheritedParams = InheritedParams, Ok = T, Err = E>, Self: crate::handler::HandlerRequires<
Params = Params,
InheritedParams = InheritedParams,
Ok = T,
Err = E,
>,
Context: crate::Context, Context: crate::Context,
F: Fn(Context, Params, InheritedParams) -> Fut + Send + Sync + Clone + 'static, F: Fn(Context, Params, InheritedParams) -> Fut + Send + Sync + Clone + 'static,
Fut: Future<Output = Result<T, E>> + Send + 'static, Fut: Future<Output = Result<T, E>> + Send + 'static,
@@ -811,7 +824,12 @@ where
impl<F, Fut, T, E, Context, Params, InheritedParams> HandlerFor<Context> impl<F, Fut, T, E, Context, Params, InheritedParams> HandlerFor<Context>
for FromFnAsyncLocal<F, Fut, T, E, HandlerArgs<Context, Params, InheritedParams>> for FromFnAsyncLocal<F, Fut, T, E, HandlerArgs<Context, Params, InheritedParams>>
where where
Self: crate::handler::HandlerRequires<Params = Params, InheritedParams = InheritedParams, Ok = T, Err = E>, Self: crate::handler::HandlerRequires<
Params = Params,
InheritedParams = InheritedParams,
Ok = T,
Err = E,
>,
F: Fn(HandlerArgs<Context, Params, InheritedParams>) -> Fut + Send + Sync + Clone + 'static, F: Fn(HandlerArgs<Context, Params, InheritedParams>) -> Fut + Send + Sync + Clone + 'static,
Fut: Future<Output = Result<T, E>> + 'static, Fut: Future<Output = Result<T, E>> + 'static,
T: Send + Sync + 'static, T: Send + Sync + 'static,
@@ -1006,7 +1024,12 @@ where
impl<Context, F, Fut, T, E, Params, InheritedParams> HandlerFor<Context> impl<Context, F, Fut, T, E, Params, InheritedParams> HandlerFor<Context>
for FromFnAsyncLocal<F, Fut, T, E, (Context, Params, InheritedParams)> for FromFnAsyncLocal<F, Fut, T, E, (Context, Params, InheritedParams)>
where where
Self: crate::handler::HandlerRequires<Params = Params, InheritedParams = InheritedParams, Ok = T, Err = E>, Self: crate::handler::HandlerRequires<
Params = Params,
InheritedParams = InheritedParams,
Ok = T,
Err = E,
>,
Context: crate::Context, Context: crate::Context,
F: Fn(Context, Params, InheritedParams) -> Fut + Send + Sync + Clone + 'static, F: Fn(Context, Params, InheritedParams) -> Fut + Send + Sync + Clone + 'static,
Fut: Future<Output = Result<T, E>> + 'static, Fut: Future<Output = Result<T, E>> + 'static,

View File

@@ -57,17 +57,13 @@ impl<Context: crate::Context, Inherited: Send + Sync> HandleAnyArgs<Context, Inh
#[cfg(feature = "ts-rs")] #[cfg(feature = "ts-rs")]
pub(crate) trait HandleAnyTS { pub(crate) trait HandleAnyTS {
fn params_ty(&self) -> Option<String>; fn type_info(&self) -> Option<String>;
fn return_ty(&self) -> Option<String>;
} }
#[cfg(feature = "ts-rs")] #[cfg(feature = "ts-rs")]
impl<T: HandleAnyTS> HandleAnyTS for Arc<T> { impl<T: HandleAnyTS> HandleAnyTS for Arc<T> {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
self.deref().params_ty() self.deref().type_info()
}
fn return_ty(&self) -> Option<String> {
self.deref().return_ty()
} }
} }
@@ -181,11 +177,8 @@ impl<Context, Inherited> Debug for DynHandler<Context, Inherited> {
} }
#[cfg(feature = "ts-rs")] #[cfg(feature = "ts-rs")]
impl<Context, Inherited> HandleAnyTS for DynHandler<Context, Inherited> { impl<Context, Inherited> HandleAnyTS for DynHandler<Context, Inherited> {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
self.0.params_ty() self.0.type_info()
}
fn return_ty(&self) -> Option<String> {
self.0.return_ty()
} }
} }
#[async_trait::async_trait] #[async_trait::async_trait]
@@ -243,8 +236,7 @@ pub trait HandlerTypes {
#[cfg(feature = "ts-rs")] #[cfg(feature = "ts-rs")]
pub trait HandlerTS { pub trait HandlerTS {
fn params_ty(&self) -> Option<String>; fn type_info(&self) -> Option<String>;
fn return_ty(&self) -> Option<String>;
} }
#[cfg(feature = "ts-rs")] #[cfg(feature = "ts-rs")]
@@ -257,9 +249,7 @@ pub trait HandlerRequires: HandlerTypes + Clone + Send + Sync + 'static {}
#[cfg(not(feature = "ts-rs"))] #[cfg(not(feature = "ts-rs"))]
impl<T: HandlerTypes + Clone + Send + Sync + 'static> HandlerRequires for T {} impl<T: HandlerTypes + Clone + Send + Sync + 'static> HandlerRequires for T {}
pub trait HandlerFor<Context: crate::Context>: pub trait HandlerFor<Context: crate::Context>: HandlerRequires {
HandlerRequires
{
fn handle_sync( fn handle_sync(
&self, &self,
handle_args: HandlerArgsFor<Context, Self>, handle_args: HandlerArgsFor<Context, Self>,
@@ -377,11 +367,8 @@ impl<Context, Inherited, H> HandleAnyTS for AnyHandler<Context, Inherited, H>
where where
H: crate::handler::HandlerTS, H: crate::handler::HandlerTS,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
self.handler.params_ty() self.handler.type_info()
}
fn return_ty(&self) -> Option<String> {
self.handler.return_ty()
} }
} }
@@ -471,6 +458,7 @@ where
#[derive(Debug, Clone, Copy, Deserialize, Serialize, Parser)] #[derive(Debug, Clone, Copy, Deserialize, Serialize, Parser)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))] #[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
#[cfg_attr(feature = "ts-rs", ts(type = "{}"))]
pub struct Empty {} pub struct Empty {}
pub trait OrEmpty<T> { pub trait OrEmpty<T> {

View File

@@ -7,13 +7,13 @@ use imbl_value::Value;
use serde::Serialize; use serde::Serialize;
use yajrc::RpcError; use yajrc::RpcError;
#[cfg(feature = "ts-rs")]
use crate::handler::HandleAnyTS;
use crate::util::{combine, Flat, PhantomData}; use crate::util::{combine, Flat, PhantomData};
use crate::{ use crate::{
CliBindings, DynHandler, Empty, HandleAny, HandleAnyArgs, Handler, HandlerArgs, HandlerArgsFor, CliBindings, DynHandler, Empty, HandleAny, HandleAnyArgs, Handler, HandlerArgs, HandlerArgsFor,
HandlerFor, HandlerTypes, WithContext, HandlerFor, HandlerRequires, HandlerTypes, WithContext,
}; };
#[cfg(feature = "ts-rs")]
use crate::handler::HandleAnyTS;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct Name(pub(crate) &'static str); pub(crate) struct Name(pub(crate) &'static str);
@@ -134,7 +134,7 @@ impl<Context, Params, InheritedParams> HandlerTypes
for ParentHandler<Context, Params, InheritedParams> for ParentHandler<Context, Params, InheritedParams>
where where
Params: Send + Sync, Params: Send + Sync,
InheritedParams: Send + Sync, InheritedParams: Send + Sync,
{ {
type Params = Params; type Params = Params;
type InheritedParams = InheritedParams; type InheritedParams = InheritedParams;
@@ -143,46 +143,34 @@ where
} }
#[cfg(feature = "ts-rs")] #[cfg(feature = "ts-rs")]
impl<Context, Params, InheritedParams> crate::handler::HandlerTS for ParentHandler<Context, Params, InheritedParams> impl<Context, Params, InheritedParams> crate::handler::HandlerTS
for ParentHandler<Context, Params, InheritedParams>
where where
Params: Send + Sync + 'static, Params: ts_rs::TS + Send + Sync + 'static,
InheritedParams: Send + Sync + 'static, InheritedParams: Send + Sync + 'static,
{ {
fn params_ty(&self) -> Option<String> { fn type_info(&self) -> Option<String> {
use std::fmt::Write; use std::fmt::Write;
let mut res = "{".to_owned(); let mut res = "{".to_owned();
res.push_str("_CHILDREN:{");
for (name, handler) in &self.subcommands.1 { for (name, handler) in &self.subcommands.1 {
let Some(ty) = handler.params_ty() else { let Some(ty) = handler.type_info() else {
continue; continue;
}; };
write!( write!(
&mut res, &mut res,
"{}:{};", "{}:{};",
serde_json::to_string(&name.0).unwrap(), serde_json::to_string(&name.0).unwrap(),
ty ty,
) )
.ok(); .ok()?;
} }
res.push('}'); res.push_str("};}");
Some(res) if let Some(ty) = self.subcommands.0.as_ref().and_then(|h| h.type_info()) {
} write!(&mut res, "&{}", ty).ok()?;
} else {
fn return_ty(&self) -> Option<String> { write!(&mut res, "&{{_PARAMS:{}}}", Params::inline()).ok()?;
use std::fmt::Write;
let mut res = "{".to_owned();
for (name, handler) in &self.subcommands.1 {
let Some(ty) = handler.return_ty() else {
continue;
};
write!(
&mut res,
"{}:{};",
serde_json::to_string(&name.0).unwrap(),
ty
)
.ok();
} }
res.push('}');
Some(res) Some(res)
} }
} }
@@ -190,6 +178,12 @@ where
impl<Context, Params, InheritedParams> HandlerFor<Context> impl<Context, Params, InheritedParams> HandlerFor<Context>
for ParentHandler<Context, Params, InheritedParams> for ParentHandler<Context, Params, InheritedParams>
where where
Self: HandlerRequires<
Params = Params,
InheritedParams = InheritedParams,
Ok = Value,
Err = RpcError,
>,
Context: crate::Context, Context: crate::Context,
Params: Send + Sync + 'static, Params: Send + Sync + 'static,
InheritedParams: Send + Sync + 'static, InheritedParams: Send + Sync + 'static,

View File

@@ -13,3 +13,8 @@ mod context;
mod handler; mod handler;
mod server; mod server;
pub mod util; pub mod util;
#[cfg(feature = "ts-rs")]
pub fn type_helpers() -> &'static str {
include_str!("./type-helpers.ts")
}

41
src/type-helpers.ts Normal file
View File

@@ -0,0 +1,41 @@
export type RpcHandler = ParentHandler | LeafHandler;
export type ParentHandler = {
_CHILDREN: {
[name: string]: RpcHandler;
};
_PARAMS: unknown;
_RETURN?: unknown;
};
export type LeafHandler = {
_PARAMS: unknown;
_RETURN: unknown;
};
export type RpcParamType<
Root extends RpcHandler,
Method extends string
> = Root["_PARAMS"] &
(Root extends ParentHandler
? Method extends `${infer A}.${infer B}`
? RpcParamType<Root["_CHILDREN"][A], B>
: Root["_CHILDREN"] extends {
[m in Method]: LeafHandler;
}
? Root["_CHILDREN"][Method]["_PARAMS"]
: never
: never);
export type RpcReturnType<
Root extends RpcHandler,
Method extends string
> = Root extends ParentHandler
? Method extends `${infer A}.${infer B}`
? RpcReturnType<Root["_CHILDREN"][A], B>
: Root["_CHILDREN"] extends {
[m in Method]: LeafHandler;
}
? Root["_CHILDREN"][Method]["_RETURN"]
: never
: never;

View File

@@ -1,251 +0,0 @@
use std::ffi::OsString;
use std::fmt::Display;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use clap::Parser;
use futures::future::ready;
use imbl_value::Value;
use rpc_toolkit::{
call_remote_socket, from_fn, from_fn_async, CallRemote, CliApp, Context, Empty, HandlerExt,
ParentHandler, Server,
};
use serde::{Deserialize, Serialize};
use tokio::runtime::Runtime;
use tokio::sync::{Mutex, OnceCell};
use yajrc::RpcError;
#[derive(Parser, Deserialize)]
#[command(
name = "test-cli",
version,
author,
about = "This is a test cli application."
)]
struct CliConfig {
#[arg(long = "host")]
host: Option<PathBuf>,
#[arg(short = 'c', long = "config")]
config: Option<PathBuf>,
}
impl CliConfig {
fn load_rec(&mut self) -> Result<(), RpcError> {
if let Some(path) = self.config.as_ref() {
let mut extra_cfg: Self =
serde_json::from_str(&std::fs::read_to_string(path).map_err(internal_error)?)
.map_err(internal_error)?;
extra_cfg.load_rec()?;
self.merge_with(extra_cfg);
}
Ok(())
}
fn merge_with(&mut self, extra: Self) {
if self.host.is_none() {
self.host = extra.host;
}
}
}
struct CliContextSeed {
host: PathBuf,
rt: OnceCell<Arc<Runtime>>,
}
#[derive(Clone)]
struct CliContext(Arc<CliContextSeed>);
impl Context for CliContext {
fn runtime(&self) -> Option<Arc<Runtime>> {
if self.0.rt.get().is_none() {
let rt = Arc::new(Runtime::new().unwrap());
self.0.rt.set(rt.clone()).unwrap_or_default();
Some(rt)
} else {
self.0.rt.get().cloned()
}
}
}
impl CallRemote<ServerContext> for CliContext {
async fn call_remote(&self, method: &str, params: Value, _: Empty) -> Result<Value, RpcError> {
call_remote_socket(
tokio::net::UnixStream::connect(&self.0.host).await.unwrap(),
method,
params,
)
.await
}
}
fn make_cli() -> CliApp<CliContext, CliConfig> {
CliApp::new(
|mut config: CliConfig| {
config.load_rec()?;
Ok(CliContext(Arc::new(CliContextSeed {
host: config
.host
.unwrap_or_else(|| Path::new("./rpc.sock").to_owned()),
rt: OnceCell::new(),
})))
},
make_api(),
)
}
struct ServerContextSeed {
state: Mutex<Value>,
}
#[derive(Clone)]
struct ServerContext(Arc<ServerContextSeed>);
impl Context for ServerContext {}
fn make_server() -> Server<ServerContext> {
let ctx = ServerContext(Arc::new(ServerContextSeed {
state: Mutex::new(Value::Null),
}));
Server::new(move || ready(Ok(ctx.clone())), make_api())
}
fn make_api<C: Context>() -> ParentHandler<C> {
async fn a_hello(_: CliContext) -> Result<String, RpcError> {
Ok::<_, RpcError>("Async Subcommand".to_string())
}
#[derive(Debug, Clone, Deserialize, Serialize, Parser)]
struct EchoParams {
next: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, Parser)]
struct HelloParams {
whom: String,
}
#[derive(Debug, Clone, Deserialize, Serialize, Parser)]
struct InheritParams {
donde: String,
}
ParentHandler::<C>::new()
.subcommand(
"echo",
from_fn_async(
|c: ServerContext, EchoParams { next }: EchoParams| async move {
Ok::<_, RpcError>(std::mem::replace(
&mut *c.0.state.lock().await,
Value::String(Arc::new(next)),
))
},
)
.with_custom_display_fn(|_, a| Ok(println!("{a}")))
.with_about("Testing")
.with_call_remote::<CliContext>(),
)
.subcommand(
"hello",
from_fn(|_: C, HelloParams { whom }: HelloParams| {
Ok::<_, RpcError>(format!("Hello {whom}").to_string())
}),
)
.subcommand("a_hello", from_fn_async(a_hello))
.subcommand(
"dondes",
ParentHandler::<C, InheritParams>::new().subcommand(
"donde",
from_fn(|c: CliContext, _: (), donde| {
Ok::<_, RpcError>(
format!(
"Subcommand No Cli: Host {host} Donde = {donde}",
host = c.0.host.display()
)
.to_string(),
)
})
.with_inherited(|InheritParams { donde }, _| donde)
.no_cli(),
),
)
.subcommand(
"fizz",
ParentHandler::<C, InheritParams>::new().root_handler(
from_fn(|c: CliContext, _: Empty, InheritParams { donde }| {
Ok::<_, RpcError>(
format!(
"Root Command: Host {host} Donde = {donde}",
host = c.0.host.display(),
)
.to_string(),
)
})
.with_inherited(|a, _| a),
),
)
.subcommand(
"error",
ParentHandler::<C, InheritParams>::new().root_handler(
from_fn(|_: CliContext, _: Empty, InheritParams { .. }| {
Err::<String, _>(RpcError {
code: 1,
message: "This is an example message".into(),
data: None,
})
})
.with_inherited(|a, _| a)
.no_cli(),
),
)
}
pub fn internal_error(e: impl Display) -> RpcError {
RpcError {
data: Some(e.to_string().into()),
..yajrc::INTERNAL_ERROR
}
}
#[test]
fn test_cli() {
make_cli()
.run(["test-cli", "hello", "me"].iter().map(OsString::from))
.unwrap();
make_cli()
.run(["test-cli", "fizz", "buzz"].iter().map(OsString::from))
.unwrap();
}
#[tokio::test]
async fn test_server() {
let path = Path::new(env!("CARGO_TARGET_TMPDIR")).join("rpc.sock");
tokio::fs::remove_file(&path).await.unwrap_or_default();
let server = make_server();
let (shutdown, fut) = server
.run_unix(path.clone(), |err| eprintln!("IO Error: {err}"))
.unwrap();
tokio::join!(
tokio::task::spawn_blocking(move || {
make_cli()
.run(
[
"test-cli",
&format!("--host={}", path.display()),
"echo",
"foo",
]
.iter()
.map(OsString::from),
)
.unwrap();
make_cli()
.run(
[
"test-cli",
&format!("--host={}", path.display()),
"echo",
"bar",
]
.iter()
.map(OsString::from),
)
.unwrap();
shutdown.shutdown()
}),
fut
)
.0
.unwrap();
}

View File

@@ -1,109 +1,77 @@
// use std::path::PathBuf; use clap::Parser;
use rpc_toolkit::{from_fn_async, Context, Empty, HandlerTS, ParentHandler, Server};
use serde::{Deserialize, Serialize};
use yajrc::RpcError;
// use clap::Parser; #[derive(Clone)]
// use futures::Future; struct TestContext;
// use rpc_toolkit::{
// AsyncCommand, CliContextSocket, Command, Contains, Context, DynCommand, LeafCommand, NoParent,
// ParentCommand, ParentInfo, Server, ShutdownHandle,
// };
// use serde::{Deserialize, Serialize};
// use tokio::net::UnixStream;
// use yajrc::RpcError;
// struct ServerContext; impl Context for TestContext {}
// impl Context for ServerContext {
// type Metadata = ();
// }
// struct CliContext(PathBuf); #[derive(Debug, Deserialize, Serialize, Parser)]
// impl Context for CliContext { #[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
// type Metadata = (); struct Thing1Params {
// } thing: String,
}
// impl CliContextSocket for CliContext { async fn thing1_handler(_ctx: TestContext, params: Thing1Params) -> Result<String, RpcError> {
// type Stream = UnixStream; Ok(format!("Thing1 is {}", params.thing))
// async fn connect(&self) -> std::io::Result<Self::Stream> { }
// UnixStream::connect(&self.0).await
// }
// }
// impl rpc_toolkit::CliContext for CliContext { #[derive(Debug, Deserialize, Serialize, Parser)]
// async fn call_remote( #[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
// &self, struct GroupParams {
// method: &str, #[arg(short, long)]
// params: imbl_value::Value, verbose: bool,
// ) -> Result<imbl_value::Value, RpcError> { }
// <Self as CliContextSocket>::call_remote(self, method, params).await
// }
// }
// async fn run_server() { #[tokio::test]
// Server::new( async fn test_basic_server() {
// vec![ let root_handler = ParentHandler::new()
// DynCommand::from_parent::<Group>(Contains::none()), .subcommand("thing1", from_fn_async(thing1_handler))
// DynCommand::from_async::<Thing1>(Contains::none()), .subcommand(
// // DynCommand::from_async::<Thing2>(Contains::none()), "group",
// // DynCommand::from_sync::<Thing3>(Contains::none()), ParentHandler::<TestContext, Empty, Empty>::new()
// // DynCommand::from_sync::<Thing4>(Contains::none()), .subcommand("thing1", from_fn_async(thing1_handler))
// ], .subcommand(
// || async { Ok(ServerContext) }, "thing2",
// ) from_fn_async(|_ctx: TestContext, params: GroupParams| async move {
// .run_unix("./test.sock", |e| eprintln!("{e}")) Ok::<_, RpcError>(format!("verbose: {}", params.verbose))
// .unwrap() }),
// .1 ),
// .await );
// }
// #[derive(Debug, Deserialize, Serialize, Parser)] println!("{}", root_handler.type_info().unwrap_or_default());
// struct Group {
// #[arg(short, long)]
// verbose: bool,
// }
// impl Command for Group {
// const NAME: &'static str = "group";
// type Parent = NoParent;
// }
// impl<Ctx> ParentCommand<Ctx> for Group
// where
// Ctx: Context,
// // SubThing: AsyncCommand<Ctx>,
// Thing1: AsyncCommand<Ctx>,
// {
// fn subcommands(chain: rpc_toolkit::ParentChain<Self>) -> Vec<DynCommand<Ctx>> {
// vec![
// // DynCommand::from_async::<SubThing>(chain.child()),
// DynCommand::from_async::<Thing1>(Contains::none()),
// ]
// }
// }
// #[derive(Debug, Deserialize, Serialize, Parser)] let server = Server::new(|| async { Ok(TestContext) }, root_handler);
// struct Thing1 {
// thing: String,
// }
// impl Command for Thing1 {
// const NAME: &'static str = "thing1";
// type Parent = NoParent;
// }
// impl LeafCommand<ServerContext> for Thing1 {
// type Ok = String;
// type Err = RpcError;
// fn display(self, _: ServerContext, _: rpc_toolkit::ParentInfo<Self::Parent>, res: Self::Ok) {
// println!("{}", res);
// }
// }
// impl AsyncCommand<ServerContext> for Thing1 { // Test calling thing1 directly
// async fn implementation( let result = server
// self, .handle_command(
// _: ServerContext, "thing1",
// _: ParentInfo<Self::Parent>, imbl_value::to_value(&Thing1Params {
// ) -> Result<Self::Ok, Self::Err> { thing: "test".to_string(),
// Ok(format!("Thing1 is {}", self.thing)) })
// } .unwrap(),
// } )
.await
.unwrap();
// #[tokio::test] let response: String = imbl_value::from_value(result).unwrap();
// async fn test() { assert_eq!(response, "Thing1 is test");
// let server = tokio::spawn(run_server());
// } // Test calling group.thing1
let result = server
.handle_command(
"group.thing1",
imbl_value::to_value(&Thing1Params {
thing: "nested".to_string(),
})
.unwrap(),
)
.await
.unwrap();
let response: String = imbl_value::from_value(result).unwrap();
assert_eq!(response, "Thing1 is nested");
}