better ts adapters

This commit is contained in:
Aiden McClelland
2025-11-07 16:43:14 -07:00
parent 7667b1adaf
commit eb64c1f422
4 changed files with 348 additions and 27 deletions

View File

@@ -44,6 +44,9 @@ pub trait HandlerExt<Context: crate::Context>: HandlerFor<Context> + Sized {
fn with_about<M>(self, message: M) -> WithAbout<M, Self>
where
M: IntoResettable<StyledStr>;
fn no_ts(self) -> NoTS<Self>;
fn unknown_ts(self) -> UnknownTS<Self>;
fn custom_ts(self, params_ty: String, return_ty: String) -> CustomTS<Self>;
}
impl<Context: crate::Context, T: HandlerFor<Context> + Sized> HandlerExt<Context> for T {
@@ -107,6 +110,22 @@ impl<Context: crate::Context, T: HandlerFor<Context> + Sized> HandlerExt<Context
message,
}
}
fn no_ts(self) -> NoTS<Self> {
NoTS(self)
}
fn unknown_ts(self) -> UnknownTS<Self> {
UnknownTS(self)
}
fn custom_ts(self, params_ty: String, return_ty: String) -> CustomTS<Self> {
CustomTS {
handler: self,
params_ty,
return_ty,
}
}
}
#[derive(Debug, Clone)]
@@ -648,7 +667,7 @@ impl<Context, H, Inherited, RemoteContext> Handler<Inherited>
where
Context: crate::Context + CallRemote<RemoteContext>,
RemoteContext: crate::Context,
H: HandlerFor<RemoteContext> + CliBindings<Context>,
H: HandlerFor<RemoteContext> + CliBindings<Context> + crate::handler::HandlerTS,
H::Ok: Serialize + DeserializeOwned,
H::Err: From<RpcError>,
H::Params: Serialize + DeserializeOwned,
@@ -926,3 +945,304 @@ where
self.handler.cli_display(handler, result)
}
}
#[derive(Debug, Clone)]
pub struct NoTS<H>(pub H);
impl<H> HandlerTypes for NoTS<H>
where
H: HandlerTypes,
{
type Params = H::Params;
type InheritedParams = H::InheritedParams;
type Ok = H::Ok;
type Err = H::Err;
}
#[cfg(feature = "ts-rs")]
impl<H> crate::handler::HandlerTS for NoTS<H> {
fn type_info(&self) -> Option<String> {
None
}
}
impl<Context, H> HandlerFor<Context> for NoTS<H>
where
Context: crate::Context,
H: HandlerFor<Context>,
{
fn handle_sync(
&self,
HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
}: HandlerArgsFor<Context, Self>,
) -> Result<Self::Ok, Self::Err> {
self.0.handle_sync(HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
})
}
async fn handle_async(
&self,
HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
}: HandlerArgsFor<Context, Self>,
) -> Result<Self::Ok, Self::Err> {
self.0
.handle_async(HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
})
.await
}
fn metadata(&self, method: VecDeque<&'static str>) -> OrdMap<&'static str, Value> {
self.0.metadata(method)
}
fn method_from_dots(&self, method: &str) -> Option<VecDeque<&'static str>> {
self.0.method_from_dots(method)
}
}
impl<Context, H> CliBindings<Context> for NoTS<H>
where
Context: crate::Context,
H: CliBindings<Context>,
{
fn cli_command(&self) -> clap::Command {
self.0.cli_command()
}
fn cli_parse(
&self,
arg_matches: &clap::ArgMatches,
) -> Result<(VecDeque<&'static str>, Value), clap::Error> {
self.0.cli_parse(arg_matches)
}
fn cli_display(
&self,
handler: HandlerArgsFor<Context, Self>,
result: Self::Ok,
) -> Result<(), Self::Err> {
self.0.cli_display(handler, result)
}
}
#[derive(Debug, Clone)]
pub struct UnknownTS<H>(pub H);
impl<H> HandlerTypes for UnknownTS<H>
where
H: HandlerTypes,
{
type Params = H::Params;
type InheritedParams = H::InheritedParams;
type Ok = H::Ok;
type Err = H::Err;
}
#[cfg(feature = "ts-rs")]
impl<H> crate::handler::HandlerTS for UnknownTS<H> {
fn type_info(&self) -> Option<String> {
Some("{_PARAMS:unknown,_RETURN:unknown}".to_string())
}
}
impl<Context, H> HandlerFor<Context> for UnknownTS<H>
where
Context: crate::Context,
H: HandlerFor<Context>,
{
fn handle_sync(
&self,
HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
}: HandlerArgsFor<Context, Self>,
) -> Result<Self::Ok, Self::Err> {
self.0.handle_sync(HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
})
}
async fn handle_async(
&self,
HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
}: HandlerArgsFor<Context, Self>,
) -> Result<Self::Ok, Self::Err> {
self.0
.handle_async(HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
})
.await
}
fn metadata(&self, method: VecDeque<&'static str>) -> OrdMap<&'static str, Value> {
self.0.metadata(method)
}
fn method_from_dots(&self, method: &str) -> Option<VecDeque<&'static str>> {
self.0.method_from_dots(method)
}
}
impl<Context, H> CliBindings<Context> for UnknownTS<H>
where
Context: crate::Context,
H: CliBindings<Context>,
{
fn cli_command(&self) -> clap::Command {
self.0.cli_command()
}
fn cli_parse(
&self,
arg_matches: &clap::ArgMatches,
) -> Result<(VecDeque<&'static str>, Value), clap::Error> {
self.0.cli_parse(arg_matches)
}
fn cli_display(
&self,
handler: HandlerArgsFor<Context, Self>,
result: Self::Ok,
) -> Result<(), Self::Err> {
self.0.cli_display(handler, result)
}
}
#[derive(Debug, Clone)]
pub struct CustomTS<H> {
pub handler: H,
pub params_ty: String,
pub return_ty: String,
}
impl<H> HandlerTypes for CustomTS<H>
where
H: HandlerTypes,
{
type Params = H::Params;
type InheritedParams = H::InheritedParams;
type Ok = H::Ok;
type Err = H::Err;
}
#[cfg(feature = "ts-rs")]
impl<H> crate::handler::HandlerTS for CustomTS<H> {
fn type_info(&self) -> Option<String> {
Some(format!(
"{{_PARAMS:{},_RETURN:{}}}",
self.params_ty, self.return_ty
))
}
}
impl<Context, H> HandlerFor<Context> for CustomTS<H>
where
Context: crate::Context,
H: HandlerFor<Context>,
{
fn handle_sync(
&self,
HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
}: HandlerArgsFor<Context, Self>,
) -> Result<Self::Ok, Self::Err> {
self.handler.handle_sync(HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
})
}
async fn handle_async(
&self,
HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
}: HandlerArgsFor<Context, Self>,
) -> Result<Self::Ok, Self::Err> {
self.handler
.handle_async(HandlerArgs {
context,
parent_method,
method,
params,
inherited_params,
raw_params,
})
.await
}
fn metadata(&self, method: VecDeque<&'static str>) -> OrdMap<&'static str, Value> {
self.handler.metadata(method)
}
fn method_from_dots(&self, method: &str) -> Option<VecDeque<&'static str>> {
self.handler.method_from_dots(method)
}
}
impl<Context, H> CliBindings<Context> for CustomTS<H>
where
Context: crate::Context,
H: CliBindings<Context>,
{
fn cli_command(&self) -> clap::Command {
self.handler.cli_command()
}
fn cli_parse(
&self,
arg_matches: &clap::ArgMatches,
) -> Result<(VecDeque<&'static str>, Value), clap::Error> {
self.handler.cli_parse(arg_matches)
}
fn cli_display(
&self,
handler: HandlerArgsFor<Context, Self>,
result: Self::Ok,
) -> Result<(), Self::Err> {
self.handler.cli_display(handler, result)
}
}

View File

@@ -55,28 +55,22 @@ impl<Context: crate::Context, Inherited: Send + Sync> HandleAnyArgs<Context, Inh
}
}
#[cfg(feature = "ts-rs")]
pub(crate) trait HandleAnyTS {
fn type_info(&self) -> Option<String>;
#[allow(dead_code)]
fn type_info(&self) -> Option<String> {
None
}
}
#[cfg(feature = "ts-rs")]
impl<T: HandleAnyTS> HandleAnyTS for Arc<T> {
fn type_info(&self) -> Option<String> {
self.deref().type_info()
}
}
#[cfg(feature = "ts-rs")]
pub(crate) trait HandleAnyRequires: HandleAnyTS + Send + Sync {}
#[cfg(feature = "ts-rs")]
impl<T: HandleAnyTS + Send + Sync> HandleAnyRequires for T {}
#[cfg(not(feature = "ts-rs"))]
pub(crate) trait HandleAnyRequires: Send + Sync {}
#[cfg(not(feature = "ts-rs"))]
impl<T: Send + Sync> HandleAnyRequires for T {}
#[async_trait::async_trait]
pub(crate) trait HandleAny<Context>: HandleAnyRequires {
type Inherited: Send;
@@ -175,7 +169,6 @@ impl<Context, Inherited> Debug for DynHandler<Context, Inherited> {
f.debug_struct("DynHandler").finish()
}
}
#[cfg(feature = "ts-rs")]
impl<Context, Inherited> HandleAnyTS for DynHandler<Context, Inherited> {
fn type_info(&self) -> Option<String> {
self.0.type_info()
@@ -234,19 +227,18 @@ pub trait HandlerTypes {
type Err: Send + Sync;
}
#[cfg(feature = "ts-rs")]
pub trait HandlerTS {
fn type_info(&self) -> Option<String>;
}
#[cfg(feature = "ts-rs")]
pub trait HandlerRequires: HandlerTS + HandlerTypes + Clone + Send + Sync + 'static {}
#[cfg(feature = "ts-rs")]
impl<T: HandlerTS + HandlerTypes + Clone + Send + Sync + 'static> HandlerRequires for T {}
#[cfg(not(feature = "ts-rs"))]
impl<T: HandlerTypes> HandlerTS for T {
fn type_info(&self) -> Option<String> {
None
}
}
#[cfg(not(feature = "ts-rs"))]
pub trait HandlerRequires: HandlerTypes + Clone + Send + Sync + 'static {}
#[cfg(not(feature = "ts-rs"))]
impl<T: HandlerTypes + Clone + Send + Sync + 'static> HandlerRequires for T {}
pub trait HandlerFor<Context: crate::Context>: HandlerRequires {
@@ -321,7 +313,7 @@ impl<Context, H> WithContext<Context, H> {
impl<Context, Inherited, H> Handler<Inherited> for WithContext<Context, H>
where
Context: crate::Context,
H: HandlerFor<Context> + CliBindings<Context>,
H: HandlerFor<Context> + CliBindings<Context> + HandlerTS,
H::Ok: Serialize + DeserializeOwned,
H::Params: DeserializeOwned,
H::InheritedParams: OrEmpty<Inherited>,
@@ -362,10 +354,9 @@ impl<Context, Inherited, H: std::fmt::Debug> std::fmt::Debug for AnyHandler<Cont
}
}
#[cfg(feature = "ts-rs")]
impl<Context, Inherited, H> HandleAnyTS for AnyHandler<Context, Inherited, H>
where
H: crate::handler::HandlerTS,
H: HandlerTS,
{
fn type_info(&self) -> Option<String> {
self.handler.type_info()
@@ -376,7 +367,7 @@ where
impl<Context, Inherited, H> HandleAny<Context> for AnyHandler<Context, Inherited, H>
where
Context: crate::Context,
H: HandlerFor<Context> + CliBindings<Context>,
H: HandlerFor<Context> + CliBindings<Context> + HandlerTS,
H::Params: DeserializeOwned,
H::Ok: Serialize + DeserializeOwned,
H::InheritedParams: OrEmpty<Inherited>,

View File

@@ -1,5 +1,3 @@
#![cfg_attr(feature = "nightly", feature(const_trait_impl, const_type_id))]
pub use cli::*;
// pub use command::*;
pub use context::*;

View File

@@ -1,5 +1,7 @@
use clap::Parser;
use rpc_toolkit::{from_fn_async, Context, Empty, HandlerTS, ParentHandler, Server};
use rpc_toolkit::{
from_fn, from_fn_async, Context, Empty, HandlerExt, HandlerTS, ParentHandler, Server,
};
use serde::{Deserialize, Serialize};
use yajrc::RpcError;
@@ -14,10 +16,19 @@ struct Thing1Params {
thing: String,
}
#[derive(Debug, Deserialize, Serialize, Parser)]
struct NoTSParams {
foo: String,
}
async fn thing1_handler(_ctx: TestContext, params: Thing1Params) -> Result<String, RpcError> {
Ok(format!("Thing1 is {}", params.thing))
}
fn no_ts_handler(_ctx: TestContext, params: NoTSParams) -> Result<String, RpcError> {
Ok(format!("foo:{}", params.foo))
}
#[derive(Debug, Deserialize, Serialize, Parser)]
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
struct GroupParams {
@@ -38,7 +49,8 @@ async fn test_basic_server() {
from_fn_async(|_ctx: TestContext, params: GroupParams| async move {
Ok::<_, RpcError>(format!("verbose: {}", params.verbose))
}),
),
)
.subcommand("no-ts", from_fn(no_ts_handler).no_ts()),
);
println!("{}", root_handler.type_info().unwrap_or_default());