From 4cbbf1a0a7c8bb35ea1de267ed914c2903c95d7c Mon Sep 17 00:00:00 2001 From: Aiden McClelland Date: Tue, 2 Jan 2024 11:56:45 -0700 Subject: [PATCH] wip --- Cargo.lock | 1 + rpc-toolkit/Cargo.toml | 1 + rpc-toolkit/src/cli.rs | 32 +- rpc-toolkit/src/context.rs | 44 +- rpc-toolkit/src/handler.rs | 1501 --------------------------- rpc-toolkit/src/handler/adapters.rs | 485 +++++++++ rpc-toolkit/src/handler/from_fn.rs | 601 +++++++++++ rpc-toolkit/src/handler/marker.rs | 1 + rpc-toolkit/src/handler/mod.rs | 317 ++++++ rpc-toolkit/src/handler/parent.rs | 520 ++++++++++ rpc-toolkit/src/server/mod.rs | 4 +- rpc-toolkit/tests/handler.rs | 5 +- 12 files changed, 1964 insertions(+), 1548 deletions(-) delete mode 100644 rpc-toolkit/src/handler.rs create mode 100644 rpc-toolkit/src/handler/adapters.rs create mode 100644 rpc-toolkit/src/handler/from_fn.rs create mode 100644 rpc-toolkit/src/handler/marker.rs create mode 100644 rpc-toolkit/src/handler/mod.rs create mode 100644 rpc-toolkit/src/handler/parent.rs diff --git a/Cargo.lock b/Cargo.lock index 5b323fd..17d221d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1033,6 +1033,7 @@ dependencies = [ "http-body-util", "hyper 1.0.1", "imbl-value", + "itertools", "lazy_format", "lazy_static", "openssl", diff --git a/rpc-toolkit/Cargo.toml b/rpc-toolkit/Cargo.toml index 146f205..ada859c 100644 --- a/rpc-toolkit/Cargo.toml +++ b/rpc-toolkit/Cargo.toml @@ -23,6 +23,7 @@ futures = "0.3" http = "1" http-body-util = "0.1" hyper = { version = "1", features = ["server", "http1", "http2", "client"] } +itertools = "0.12" imbl-value = "0.1" lazy_format = "2" lazy_static = "1.4" diff --git a/rpc-toolkit/src/cli.rs b/rpc-toolkit/src/cli.rs index fdee58a..c518842 100644 --- a/rpc-toolkit/src/cli.rs +++ b/rpc-toolkit/src/cli.rs @@ -165,11 +165,11 @@ pub async fn call_remote_socket( .result } -pub struct CallRemoteHandler { - _phantom: PhantomData, +pub struct CallRemoteHandler { + _phantom: PhantomData, handler: RemoteHandler, } -impl CallRemoteHandler { +impl CallRemoteHandler { pub fn new(handler: RemoteHandler) -> Self { Self { _phantom: PhantomData, @@ -177,9 +177,7 @@ impl CallRemoteHandler Clone - for CallRemoteHandler -{ +impl Clone for CallRemoteHandler { fn clone(&self) -> Self { Self { _phantom: PhantomData, @@ -187,17 +185,14 @@ impl Clone } } } -impl std::fmt::Debug - for CallRemoteHandler -{ +impl std::fmt::Debug for CallRemoteHandler { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("CallRemoteHandler").finish() } } -impl HandlerTypes for CallRemoteHandler +impl HandlerTypes for CallRemoteHandler where - RemoteContext: IntoContext, RemoteHandler: HandlerTypes, RemoteHandler::Params: Serialize, RemoteHandler::InheritedParams: Serialize, @@ -210,16 +205,15 @@ where type Err = RemoteHandler::Err; } #[async_trait::async_trait] -impl Handler - for CallRemoteHandler +impl Handler for CallRemoteHandler where - RemoteContext: IntoContext, - RemoteHandler: Handler, + RemoteHandler: Handler, RemoteHandler::Params: Serialize, RemoteHandler::InheritedParams: Serialize, RemoteHandler::Ok: DeserializeOwned, RemoteHandler::Err: From, { + type Context = Context; async fn handle_async( &self, handle_args: HandleArgs, @@ -245,17 +239,15 @@ where } } } -// #[async_trait::async_trait] -impl CliBindings - for CallRemoteHandler +impl CliBindings for CallRemoteHandler where - RemoteContext: IntoContext, - RemoteHandler: Handler + CliBindings, + RemoteHandler: Handler + CliBindings, RemoteHandler::Params: Serialize, RemoteHandler::InheritedParams: Serialize, RemoteHandler::Ok: DeserializeOwned, RemoteHandler::Err: From, { + type Context = Context; fn cli_command(&self, ctx_ty: TypeId) -> clap::Command { self.handler.cli_command(ctx_ty) } diff --git a/rpc-toolkit/src/context.rs b/rpc-toolkit/src/context.rs index 0683fd2..a5a0deb 100644 --- a/rpc-toolkit/src/context.rs +++ b/rpc-toolkit/src/context.rs @@ -1,10 +1,8 @@ use std::any::{Any, TypeId}; -use std::collections::BTreeSet; +use imbl_value::imbl::OrdSet; use tokio::runtime::Handle; -use crate::Handler; - pub trait Context: Any + Send + Sync + 'static { fn inner_type_id(&self) -> TypeId { ::type_id(&self) @@ -17,7 +15,7 @@ pub trait Context: Any + Send + Sync + 'static { #[allow(private_bounds)] pub trait IntoContext: sealed::Sealed + Any + Send + Sync + Sized + 'static { fn runtime(&self) -> Handle; - fn type_ids_for + ?Sized>(handler: &H) -> Option>; + fn type_ids() -> Option>; fn inner_type_id(&self) -> TypeId; fn upcast(self) -> AnyContext; fn downcast(value: AnyContext) -> Result; @@ -27,8 +25,8 @@ impl IntoContext for C { fn runtime(&self) -> Handle { ::runtime(&self) } - fn type_ids_for + ?Sized>(_: &H) -> Option> { - let mut set = BTreeSet::new(); + fn type_ids() -> Option> { + let mut set = OrdSet::new(); set.insert(TypeId::of::()); Some(set) } @@ -51,38 +49,38 @@ pub enum EitherContext { C1(C1), C2(C2), } -impl IntoContext for EitherContext { +impl IntoContext for EitherContext { fn runtime(&self) -> Handle { match self { Self::C1(a) => a.runtime(), Self::C2(a) => a.runtime(), } } - fn type_ids_for + ?Sized>(_: &H) -> Option> { - let mut set = BTreeSet::new(); - set.insert(TypeId::of::()); - set.insert(TypeId::of::()); + fn type_ids() -> Option> { + let mut set = OrdSet::new(); + set.extend(C1::type_ids()?); + set.extend(C2::type_ids()?); Some(set) } fn inner_type_id(&self) -> TypeId { match self { - EitherContext::C1(c) => c.type_id(), - EitherContext::C2(c) => c.type_id(), + EitherContext::C1(c) => c.inner_type_id(), + EitherContext::C2(c) => c.inner_type_id(), } } fn downcast(value: AnyContext) -> Result { - if value.inner_type_id() == TypeId::of::() { - Ok(EitherContext::C1(C1::downcast(value)?)) - } else if value.inner_type_id() == TypeId::of::() { - Ok(EitherContext::C2(C2::downcast(value)?)) - } else { - Err(value) + match C1::downcast(value) { + Ok(a) => Ok(EitherContext::C1(a)), + Err(value) => match C2::downcast(value) { + Ok(a) => Ok(EitherContext::C2(a)), + Err(value) => Err(value), + }, } } fn upcast(self) -> AnyContext { match self { - Self::C1(c) => AnyContext::new(c), - Self::C2(c) => AnyContext::new(c), + Self::C1(c) => c.upcast(), + Self::C2(c) => c.upcast(), } } } @@ -102,7 +100,7 @@ impl IntoContext for AnyContext { fn runtime(&self) -> Handle { self.0.runtime() } - fn type_ids_for + ?Sized>(_: &H) -> Option> { + fn type_ids() -> Option> { None } fn inner_type_id(&self) -> TypeId { @@ -119,6 +117,6 @@ impl IntoContext for AnyContext { mod sealed { pub(crate) trait Sealed {} impl Sealed for C {} - impl Sealed for super::EitherContext {} + impl Sealed for super::EitherContext {} impl Sealed for super::AnyContext {} } diff --git a/rpc-toolkit/src/handler.rs b/rpc-toolkit/src/handler.rs deleted file mode 100644 index 6d85d31..0000000 --- a/rpc-toolkit/src/handler.rs +++ /dev/null @@ -1,1501 +0,0 @@ -use std::any::TypeId; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; -use std::fmt::Display; -use std::marker::PhantomData; -use std::ops::Deref; -use std::sync::Arc; - -use clap::{ArgMatches, Command, CommandFactory, FromArgMatches, Parser}; -use futures::Future; -use imbl_value::imbl::OrdMap; -use imbl_value::Value; -use serde::de::DeserializeOwned; -use serde::{Deserialize, Serialize}; -use yajrc::RpcError; - -use crate::context::{AnyContext, IntoContext}; -use crate::util::{combine, internal_error, invalid_params, Flat}; -use crate::{CallRemote, CallRemoteHandler}; - -pub(crate) struct HandleAnyArgs { - pub(crate) context: AnyContext, - pub(crate) parent_method: VecDeque<&'static str>, - pub(crate) method: VecDeque<&'static str>, - pub(crate) params: Value, -} -impl HandleAnyArgs { - fn downcast(self) -> Result, imbl_value::Error> - where - H: HandlerTypes, - H::Params: DeserializeOwned, - H::InheritedParams: DeserializeOwned, - { - let Self { - context, - parent_method, - method, - params, - } = self; - Ok(HandleArgs { - context: Context::downcast(context).map_err(|_| imbl_value::Error { - kind: imbl_value::ErrorKind::Deserialization, - source: serde::ser::Error::custom("context does not match expected"), - })?, - parent_method, - method, - params: imbl_value::from_value(params.clone())?, - inherited_params: imbl_value::from_value(params.clone())?, - raw_params: params, - }) - } -} - -#[async_trait::async_trait] -pub(crate) trait HandleAny: std::fmt::Debug + Send + Sync { - fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result; - async fn handle_async(&self, handle_args: HandleAnyArgs) -> Result; - fn metadata( - &self, - method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value>; - fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option>; -} -#[async_trait::async_trait] -impl HandleAny for Arc { - fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result { - self.deref().handle_sync(handle_args) - } - async fn handle_async(&self, handle_args: HandleAnyArgs) -> Result { - self.deref().handle_async(handle_args).await - } - fn metadata( - &self, - method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.deref().metadata(method, ctx_ty) - } - fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { - self.deref().method_from_dots(method, ctx_ty) - } -} - -pub(crate) trait CliBindingsAny { - fn cli_command(&self, ctx_ty: TypeId) -> Command; - fn cli_parse( - &self, - matches: &ArgMatches, - ctx_ty: TypeId, - ) -> Result<(VecDeque<&'static str>, Value), clap::Error>; - fn cli_display(&self, handle_args: HandleAnyArgs, result: Value) -> Result<(), RpcError>; -} - -pub trait CliBindings: HandlerTypes { - fn cli_command(&self, ctx_ty: TypeId) -> Command; - fn cli_parse( - &self, - matches: &ArgMatches, - ctx_ty: TypeId, - ) -> Result<(VecDeque<&'static str>, Value), clap::Error>; - fn cli_display( - &self, - handle_args: HandleArgs, - result: Self::Ok, - ) -> Result<(), Self::Err>; -} - -pub trait PrintCliResult: HandlerTypes { - fn print( - &self, - handle_args: HandleArgs, - result: Self::Ok, - ) -> Result<(), Self::Err>; -} - -pub(crate) trait HandleAnyWithCli: HandleAny + CliBindingsAny {} -impl HandleAnyWithCli for T {} - -#[derive(Debug, Clone)] -pub(crate) enum DynHandler { - WithoutCli(Arc), - WithCli(Arc), -} -#[async_trait::async_trait] -impl HandleAny for DynHandler { - fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result { - match self { - DynHandler::WithoutCli(h) => h.handle_sync(handle_args), - DynHandler::WithCli(h) => h.handle_sync(handle_args), - } - } - async fn handle_async(&self, handle_args: HandleAnyArgs) -> Result { - match self { - DynHandler::WithoutCli(h) => h.handle_async(handle_args).await, - DynHandler::WithCli(h) => h.handle_async(handle_args).await, - } - } - fn metadata( - &self, - method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - match self { - DynHandler::WithoutCli(h) => h.metadata(method, ctx_ty), - DynHandler::WithCli(h) => h.metadata(method, ctx_ty), - } - } - fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { - match self { - DynHandler::WithoutCli(h) => h.method_from_dots(method, ctx_ty), - DynHandler::WithCli(h) => h.method_from_dots(method, ctx_ty), - } - } -} - -#[derive(Debug, Clone)] -pub struct HandleArgs { - pub context: Context, - pub parent_method: VecDeque<&'static str>, - pub method: VecDeque<&'static str>, - pub params: H::Params, - pub inherited_params: H::InheritedParams, - pub raw_params: Value, -} - -pub trait HandlerTypes { - type Params: Send + Sync; - type InheritedParams: Send + Sync; - type Ok: Send + Sync; - type Err: Send + Sync; -} - -#[async_trait::async_trait] -pub trait Handler: - HandlerTypes + std::fmt::Debug + Clone + Send + Sync + 'static -{ - fn handle_sync(&self, handle_args: HandleArgs) -> Result { - handle_args - .context - .runtime() - .block_on(self.handle_async(handle_args)) - } - async fn handle_async( - &self, - handle_args: HandleArgs, - ) -> Result; - async fn handle_async_with_sync( - &self, - handle_args: HandleArgs, - ) -> Result { - self.handle_sync(handle_args) - } - async fn handle_async_with_sync_blocking( - &self, - handle_args: HandleArgs, - ) -> Result { - let s = self.clone(); - handle_args - .context - .runtime() - .spawn_blocking(move || s.handle_sync(handle_args)) - .await - .unwrap() - } - #[allow(unused_variables)] - fn metadata( - &self, - method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - OrdMap::new() - } - fn contexts(&self) -> Option> { - Context::type_ids_for(self) - } - #[allow(unused_variables)] - fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { - if method.is_empty() { - Some(VecDeque::new()) - } else { - None - } - } -} - -pub(crate) struct AnyHandler { - _ctx: PhantomData, - handler: H, -} -impl AnyHandler { - pub(crate) fn new(handler: H) -> Self { - Self { - _ctx: PhantomData, - handler, - } - } -} -impl std::fmt::Debug for AnyHandler { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("AnyHandler").field(&self.handler).finish() - } -} - -#[async_trait::async_trait] -impl> HandleAny for AnyHandler -where - H::Params: DeserializeOwned, - H::InheritedParams: DeserializeOwned, - H::Ok: Serialize, - RpcError: From, -{ - fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result { - imbl_value::to_value( - &self - .handler - .handle_sync(handle_args.downcast().map_err(invalid_params)?)?, - ) - .map_err(internal_error) - } - async fn handle_async(&self, handle_args: HandleAnyArgs) -> Result { - imbl_value::to_value( - &self - .handler - .handle_async(handle_args.downcast().map_err(invalid_params)?) - .await?, - ) - .map_err(internal_error) - } - fn metadata( - &self, - method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.handler.metadata(method, ctx_ty) - } - fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { - self.handler.method_from_dots(method, ctx_ty) - } -} - -impl> CliBindingsAny for AnyHandler -where - H: CliBindings, - H::Params: DeserializeOwned, - H::InheritedParams: DeserializeOwned, - H::Ok: Serialize + DeserializeOwned, - RpcError: From, -{ - fn cli_command(&self, ctx_ty: TypeId) -> Command { - self.handler.cli_command(ctx_ty) - } - fn cli_parse( - &self, - matches: &ArgMatches, - ctx_ty: TypeId, - ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { - self.handler.cli_parse(matches, ctx_ty) - } - fn cli_display(&self, handle_args: HandleAnyArgs, result: Value) -> Result<(), RpcError> { - self.handler - .cli_display( - handle_args.downcast().map_err(invalid_params)?, - imbl_value::from_value(result).map_err(internal_error)?, - ) - .map_err(RpcError::from) - } -} - -#[derive(Debug, Clone, Copy, Deserialize, Serialize, Parser)] -pub struct NoParams {} - -#[derive(Debug, Clone, Copy, Deserialize, Serialize, Parser)] -pub enum Never {} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub(crate) struct Name(pub(crate) Option<&'static str>); -impl<'a> std::borrow::Borrow> for Name { - fn borrow(&self) -> &Option<&'a str> { - &self.0 - } -} - -#[derive(Debug, Clone)] -pub(crate) struct SubcommandMap(pub(crate) OrdMap, DynHandler>>); -impl SubcommandMap { - fn insert( - &mut self, - ctx_tys: Option>, - name: Option<&'static str>, - handler: DynHandler, - ) { - let mut for_name = self.0.remove(&name).unwrap_or_default(); - if let Some(ctx_tys) = ctx_tys { - for ctx_ty in ctx_tys { - for_name.insert(Some(ctx_ty), handler.clone()); - } - } else { - for_name.insert(None, handler); - } - self.0.insert(Name(name), for_name); - } - - fn get<'a>(&'a self, ctx_ty: TypeId, name: Option<&str>) -> Option<(Name, &'a DynHandler)> { - if let Some((name, for_name)) = self.0.get_key_value(&name) { - if let Some(for_ctx) = for_name.get(&Some(ctx_ty)) { - Some((*name, for_ctx)) - } else { - for_name.get(&None).map(|h| (*name, h)) - } - } else { - None - } - } -} - -pub struct ParentHandler { - _phantom: PhantomData<(Params, InheritedParams)>, - pub(crate) subcommands: SubcommandMap, - metadata: OrdMap<&'static str, Value>, -} -impl ParentHandler { - pub fn new() -> Self { - Self { - _phantom: PhantomData, - subcommands: SubcommandMap(OrdMap::new()), - metadata: OrdMap::new(), - } - } - pub fn with_metadata(mut self, key: &'static str, value: Value) -> Self { - self.metadata.insert(key, value); - self - } -} -impl Clone for ParentHandler { - fn clone(&self) -> Self { - Self { - _phantom: PhantomData, - subcommands: self.subcommands.clone(), - metadata: self.metadata.clone(), - } - } -} -impl std::fmt::Debug for ParentHandler { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("ParentHandler") - .field(&self.subcommands) - .finish() - } -} - -struct InheritanceHandler { - _phantom: PhantomData<(Context, Params, InheritedParams)>, - handler: H, - inherit: F, -} -impl Clone - for InheritanceHandler -{ - fn clone(&self) -> Self { - Self { - _phantom: PhantomData, - handler: self.handler.clone(), - inherit: self.inherit.clone(), - } - } -} -impl std::fmt::Debug - for InheritanceHandler -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_tuple("InheritanceHandler") - .field(&self.handler) - .finish() - } -} -impl HandlerTypes - for InheritanceHandler -where - Context: IntoContext, - H: HandlerTypes, - Params: Send + Sync, - InheritedParams: Send + Sync, -{ - type Params = H::Params; - type InheritedParams = Flat; - type Ok = H::Ok; - type Err = H::Err; -} -#[async_trait::async_trait] -impl Handler - for InheritanceHandler -where - Context: IntoContext, - Params: Send + Sync + 'static, - InheritedParams: Send + Sync + 'static, - H: Handler, - F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, -{ - fn handle_sync( - &self, - HandleArgs { - context, - parent_method, - method, - params, - inherited_params, - raw_params, - }: HandleArgs, - ) -> Result { - self.handler.handle_sync(HandleArgs { - context, - parent_method, - method, - params, - inherited_params: (self.inherit)(inherited_params.0, inherited_params.1), - raw_params, - }) - } - async fn handle_async( - &self, - HandleArgs { - context, - parent_method, - method, - params, - inherited_params, - raw_params, - }: HandleArgs, - ) -> Result { - self.handler.handle_sync(HandleArgs { - context, - parent_method, - method, - params, - inherited_params: (self.inherit)(inherited_params.0, inherited_params.1), - raw_params, - }) - } - fn metadata( - &self, - method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.handler.metadata(method, ctx_ty) - } - fn contexts(&self) -> Option> { - self.handler.contexts() - } - fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { - self.handler.method_from_dots(method, ctx_ty) - } -} - -impl CliBindings - for InheritanceHandler -where - Context: IntoContext, - Params: Send + Sync + 'static, - InheritedParams: Send + Sync + 'static, - H: CliBindings, - F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, -{ - fn cli_command(&self, ctx_ty: TypeId) -> Command { - self.handler.cli_command(ctx_ty) - } - fn cli_parse( - &self, - matches: &ArgMatches, - ctx_ty: TypeId, - ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { - self.handler.cli_parse(matches, ctx_ty) - } - fn cli_display( - &self, - HandleArgs { - context, - parent_method, - method, - params, - inherited_params, - raw_params, - }: HandleArgs, - result: Self::Ok, - ) -> Result<(), Self::Err> { - self.handler.cli_display( - HandleArgs { - context, - parent_method, - method, - params, - inherited_params: (self.inherit)(inherited_params.0, inherited_params.1), - raw_params, - }, - result, - ) - } -} - -impl ParentHandler { - pub fn subcommand(mut self, name: &'static str, handler: H) -> Self - where - Context: IntoContext, - H: HandlerTypes - + Handler - + CliBindings - + 'static, - H::Params: DeserializeOwned, - H::Ok: Serialize + DeserializeOwned, - RpcError: From, - { - self.subcommands.insert( - handler.contexts(), - name.into(), - DynHandler::WithCli(Arc::new(AnyHandler::new(handler))), - ); - self - } - pub fn subcommand_remote_cli( - mut self, - name: &'static str, - handler: H, - ) -> Self - where - ServerContext: IntoContext, - CliContext: IntoContext + CallRemote, - H: HandlerTypes - + Handler - + CliBindings - + 'static, - H::Params: Serialize + DeserializeOwned, - H::Ok: Serialize + DeserializeOwned, - RpcError: From, - H::Err: From, - CallRemoteHandler: Handler, - as HandlerTypes>::Ok: Serialize + DeserializeOwned, - as HandlerTypes>::Params: Serialize + DeserializeOwned, - as HandlerTypes>::InheritedParams: DeserializeOwned, - RpcError: From< as HandlerTypes>::Err>, - { - self.subcommands.insert( - handler.contexts(), - name.into(), - DynHandler::WithoutCli(Arc::new(AnyHandler::new(handler.clone()))), - ); - let call_remote = CallRemoteHandler::::new(handler); - self.subcommands.insert( - call_remote.contexts(), - name.into(), - DynHandler::WithCli(Arc::new(AnyHandler::new(call_remote))), - ); - self - } - pub fn subcommand_no_cli(mut self, name: &'static str, handler: H) -> Self - where - Context: IntoContext, - H: Handler + 'static, - H::Params: DeserializeOwned, - H::Ok: Serialize, - RpcError: From, - { - self.subcommands.insert( - handler.contexts(), - name.into(), - DynHandler::WithoutCli(Arc::new(AnyHandler::new(handler))), - ); - self - } -} -impl ParentHandler -where - Params: DeserializeOwned + 'static, - InheritedParams: DeserializeOwned + 'static, -{ - pub fn subcommand_with_inherited( - mut self, - name: &'static str, - handler: H, - inherit: F, - ) -> Self - where - Context: IntoContext, - H: Handler + CliBindings + 'static, - H::Params: DeserializeOwned, - H::Ok: Serialize + DeserializeOwned, - RpcError: From, - F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, - { - self.subcommands.insert( - handler.contexts(), - name.into(), - DynHandler::WithCli(Arc::new(AnyHandler { - _ctx: PhantomData, - handler: InheritanceHandler:: { - _phantom: PhantomData, - handler, - inherit, - }, - })), - ); - self - } - pub fn subcommand_with_inherited_remote_cli( - mut self, - name: &'static str, - handler: H, - inherit: F, - ) -> Self - where - ServerContext: IntoContext, - CliContext: IntoContext + CallRemote, - H: HandlerTypes + Handler + CliBindings + 'static, - H::Params: Serialize + DeserializeOwned, - H::Ok: Serialize + DeserializeOwned, - RpcError: From, - H::Err: From, - CallRemoteHandler: - Handler, - as HandlerTypes>::Ok: Serialize + DeserializeOwned, - as HandlerTypes>::Params: Serialize + DeserializeOwned, - as HandlerTypes>::InheritedParams: - Serialize + DeserializeOwned, - RpcError: From< as HandlerTypes>::Err>, - F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, - { - self.subcommands.insert( - handler.contexts(), - name.into(), - DynHandler::WithoutCli(Arc::new(AnyHandler::new(InheritanceHandler::< - ServerContext, - Params, - InheritedParams, - H, - F, - > { - _phantom: PhantomData, - handler: handler.clone(), - inherit: inherit.clone(), - }))), - ); - let call_remote = CallRemoteHandler::::new(handler); - self.subcommands.insert( - call_remote.contexts(), - name.into(), - DynHandler::WithCli(Arc::new(AnyHandler::new(InheritanceHandler::< - CliContext, - Params, - InheritedParams, - CallRemoteHandler, - F, - > { - _phantom: PhantomData, - handler: call_remote, - inherit, - }))), - ); - self - } - pub fn subcommand_with_inherited_no_cli( - mut self, - name: &'static str, - handler: H, - inherit: F, - ) -> Self - where - Context: IntoContext, - H: Handler + 'static, - H::Params: DeserializeOwned, - H::Ok: Serialize, - RpcError: From, - F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, - { - self.subcommands.insert( - handler.contexts(), - name.into(), - DynHandler::WithoutCli(Arc::new(AnyHandler { - _ctx: PhantomData, - handler: InheritanceHandler:: { - _phantom: PhantomData, - handler, - inherit, - }, - })), - ); - self - } - pub fn root_handler(mut self, handler: H, inherit: F) -> Self - where - Context: IntoContext, - H: HandlerTypes + Handler + CliBindings + 'static, - H::Params: DeserializeOwned, - H::Ok: Serialize + DeserializeOwned, - RpcError: From, - F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, - { - self.subcommands.insert( - handler.contexts(), - None, - DynHandler::WithCli(Arc::new(AnyHandler { - _ctx: PhantomData, - handler: InheritanceHandler:: { - _phantom: PhantomData, - handler, - inherit, - }, - })), - ); - self - } - pub fn root_handler_no_cli(mut self, handler: H, inherit: F) -> Self - where - Context: IntoContext, - H: Handler + 'static, - H::Params: DeserializeOwned, - H::Ok: Serialize, - RpcError: From, - F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, - { - self.subcommands.insert( - handler.contexts(), - None, - DynHandler::WithoutCli(Arc::new(AnyHandler { - _ctx: PhantomData, - handler: InheritanceHandler:: { - _phantom: PhantomData, - handler, - inherit, - }, - })), - ); - self - } -} - -impl HandlerTypes for ParentHandler -where - Params: Send + Sync, - InheritedParams: Send + Sync, -{ - type Params = Params; - type InheritedParams = InheritedParams; - type Ok = Value; - type Err = RpcError; -} -#[async_trait::async_trait] -impl Handler for ParentHandler -where - Context: IntoContext, - Params: Serialize + Send + Sync + 'static, - InheritedParams: Serialize + Send + Sync + 'static, -{ - fn handle_sync( - &self, - HandleArgs { - context, - mut parent_method, - mut method, - raw_params, - .. - }: HandleArgs, - ) -> Result { - let cmd = method.pop_front(); - if let Some(cmd) = cmd { - parent_method.push_back(cmd); - } - if let Some((_, sub_handler)) = &self.subcommands.get(context.inner_type_id(), cmd) { - sub_handler.handle_sync(HandleAnyArgs { - context: context.upcast(), - parent_method, - method, - params: raw_params, - }) - } else { - Err(yajrc::METHOD_NOT_FOUND_ERROR) - } - } - async fn handle_async( - &self, - HandleArgs { - context, - mut parent_method, - mut method, - raw_params, - .. - }: HandleArgs, - ) -> Result { - let cmd = method.pop_front(); - if let Some(cmd) = cmd { - parent_method.push_back(cmd); - } - if let Some((_, sub_handler)) = self.subcommands.get(context.inner_type_id(), cmd) { - sub_handler - .handle_async(HandleAnyArgs { - context: context.upcast(), - parent_method, - method, - params: raw_params, - }) - .await - } else { - Err(yajrc::METHOD_NOT_FOUND_ERROR) - } - } - fn metadata( - &self, - mut method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - let mut metadata = self.metadata.clone(); - if let Some((_, handler)) = self.subcommands.get(ctx_ty, method.pop_front()) { - handler.metadata(method, ctx_ty).union(metadata) - } else { - metadata - } - } - fn contexts(&self) -> Option> { - let mut set = BTreeSet::new(); - for ctx_ty in self.subcommands.0.values().flat_map(|c| c.keys()) { - set.insert((*ctx_ty)?); - } - Some(set) - } - fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { - let (head, tail) = if method.is_empty() { - (None, None) - } else { - method - .split_once(".") - .map(|(head, tail)| (Some(head), Some(tail))) - .unwrap_or((Some(method), None)) - }; - let (Name(name), h) = self.subcommands.get(ctx_ty, head)?; - let mut res = VecDeque::new(); - if let Some(name) = name { - res.push_back(name); - } - if let Some(tail) = tail { - res.append(&mut h.method_from_dots(tail, ctx_ty)?); - } - Some(res) - } -} - -impl CliBindings for ParentHandler -where - Params: FromArgMatches + CommandFactory + Serialize + Send + Sync + 'static, - InheritedParams: Serialize + Send + Sync + 'static, -{ - fn cli_command(&self, ctx_ty: TypeId) -> Command { - let mut base = Params::command(); - for (name, handlers) in &self.subcommands.0 { - if let (Name(Some(name)), Some(DynHandler::WithCli(handler))) = ( - name, - if let Some(handler) = handlers.get(&Some(ctx_ty)) { - Some(handler) - } else if let Some(handler) = handlers.get(&None) { - Some(handler) - } else { - None - }, - ) { - base = base.subcommand(handler.cli_command(ctx_ty).name(name)); - } - } - base - } - fn cli_parse( - &self, - matches: &ArgMatches, - ctx_ty: TypeId, - ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { - let root_params = imbl_value::to_value(&Params::from_arg_matches(matches)?) - .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?; - let (name, matches) = match matches.subcommand() { - Some((name, matches)) => (Some(name), matches), - None => (None, matches), - }; - if let Some((Name(Some(name)), DynHandler::WithCli(handler))) = - self.subcommands.get(ctx_ty, name) - { - let (mut method, params) = handler.cli_parse(matches, ctx_ty)?; - method.push_front(name); - - Ok(( - method, - combine(root_params, params) - .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ArgumentConflict, e))?, - )) - } else { - Ok((VecDeque::new(), root_params)) - } - } - fn cli_display( - &self, - HandleArgs { - context, - mut parent_method, - mut method, - raw_params, - .. - }: HandleArgs, - result: Self::Ok, - ) -> Result<(), Self::Err> { - let cmd = method.pop_front(); - if let Some(cmd) = cmd { - parent_method.push_back(cmd); - } - if let Some((_, DynHandler::WithCli(sub_handler))) = - self.subcommands.get(context.inner_type_id(), cmd) - { - sub_handler.cli_display( - HandleAnyArgs { - context, - parent_method, - method, - params: raw_params, - }, - result, - ) - } else { - Err(yajrc::METHOD_NOT_FOUND_ERROR) - } - } -} - -pub struct FromFn { - _phantom: PhantomData<(T, E, Args)>, - function: F, - blocking: bool, - metadata: OrdMap<&'static str, Value>, -} -impl FromFn { - pub fn with_metadata(mut self, key: &'static str, value: Value) -> Self { - self.metadata.insert(key, value); - self - } -} -impl Clone for FromFn { - fn clone(&self) -> Self { - Self { - _phantom: PhantomData, - function: self.function.clone(), - blocking: self.blocking, - metadata: self.metadata.clone(), - } - } -} -impl std::fmt::Debug for FromFn { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("FromFn") - .field("blocking", &self.blocking) - .finish() - } -} -impl PrintCliResult for FromFn -where - Context: IntoContext, - Self: HandlerTypes, - ::Ok: Display, -{ - fn print(&self, _: HandleArgs, result: Self::Ok) -> Result<(), Self::Err> { - Ok(println!("{result}")) - } -} - -pub fn from_fn(function: F) -> FromFn { - FromFn { - function, - _phantom: PhantomData, - blocking: false, - metadata: OrdMap::new(), - } -} - -pub fn from_fn_blocking(function: F) -> FromFn { - FromFn { - function, - _phantom: PhantomData, - blocking: true, - metadata: OrdMap::new(), - } -} - -pub struct FromFnAsync { - _phantom: PhantomData<(Fut, T, E, Args)>, - function: F, - metadata: OrdMap<&'static str, Value>, -} -impl Clone for FromFnAsync { - fn clone(&self) -> Self { - Self { - _phantom: PhantomData, - function: self.function.clone(), - metadata: self.metadata.clone(), - } - } -} -impl std::fmt::Debug for FromFnAsync { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("FromFnAsync").finish() - } -} -impl PrintCliResult for FromFnAsync -where - Context: IntoContext, - Self: HandlerTypes, - ::Ok: Display, -{ - fn print(&self, _: HandleArgs, result: Self::Ok) -> Result<(), Self::Err> { - Ok(println!("{result}")) - } -} - -pub fn from_fn_async(function: F) -> FromFnAsync { - FromFnAsync { - function, - _phantom: PhantomData, - metadata: OrdMap::new(), - } -} - -impl HandlerTypes for FromFn -where - F: Fn() -> Result + Send + Sync + Clone + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - type Params = NoParams; - type InheritedParams = NoParams; - type Ok = T; - type Err = E; -} -#[async_trait::async_trait] -impl Handler for FromFn -where - Context: IntoContext, - F: Fn() -> Result + Send + Sync + Clone + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - fn handle_sync(&self, _: HandleArgs) -> Result { - (self.function)() - } - async fn handle_async( - &self, - handle_args: HandleArgs, - ) -> Result { - if self.blocking { - self.handle_async_with_sync_blocking(handle_args).await - } else { - self.handle_async_with_sync(handle_args).await - } - } - fn metadata( - &self, - mut method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.metadata.clone() - } -} -impl HandlerTypes for FromFnAsync -where - F: Fn() -> Fut + Send + Sync + Clone + 'static, - Fut: Future> + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - type Params = NoParams; - type InheritedParams = NoParams; - type Ok = T; - type Err = E; -} -#[async_trait::async_trait] -impl Handler for FromFnAsync -where - Context: IntoContext, - F: Fn() -> Fut + Send + Sync + Clone + 'static, - Fut: Future> + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - async fn handle_async(&self, _: HandleArgs) -> Result { - (self.function)().await - } - fn metadata( - &self, - mut method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.metadata.clone() - } -} - -impl HandlerTypes for FromFn -where - Context: IntoContext, - F: Fn(Context) -> Result + Send + Sync + Clone + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - type Params = NoParams; - type InheritedParams = NoParams; - type Ok = T; - type Err = E; -} -#[async_trait::async_trait] -impl Handler for FromFn -where - Context: IntoContext, - F: Fn(Context) -> Result + Send + Sync + Clone + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - fn handle_sync(&self, handle_args: HandleArgs) -> Result { - (self.function)(handle_args.context) - } - async fn handle_async( - &self, - handle_args: HandleArgs, - ) -> Result { - if self.blocking { - self.handle_async_with_sync_blocking(handle_args).await - } else { - self.handle_async_with_sync(handle_args).await - } - } - fn metadata( - &self, - mut method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.metadata.clone() - } -} -impl HandlerTypes for FromFnAsync -where - Context: IntoContext, - F: Fn(Context) -> Fut + Send + Sync + Clone + 'static, - Fut: Future> + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - type Params = NoParams; - type InheritedParams = NoParams; - type Ok = T; - type Err = E; -} -#[async_trait::async_trait] -impl Handler for FromFnAsync -where - Context: IntoContext, - F: Fn(Context) -> Fut + Send + Sync + Clone + 'static, - Fut: Future> + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - async fn handle_async( - &self, - handle_args: HandleArgs, - ) -> Result { - (self.function)(handle_args.context).await - } - fn metadata( - &self, - mut method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.metadata.clone() - } -} - -impl HandlerTypes for FromFn -where - Context: IntoContext, - F: Fn(Context, Params) -> Result + Send + Sync + Clone + 'static, - Params: DeserializeOwned + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - type Params = Params; - type InheritedParams = NoParams; - type Ok = T; - type Err = E; -} -#[async_trait::async_trait] -impl Handler for FromFn -where - Context: IntoContext, - F: Fn(Context, Params) -> Result + Send + Sync + Clone + 'static, - Params: DeserializeOwned + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - fn handle_sync(&self, handle_args: HandleArgs) -> Result { - let HandleArgs { - context, params, .. - } = handle_args; - (self.function)(context, params) - } - async fn handle_async( - &self, - handle_args: HandleArgs, - ) -> Result { - if self.blocking { - self.handle_async_with_sync_blocking(handle_args).await - } else { - self.handle_async_with_sync(handle_args).await - } - } - fn metadata( - &self, - mut method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.metadata.clone() - } -} - -impl HandlerTypes for FromFnAsync -where - Context: IntoContext, - F: Fn(Context, Params) -> Fut + Send + Sync + Clone + 'static, - Fut: Future> + Send + Sync + 'static, - Params: DeserializeOwned + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - type Params = Params; - type InheritedParams = NoParams; - type Ok = T; - type Err = E; -} -#[async_trait::async_trait] -impl Handler - for FromFnAsync -where - Context: IntoContext, - F: Fn(Context, Params) -> Fut + Send + Sync + Clone + 'static, - Fut: Future> + Send + Sync + 'static, - Params: DeserializeOwned + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - async fn handle_async( - &self, - handle_args: HandleArgs, - ) -> Result { - let HandleArgs { - context, params, .. - } = handle_args; - (self.function)(context, params).await - } - fn metadata( - &self, - mut method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.metadata.clone() - } -} - -impl HandlerTypes - for FromFn -where - Context: IntoContext, - F: Fn(Context, Params, InheritedParams) -> Result + Send + Sync + Clone + 'static, - Params: DeserializeOwned + Send + Sync + 'static, - InheritedParams: DeserializeOwned + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - type Params = Params; - type InheritedParams = InheritedParams; - type Ok = T; - type Err = E; -} -#[async_trait::async_trait] -impl Handler - for FromFn -where - Context: IntoContext, - F: Fn(Context, Params, InheritedParams) -> Result + Send + Sync + Clone + 'static, - Params: DeserializeOwned + Send + Sync + 'static, - InheritedParams: DeserializeOwned + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - fn handle_sync(&self, handle_args: HandleArgs) -> Result { - let HandleArgs { - context, - params, - inherited_params, - .. - } = handle_args; - (self.function)(context, params, inherited_params) - } - async fn handle_async( - &self, - handle_args: HandleArgs, - ) -> Result { - if self.blocking { - self.handle_async_with_sync_blocking(handle_args).await - } else { - self.handle_async_with_sync(handle_args).await - } - } - fn metadata( - &self, - mut method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.metadata.clone() - } -} - -impl HandlerTypes - for FromFnAsync -where - Context: IntoContext, - F: Fn(Context, Params, InheritedParams) -> Fut + Send + Sync + Clone + 'static, - Fut: Future> + Send + Sync + 'static, - Params: DeserializeOwned + Send + Sync + 'static, - InheritedParams: DeserializeOwned + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - type Params = Params; - type InheritedParams = InheritedParams; - type Ok = T; - type Err = E; -} -#[async_trait::async_trait] -impl Handler - for FromFnAsync -where - Context: IntoContext, - F: Fn(Context, Params, InheritedParams) -> Fut + Send + Sync + Clone + 'static, - Fut: Future> + Send + Sync + 'static, - Params: DeserializeOwned + Send + Sync + 'static, - InheritedParams: DeserializeOwned + Send + Sync + 'static, - T: Send + Sync + 'static, - E: Send + Sync + 'static, -{ - async fn handle_async( - &self, - handle_args: HandleArgs, - ) -> Result { - let HandleArgs { - context, - params, - inherited_params, - .. - } = handle_args; - (self.function)(context, params, inherited_params).await - } - fn metadata( - &self, - mut method: VecDeque<&'static str>, - ctx_ty: TypeId, - ) -> OrdMap<&'static str, Value> { - self.metadata.clone() - } -} - -impl CliBindings for FromFn -where - Context: IntoContext, - Self: HandlerTypes, - Self::Params: FromArgMatches + CommandFactory + Serialize, - Self: PrintCliResult, -{ - fn cli_command(&self, _: TypeId) -> Command { - Self::Params::command() - } - fn cli_parse( - &self, - matches: &ArgMatches, - _: TypeId, - ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { - Self::Params::from_arg_matches(matches).and_then(|a| { - Ok(( - VecDeque::new(), - imbl_value::to_value(&a) - .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?, - )) - }) - } - fn cli_display( - &self, - HandleArgs { - context, - parent_method, - method, - params, - inherited_params, - raw_params, - }: HandleArgs, - result: Self::Ok, - ) -> Result<(), Self::Err> { - self.print( - HandleArgs { - context, - parent_method, - method, - params, - inherited_params, - raw_params, - }, - result, - ) - } -} - -impl CliBindings for FromFnAsync -where - Context: IntoContext, - Self: HandlerTypes, - Self::Params: FromArgMatches + CommandFactory + Serialize, - Self: PrintCliResult, -{ - fn cli_command(&self, _: TypeId) -> Command { - Self::Params::command() - } - fn cli_parse( - &self, - matches: &ArgMatches, - _: TypeId, - ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { - Self::Params::from_arg_matches(matches).and_then(|a| { - Ok(( - VecDeque::new(), - imbl_value::to_value(&a) - .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?, - )) - }) - } - fn cli_display( - &self, - HandleArgs { - context, - parent_method, - method, - params, - inherited_params, - raw_params, - }: HandleArgs, - result: Self::Ok, - ) -> Result<(), Self::Err> { - self.print( - HandleArgs { - context, - parent_method, - method, - params, - inherited_params, - raw_params, - }, - result, - ) - } -} diff --git a/rpc-toolkit/src/handler/adapters.rs b/rpc-toolkit/src/handler/adapters.rs new file mode 100644 index 0000000..0eca646 --- /dev/null +++ b/rpc-toolkit/src/handler/adapters.rs @@ -0,0 +1,485 @@ +use std::any::TypeId; +use std::collections::VecDeque; +use std::fmt::Debug; +use std::marker::PhantomData; +use std::sync::Arc; +use std::task::Context; + +use clap::{CommandFactory, FromArgMatches}; +use imbl_value::imbl::{OrdMap, OrdSet}; +use imbl_value::Value; +use serde::de::DeserializeOwned; +use serde::Serialize; +use yajrc::RpcError; + +use crate::util::{internal_error, parse_error, Flat}; +use crate::{ + intersect_type_ids, iter_from_ctx_and_handler, AnyHandler, CallRemote, CliBindings, DynHandler, + HandleArgs, Handler, HandlerTypes, IntoContext, IntoHandlers, NoParams, PrintCliResult, +}; + +pub trait HandlerExt: HandlerTypes + Sized { + fn no_cli(self) -> NoCli; + fn with_custom_display

(self, display: P) -> CustomDisplay + where + P: PrintCliResult< + Params = Self::Params, + InheritedParams = Self::InheritedParams, + Ok = Self::Ok, + Err = Self::Err, + >; + fn with_custom_display_fn( + self, + display: F, + ) -> CustomDisplayFn + where + F: Fn(HandleArgs, Self::Ok) -> Result<(), Self::Err>; +} + +impl HandlerExt for T { + fn no_cli(self) -> NoCli { + NoCli(self) + } + fn with_custom_display

(self, display: P) -> CustomDisplay + where + P: PrintCliResult< + Params = Self::Params, + InheritedParams = Self::InheritedParams, + Ok = Self::Ok, + Err = Self::Err, + >, + { + CustomDisplay { + print: display, + handler: self, + } + } + fn with_custom_display_fn( + self, + display: F, + ) -> CustomDisplayFn + where + F: Fn(HandleArgs, Self::Ok) -> Result<(), Self::Err>, + { + CustomDisplayFn { + _phantom: PhantomData, + print: display, + handler: self, + } + } +} + +#[derive(Debug, Clone)] +pub struct NoCli(pub H); +impl HandlerTypes for NoCli { + type Params = H::Params; + type InheritedParams = H::InheritedParams; + type Ok = H::Ok; + type Err = H::Err; +} + +#[derive(Clone, Debug)] +pub struct CustomDisplay { + print: P, + handler: H, +} +impl HandlerTypes for CustomDisplay +where + H: HandlerTypes, +{ + type Params = H::Params; + type InheritedParams = H::InheritedParams; + type Ok = H::Ok; + type Err = H::Err; +} +#[async_trait::async_trait] +impl Handler for CustomDisplay +where + H: Handler, + P: Send + Sync + Clone + Debug + 'static, +{ + type Context = H::Context; + fn handle_sync( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + ) -> Result { + self.handler.handle_sync(HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }) + } + async fn handle_async( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + ) -> Result { + self.handler + .handle_async(HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }) + .await + } + fn metadata( + &self, + method: VecDeque<&'static str>, + ctx_ty: TypeId, + ) -> OrdMap<&'static str, Value> { + self.handler.metadata(method, ctx_ty) + } + fn contexts(&self) -> Option> { + self.handler.contexts() + } + fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { + self.handler.method_from_dots(method, ctx_ty) + } +} +impl CliBindings for CustomDisplay +where + H: HandlerTypes, + H::Params: FromArgMatches + CommandFactory + Serialize, + P: PrintCliResult< + Params = H::Params, + InheritedParams = H::InheritedParams, + Ok = H::Ok, + Err = H::Err, + > + Send + + Sync + + Clone + + Debug + + 'static, +{ + type Context = P::Context; + fn cli_command(&self, ctx_ty: TypeId) -> clap::Command { + H::Params::command() + } + fn cli_parse( + &self, + matches: &clap::ArgMatches, + ctx_ty: TypeId, + ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { + Self::Params::from_arg_matches(matches).and_then(|a| { + Ok(( + VecDeque::new(), + imbl_value::to_value(&a) + .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?, + )) + }) + } + fn cli_display( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + result: Self::Ok, + ) -> Result<(), Self::Err> { + self.print.print( + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }, + result, + ) + } +} +impl IntoHandlers for CustomDisplay +where + Self: HandlerTypes + Handler + CliBindings, + ::Params: DeserializeOwned, + ::InheritedParams: DeserializeOwned, + ::Ok: Serialize + DeserializeOwned, + RpcError: From<::Err>, +{ + fn into_handlers(self) -> impl IntoIterator, crate::DynHandler)> { + iter_from_ctx_and_handler( + intersect_type_ids(self.contexts(), ::Context::type_ids()), + DynHandler::WithCli(Arc::new(AnyHandler::new(self))), + ) + } +} + +pub struct CustomDisplayFn { + _phantom: PhantomData, + print: F, + handler: H, +} +impl Clone for CustomDisplayFn { + fn clone(&self) -> Self { + Self { + _phantom: PhantomData, + print: self.print.clone(), + handler: self.handler.clone(), + } + } +} +impl Debug for CustomDisplayFn { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("CustomDisplayFn") + .field("print", &self.print) + .field("handler", &self.handler) + .finish() + } +} +impl HandlerTypes for CustomDisplayFn +where + H: HandlerTypes, +{ + type Params = H::Params; + type InheritedParams = H::InheritedParams; + type Ok = H::Ok; + type Err = H::Err; +} +#[async_trait::async_trait] +impl Handler for CustomDisplayFn +where + Context: Send + Sync + 'static, + H: Handler, + F: Send + Sync + Clone + Debug + 'static, +{ + type Context = H::Context; + fn handle_sync( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + ) -> Result { + self.handler.handle_sync(HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }) + } + async fn handle_async( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + ) -> Result { + self.handler + .handle_async(HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }) + .await + } + fn metadata( + &self, + method: VecDeque<&'static str>, + ctx_ty: TypeId, + ) -> OrdMap<&'static str, Value> { + self.handler.metadata(method, ctx_ty) + } + fn contexts(&self) -> Option> { + self.handler.contexts() + } + fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { + self.handler.method_from_dots(method, ctx_ty) + } +} +impl CliBindings for CustomDisplayFn +where + Context: IntoContext, + H: CliBindings, + F: Fn(HandleArgs, H::Ok) -> Result<(), H::Err> + + Send + + Sync + + Clone + + Debug + + 'static, +{ + type Context = Context; + fn cli_command(&self, ctx_ty: TypeId) -> clap::Command { + self.handler.cli_command(ctx_ty) + } + fn cli_parse( + &self, + matches: &clap::ArgMatches, + ctx_ty: TypeId, + ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { + self.handler.cli_parse(matches, ctx_ty) + } + fn cli_display( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + result: Self::Ok, + ) -> Result<(), Self::Err> { + (self.print)( + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }, + result, + ) + } +} + +// pub struct RemoteCli { +// _phantom: PhantomData<(CliContext, RemoteContext)>, +// handler: H, +// } +// impl Clone for RemoteCli { +// fn clone(&self) -> Self { +// Self { +// _phantom: PhantomData, +// handler: self.handler.clone(), +// } +// } +// } +// impl Debug for RemoteCli { +// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +// f.debug_tuple("RemoteCli").field(&self.handler).finish() +// } +// } +// impl HandlerTypes for RemoteCli +// where +// H: HandlerTypes, +// { +// type Params = H::Params; +// type InheritedParams = H::InheritedParams; +// type Ok = H::Ok; +// type Err = H::Err; +// } +// #[async_trait::async_trait] +// impl Handler> +// for RemoteCli +// where +// CliContext: CallRemote, +// H: Handler, +// { +// async fn handle_async( +// &self, +// HandleArgs { +// context, +// parent_method, +// method, +// params, +// inherited_params, +// raw_params, +// }: HandleArgs, +// ) -> Result { +// let full_method = parent_method.into_iter().chain(method).collect::>(); +// match context +// .call_remote( +// &full_method.join("."), +// imbl_value::to_value(&Flat(params, inherited_params)).map_err(parse_error)?, +// ) +// .await +// { +// Ok(a) => imbl_value::from_value(a) +// .map_err(internal_error) +// .map_err(Self::Err::from), +// Err(e) => Err(Self::Err::from(e)), +// } +// } +// fn metadata( +// &self, +// method: VecDeque<&'static str>, +// ctx_ty: TypeId, +// ) -> OrdMap<&'static str, Value> { +// self.handler.metadata(method, ctx_ty) +// } +// fn contexts(&self) -> Option> { +// todo!() +// } +// fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { +// self.handler.method_from_dots(method, ctx_ty) +// } +// } +// impl CliBindings for RemoteCli +// where +// Context: crate::Context, +// H: CliBindings, +// { +// fn cli_command(&self, ctx_ty: TypeId) -> clap::Command { +// self.handler.cli_command(ctx_ty) +// } +// fn cli_parse( +// &self, +// matches: &clap::ArgMatches, +// ctx_ty: TypeId, +// ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { +// self.handler.cli_parse(matches, ctx_ty) +// } +// fn cli_display( +// &self, +// HandleArgs { +// context, +// parent_method, +// method, +// params, +// inherited_params, +// raw_params, +// }: HandleArgs, +// result: Self::Ok, +// ) -> Result<(), Self::Err> { +// self.handler.cli_display( +// HandleArgs { +// context, +// parent_method, +// method, +// params, +// inherited_params, +// raw_params, +// }, +// result, +// ) +// } +// } diff --git a/rpc-toolkit/src/handler/from_fn.rs b/rpc-toolkit/src/handler/from_fn.rs new file mode 100644 index 0000000..fa06850 --- /dev/null +++ b/rpc-toolkit/src/handler/from_fn.rs @@ -0,0 +1,601 @@ +use std::any::TypeId; +use std::collections::VecDeque; +use std::fmt::Display; +use std::marker::PhantomData; +use std::sync::Arc; + +use clap::{ArgMatches, Command, CommandFactory, FromArgMatches}; +use futures::Future; +use imbl_value::imbl::OrdMap; +use imbl_value::Value; +use serde::de::DeserializeOwned; +use serde::Serialize; +use yajrc::RpcError; + +use crate::marker::LeafHandler; +use crate::{ + intersect_type_ids, iter_from_ctx_and_handler, AnyContext, AnyHandler, CliBindings, DynHandler, + HandleArgs, Handler, HandlerTypes, IntoContext, IntoHandlers, NoCli, NoParams, PrintCliResult, +}; + +pub struct FromFn { + _phantom: PhantomData<(T, E, Args)>, + function: F, + blocking: bool, + metadata: OrdMap<&'static str, Value>, +} +impl FromFn { + pub fn with_metadata(mut self, key: &'static str, value: Value) -> Self { + self.metadata.insert(key, value); + self + } +} +impl Clone for FromFn { + fn clone(&self) -> Self { + Self { + _phantom: PhantomData, + function: self.function.clone(), + blocking: self.blocking, + metadata: self.metadata.clone(), + } + } +} +impl std::fmt::Debug for FromFn { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("FromFn") + .field("blocking", &self.blocking) + .finish() + } +} +impl LeafHandler for FromFn {} +impl PrintCliResult for FromFn +where + Self: HandlerTypes, + ::Ok: Display, +{ + type Context = AnyContext; + fn print(&self, _: HandleArgs, result: Self::Ok) -> Result<(), Self::Err> { + Ok(println!("{result}")) + } +} +impl IntoHandlers for FromFn +where + Self: HandlerTypes + Handler + CliBindings, + ::Params: DeserializeOwned, + ::InheritedParams: DeserializeOwned, + ::Ok: Serialize + DeserializeOwned, + RpcError: From<::Err>, +{ + fn into_handlers(self) -> impl IntoIterator, crate::DynHandler)> { + iter_from_ctx_and_handler( + intersect_type_ids(self.contexts(), ::Context::type_ids()), + DynHandler::WithCli(Arc::new(AnyHandler::new(self))), + ) + } +} +impl IntoHandlers for NoCli> +where + Self: HandlerTypes + Handler, + ::Params: DeserializeOwned, + ::InheritedParams: DeserializeOwned, + ::Ok: Serialize + DeserializeOwned, + RpcError: From<::Err>, +{ + fn into_handlers(self) -> impl IntoIterator, crate::DynHandler)> { + iter_from_ctx_and_handler( + self.contexts(), + DynHandler::WithoutCli(Arc::new(AnyHandler::new(self))), + ) + } +} + +pub fn from_fn(function: F) -> FromFn { + FromFn { + function, + _phantom: PhantomData, + blocking: false, + metadata: OrdMap::new(), + } +} + +pub fn from_fn_blocking(function: F) -> FromFn { + FromFn { + function, + _phantom: PhantomData, + blocking: true, + metadata: OrdMap::new(), + } +} + +pub struct FromFnAsync { + _phantom: PhantomData<(Fut, T, E, Args)>, + function: F, + metadata: OrdMap<&'static str, Value>, +} +impl Clone for FromFnAsync { + fn clone(&self) -> Self { + Self { + _phantom: PhantomData, + function: self.function.clone(), + metadata: self.metadata.clone(), + } + } +} +impl std::fmt::Debug for FromFnAsync { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("FromFnAsync").finish() + } +} +impl PrintCliResult for FromFnAsync +where + Self: HandlerTypes, + ::Ok: Display, +{ + type Context = AnyContext; + fn print(&self, _: HandleArgs, result: Self::Ok) -> Result<(), Self::Err> { + Ok(println!("{result}")) + } +} +impl IntoHandlers for FromFnAsync +where + Self: HandlerTypes + Handler + CliBindings, + ::Params: DeserializeOwned, + ::InheritedParams: DeserializeOwned, + ::Ok: Serialize + DeserializeOwned, + RpcError: From<::Err>, +{ + fn into_handlers(self) -> impl IntoIterator, crate::DynHandler)> { + iter_from_ctx_and_handler( + intersect_type_ids(self.contexts(), ::Context::type_ids()), + DynHandler::WithCli(Arc::new(AnyHandler::new(self))), + ) + } +} +impl IntoHandlers for NoCli> +where + Self: HandlerTypes + Handler, + ::Params: DeserializeOwned, + ::InheritedParams: DeserializeOwned, + ::Ok: Serialize + DeserializeOwned, + RpcError: From<::Err>, +{ + fn into_handlers(self) -> impl IntoIterator, crate::DynHandler)> { + iter_from_ctx_and_handler( + self.contexts(), + DynHandler::WithoutCli(Arc::new(AnyHandler::new(self))), + ) + } +} + +pub fn from_fn_async(function: F) -> FromFnAsync { + FromFnAsync { + function, + _phantom: PhantomData, + metadata: OrdMap::new(), + } +} + +impl HandlerTypes for FromFn +where + F: Fn() -> Result + Send + Sync + Clone + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Params = NoParams; + type InheritedParams = NoParams; + type Ok = T; + type Err = E; +} +#[async_trait::async_trait] +impl Handler for FromFn +where + F: Fn() -> Result + Send + Sync + Clone + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Context = AnyContext; + fn handle_sync(&self, _: HandleArgs) -> Result { + (self.function)() + } + async fn handle_async( + &self, + handle_args: HandleArgs, + ) -> Result { + if self.blocking { + self.handle_async_with_sync_blocking(handle_args).await + } else { + self.handle_async_with_sync(handle_args).await + } + } + fn metadata(&self, _: VecDeque<&'static str>, _: TypeId) -> OrdMap<&'static str, Value> { + self.metadata.clone() + } +} +impl HandlerTypes for FromFnAsync +where + F: Fn() -> Fut + Send + Sync + Clone + 'static, + Fut: Future> + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Params = NoParams; + type InheritedParams = NoParams; + type Ok = T; + type Err = E; +} +#[async_trait::async_trait] +impl Handler for FromFnAsync +where + F: Fn() -> Fut + Send + Sync + Clone + 'static, + Fut: Future> + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Context = AnyContext; + async fn handle_async( + &self, + _: HandleArgs, + ) -> Result { + (self.function)().await + } + fn metadata(&self, _: VecDeque<&'static str>, _: TypeId) -> OrdMap<&'static str, Value> { + self.metadata.clone() + } +} + +impl HandlerTypes for FromFn +where + Context: IntoContext, + F: Fn(Context) -> Result + Send + Sync + Clone + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Params = NoParams; + type InheritedParams = NoParams; + type Ok = T; + type Err = E; +} +#[async_trait::async_trait] +impl Handler for FromFn +where + Context: IntoContext, + F: Fn(Context) -> Result + Send + Sync + Clone + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Context = Context; + fn handle_sync( + &self, + handle_args: HandleArgs, + ) -> Result { + (self.function)(handle_args.context) + } + async fn handle_async( + &self, + handle_args: HandleArgs, + ) -> Result { + if self.blocking { + self.handle_async_with_sync_blocking(handle_args).await + } else { + self.handle_async_with_sync(handle_args).await + } + } + fn metadata(&self, _: VecDeque<&'static str>, _: TypeId) -> OrdMap<&'static str, Value> { + self.metadata.clone() + } +} +impl HandlerTypes for FromFnAsync +where + Context: IntoContext, + F: Fn(Context) -> Fut + Send + Sync + Clone + 'static, + Fut: Future> + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Params = NoParams; + type InheritedParams = NoParams; + type Ok = T; + type Err = E; +} +#[async_trait::async_trait] +impl Handler for FromFnAsync +where + Context: IntoContext, + F: Fn(Context) -> Fut + Send + Sync + Clone + 'static, + Fut: Future> + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Context = Context; + async fn handle_async( + &self, + handle_args: HandleArgs, + ) -> Result { + (self.function)(handle_args.context).await + } + fn metadata(&self, _: VecDeque<&'static str>, _: TypeId) -> OrdMap<&'static str, Value> { + self.metadata.clone() + } +} + +impl HandlerTypes for FromFn +where + Context: IntoContext, + F: Fn(Context, Params) -> Result + Send + Sync + Clone + 'static, + Params: DeserializeOwned + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Params = Params; + type InheritedParams = NoParams; + type Ok = T; + type Err = E; +} +#[async_trait::async_trait] +impl Handler for FromFn +where + Context: IntoContext, + F: Fn(Context, Params) -> Result + Send + Sync + Clone + 'static, + Params: DeserializeOwned + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Context = Context; + fn handle_sync( + &self, + handle_args: HandleArgs, + ) -> Result { + let HandleArgs { + context, params, .. + } = handle_args; + (self.function)(context, params) + } + async fn handle_async( + &self, + handle_args: HandleArgs, + ) -> Result { + if self.blocking { + self.handle_async_with_sync_blocking(handle_args).await + } else { + self.handle_async_with_sync(handle_args).await + } + } + fn metadata(&self, _: VecDeque<&'static str>, _: TypeId) -> OrdMap<&'static str, Value> { + self.metadata.clone() + } +} +impl HandlerTypes for FromFnAsync +where + Context: IntoContext, + F: Fn(Context, Params) -> Fut + Send + Sync + Clone + 'static, + Fut: Future> + Send + Sync + 'static, + Params: DeserializeOwned + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Params = Params; + type InheritedParams = NoParams; + type Ok = T; + type Err = E; +} +#[async_trait::async_trait] +impl Handler for FromFnAsync +where + Context: IntoContext, + F: Fn(Context, Params) -> Fut + Send + Sync + Clone + 'static, + Fut: Future> + Send + Sync + 'static, + Params: DeserializeOwned + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Context = Context; + async fn handle_async( + &self, + handle_args: HandleArgs, + ) -> Result { + let HandleArgs { + context, params, .. + } = handle_args; + (self.function)(context, params).await + } + fn metadata(&self, _: VecDeque<&'static str>, _: TypeId) -> OrdMap<&'static str, Value> { + self.metadata.clone() + } +} + +impl HandlerTypes + for FromFn +where + Context: IntoContext, + F: Fn(Context, Params, InheritedParams) -> Result + Send + Sync + Clone + 'static, + Params: DeserializeOwned + Send + Sync + 'static, + InheritedParams: DeserializeOwned + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Params = Params; + type InheritedParams = InheritedParams; + type Ok = T; + type Err = E; +} +#[async_trait::async_trait] +impl Handler + for FromFn +where + Context: IntoContext, + F: Fn(Context, Params, InheritedParams) -> Result + Send + Sync + Clone + 'static, + Params: DeserializeOwned + Send + Sync + 'static, + InheritedParams: DeserializeOwned + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Context = Context; + fn handle_sync( + &self, + handle_args: HandleArgs, + ) -> Result { + let HandleArgs { + context, + params, + inherited_params, + .. + } = handle_args; + (self.function)(context, params, inherited_params) + } + async fn handle_async( + &self, + handle_args: HandleArgs, + ) -> Result { + if self.blocking { + self.handle_async_with_sync_blocking(handle_args).await + } else { + self.handle_async_with_sync(handle_args).await + } + } + fn metadata(&self, _: VecDeque<&'static str>, _: TypeId) -> OrdMap<&'static str, Value> { + self.metadata.clone() + } +} +impl HandlerTypes + for FromFnAsync +where + Context: IntoContext, + F: Fn(Context, Params, InheritedParams) -> Fut + Send + Sync + Clone + 'static, + Fut: Future> + Send + Sync + 'static, + Params: DeserializeOwned + Send + Sync + 'static, + InheritedParams: DeserializeOwned + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Params = Params; + type InheritedParams = InheritedParams; + type Ok = T; + type Err = E; +} +#[async_trait::async_trait] +impl Handler + for FromFnAsync +where + Context: IntoContext, + F: Fn(Context, Params, InheritedParams) -> Fut + Send + Sync + Clone + 'static, + Fut: Future> + Send + Sync + 'static, + Params: DeserializeOwned + Send + Sync + 'static, + InheritedParams: DeserializeOwned + Send + Sync + 'static, + T: Send + Sync + 'static, + E: Send + Sync + 'static, +{ + type Context = Context; + async fn handle_async( + &self, + handle_args: HandleArgs, + ) -> Result { + let HandleArgs { + context, + params, + inherited_params, + .. + } = handle_args; + (self.function)(context, params, inherited_params).await + } + fn metadata(&self, _: VecDeque<&'static str>, _: TypeId) -> OrdMap<&'static str, Value> { + self.metadata.clone() + } +} + +impl CliBindings for FromFn +where + Self: HandlerTypes, + Self::Params: FromArgMatches + CommandFactory + Serialize, + Self: PrintCliResult, +{ + type Context = ::Context; + fn cli_command(&self, _: TypeId) -> Command { + Self::Params::command() + } + fn cli_parse( + &self, + matches: &ArgMatches, + _: TypeId, + ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { + Self::Params::from_arg_matches(matches).and_then(|a| { + Ok(( + VecDeque::new(), + imbl_value::to_value(&a) + .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?, + )) + }) + } + fn cli_display( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + result: Self::Ok, + ) -> Result<(), Self::Err> { + self.print( + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }, + result, + ) + } +} + +impl CliBindings for FromFnAsync +where + Self: HandlerTypes, + Self::Params: FromArgMatches + CommandFactory + Serialize, + Self: PrintCliResult, +{ + type Context = ::Context; + fn cli_command(&self, _: TypeId) -> Command { + Self::Params::command() + } + fn cli_parse( + &self, + matches: &ArgMatches, + _: TypeId, + ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { + Self::Params::from_arg_matches(matches).and_then(|a| { + Ok(( + VecDeque::new(), + imbl_value::to_value(&a) + .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?, + )) + }) + } + fn cli_display( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + result: Self::Ok, + ) -> Result<(), Self::Err> { + self.print( + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }, + result, + ) + } +} diff --git a/rpc-toolkit/src/handler/marker.rs b/rpc-toolkit/src/handler/marker.rs new file mode 100644 index 0000000..32a0f18 --- /dev/null +++ b/rpc-toolkit/src/handler/marker.rs @@ -0,0 +1 @@ +pub trait LeafHandler {} diff --git a/rpc-toolkit/src/handler/mod.rs b/rpc-toolkit/src/handler/mod.rs new file mode 100644 index 0000000..d859c7c --- /dev/null +++ b/rpc-toolkit/src/handler/mod.rs @@ -0,0 +1,317 @@ +use std::any::TypeId; +use std::collections::VecDeque; +use std::ops::Deref; +use std::sync::Arc; + +use clap::{ArgMatches, Command, Parser}; +use imbl_value::imbl::{OrdMap, OrdSet}; +use imbl_value::Value; +use serde::de::DeserializeOwned; +use serde::{Deserialize, Serialize}; +use yajrc::RpcError; + +use crate::context::{AnyContext, IntoContext}; +use crate::util::{internal_error, invalid_params}; + +pub mod adapters; +pub mod from_fn; +pub mod marker; +pub mod parent; + +pub use adapters::*; +pub use from_fn::*; +pub use parent::*; + +pub(crate) struct HandleAnyArgs { + pub(crate) context: AnyContext, + pub(crate) parent_method: VecDeque<&'static str>, + pub(crate) method: VecDeque<&'static str>, + pub(crate) params: Value, +} +impl HandleAnyArgs { + fn downcast(self) -> Result, imbl_value::Error> + where + H: HandlerTypes, + H::Params: DeserializeOwned, + H::InheritedParams: DeserializeOwned, + { + let Self { + context, + parent_method, + method, + params, + } = self; + Ok(HandleArgs { + context: Context::downcast(context).map_err(|_| imbl_value::Error { + kind: imbl_value::ErrorKind::Deserialization, + source: serde::ser::Error::custom("context does not match expected"), + })?, + parent_method, + method, + params: imbl_value::from_value(params.clone())?, + inherited_params: imbl_value::from_value(params.clone())?, + raw_params: params, + }) + } +} + +#[async_trait::async_trait] +pub(crate) trait HandleAny: std::fmt::Debug + Send + Sync { + fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result; + async fn handle_async(&self, handle_args: HandleAnyArgs) -> Result; + fn metadata( + &self, + method: VecDeque<&'static str>, + ctx_ty: TypeId, + ) -> OrdMap<&'static str, Value>; + fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option>; +} +#[async_trait::async_trait] +impl HandleAny for Arc { + fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result { + self.deref().handle_sync(handle_args) + } + async fn handle_async(&self, handle_args: HandleAnyArgs) -> Result { + self.deref().handle_async(handle_args).await + } + fn metadata( + &self, + method: VecDeque<&'static str>, + ctx_ty: TypeId, + ) -> OrdMap<&'static str, Value> { + self.deref().metadata(method, ctx_ty) + } + fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { + self.deref().method_from_dots(method, ctx_ty) + } +} + +pub(crate) trait CliBindingsAny { + fn cli_command(&self, ctx_ty: TypeId) -> Command; + fn cli_parse( + &self, + matches: &ArgMatches, + ctx_ty: TypeId, + ) -> Result<(VecDeque<&'static str>, Value), clap::Error>; + fn cli_display(&self, handle_args: HandleAnyArgs, result: Value) -> Result<(), RpcError>; +} + +pub trait CliBindings: HandlerTypes { + type Context: IntoContext; + fn cli_command(&self, ctx_ty: TypeId) -> Command; + fn cli_parse( + &self, + matches: &ArgMatches, + ctx_ty: TypeId, + ) -> Result<(VecDeque<&'static str>, Value), clap::Error>; + fn cli_display( + &self, + handle_args: HandleArgs, + result: Self::Ok, + ) -> Result<(), Self::Err>; +} + +pub trait PrintCliResult: HandlerTypes { + type Context: IntoContext; + fn print( + &self, + handle_args: HandleArgs, + result: Self::Ok, + ) -> Result<(), Self::Err>; +} + +pub(crate) trait HandleAnyWithCli: HandleAny + CliBindingsAny {} +impl HandleAnyWithCli for T {} + +#[derive(Debug, Clone)] +#[allow(private_interfaces)] +pub enum DynHandler { + WithoutCli(Arc), + WithCli(Arc), +} +#[async_trait::async_trait] +impl HandleAny for DynHandler { + fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result { + match self { + DynHandler::WithoutCli(h) => h.handle_sync(handle_args), + DynHandler::WithCli(h) => h.handle_sync(handle_args), + } + } + async fn handle_async(&self, handle_args: HandleAnyArgs) -> Result { + match self { + DynHandler::WithoutCli(h) => h.handle_async(handle_args).await, + DynHandler::WithCli(h) => h.handle_async(handle_args).await, + } + } + fn metadata( + &self, + method: VecDeque<&'static str>, + ctx_ty: TypeId, + ) -> OrdMap<&'static str, Value> { + match self { + DynHandler::WithoutCli(h) => h.metadata(method, ctx_ty), + DynHandler::WithCli(h) => h.metadata(method, ctx_ty), + } + } + fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { + match self { + DynHandler::WithoutCli(h) => h.method_from_dots(method, ctx_ty), + DynHandler::WithCli(h) => h.method_from_dots(method, ctx_ty), + } + } +} + +#[derive(Debug, Clone)] +pub struct HandleArgs { + pub context: Context, + pub parent_method: VecDeque<&'static str>, + pub method: VecDeque<&'static str>, + pub params: H::Params, + pub inherited_params: H::InheritedParams, + pub raw_params: Value, +} + +pub trait HandlerTypes { + type Params: Send + Sync; + type InheritedParams: Send + Sync; + type Ok: Send + Sync; + type Err: Send + Sync; +} + +#[async_trait::async_trait] +pub trait Handler: HandlerTypes + std::fmt::Debug + Clone + Send + Sync + 'static { + type Context: IntoContext; + fn handle_sync( + &self, + handle_args: HandleArgs, + ) -> Result { + handle_args + .context + .runtime() + .block_on(self.handle_async(handle_args)) + } + async fn handle_async( + &self, + handle_args: HandleArgs, + ) -> Result; + async fn handle_async_with_sync( + &self, + handle_args: HandleArgs, + ) -> Result { + self.handle_sync(handle_args) + } + async fn handle_async_with_sync_blocking( + &self, + handle_args: HandleArgs, + ) -> Result { + let s = self.clone(); + handle_args + .context + .runtime() + .spawn_blocking(move || s.handle_sync(handle_args)) + .await + .unwrap() + } + #[allow(unused_variables)] + fn metadata( + &self, + method: VecDeque<&'static str>, + ctx_ty: TypeId, + ) -> OrdMap<&'static str, Value> { + OrdMap::new() + } + fn contexts(&self) -> Option> { + Self::Context::type_ids() + } + #[allow(unused_variables)] + fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { + if method.is_empty() { + Some(VecDeque::new()) + } else { + None + } + } +} + +pub(crate) struct AnyHandler(H); +impl AnyHandler { + pub(crate) fn new(handler: H) -> Self { + Self(handler) + } +} +impl std::fmt::Debug for AnyHandler { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("AnyHandler").field(&self.0).finish() + } +} + +#[async_trait::async_trait] +impl HandleAny for AnyHandler +where + H::Params: DeserializeOwned, + H::InheritedParams: DeserializeOwned, + H::Ok: Serialize, + RpcError: From, +{ + fn handle_sync(&self, handle_args: HandleAnyArgs) -> Result { + imbl_value::to_value( + &self + .0 + .handle_sync(handle_args.downcast().map_err(invalid_params)?)?, + ) + .map_err(internal_error) + } + async fn handle_async(&self, handle_args: HandleAnyArgs) -> Result { + imbl_value::to_value( + &self + .0 + .handle_async(handle_args.downcast().map_err(invalid_params)?) + .await?, + ) + .map_err(internal_error) + } + fn metadata( + &self, + method: VecDeque<&'static str>, + ctx_ty: TypeId, + ) -> OrdMap<&'static str, Value> { + self.0.metadata(method, ctx_ty) + } + fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { + self.0.method_from_dots(method, ctx_ty) + } +} + +impl CliBindingsAny for AnyHandler +where + H: CliBindings, + H::Params: DeserializeOwned, + H::InheritedParams: DeserializeOwned, + H::Ok: Serialize + DeserializeOwned, + RpcError: From, +{ + fn cli_command(&self, ctx_ty: TypeId) -> Command { + self.0.cli_command(ctx_ty) + } + fn cli_parse( + &self, + matches: &ArgMatches, + ctx_ty: TypeId, + ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { + self.0.cli_parse(matches, ctx_ty) + } + fn cli_display(&self, handle_args: HandleAnyArgs, result: Value) -> Result<(), RpcError> { + self.0 + .cli_display( + handle_args.downcast().map_err(invalid_params)?, + imbl_value::from_value(result).map_err(internal_error)?, + ) + .map_err(RpcError::from) + } +} + +#[derive(Debug, Clone, Copy, Deserialize, Serialize, Parser)] +pub struct NoParams {} + +#[derive(Debug, Clone, Copy, Deserialize, Serialize, Parser)] +pub enum Never {} diff --git a/rpc-toolkit/src/handler/parent.rs b/rpc-toolkit/src/handler/parent.rs new file mode 100644 index 0000000..998f6d6 --- /dev/null +++ b/rpc-toolkit/src/handler/parent.rs @@ -0,0 +1,520 @@ +use std::any::TypeId; +use std::collections::VecDeque; +use std::marker::PhantomData; +use std::sync::Arc; + +use clap::{ArgMatches, Command, CommandFactory, FromArgMatches}; +use imbl_value::imbl::{OrdMap, OrdSet}; +use imbl_value::Value; +use serde::de::DeserializeOwned; +use serde::Serialize; +use yajrc::RpcError; + +use crate::util::{combine, Flat}; +use crate::{ + AnyContext, AnyHandler, CliBindings, DynHandler, HandleAny, HandleAnyArgs, HandleArgs, Handler, + HandlerTypes, IntoContext, NoCli, NoParams, +}; + +pub trait IntoHandlers: HandlerTypes { + fn into_handlers(self) -> impl IntoIterator, DynHandler)>; +} + +impl IntoHandlers for H { + fn into_handlers(self) -> impl IntoIterator, DynHandler)> { + iter_from_ctx_and_handler( + intersect_type_ids(self.contexts(), ::Context::type_ids()), + DynHandler::WithCli(Arc::new(AnyHandler::new(self))), + ) + } +} + +pub(crate) fn iter_from_ctx_and_handler( + ctx: Option>, + handler: DynHandler, +) -> impl IntoIterator, DynHandler)> { + if let Some(ctx) = ctx { + itertools::Either::Left(ctx.into_iter().map(Some)) + } else { + itertools::Either::Right(std::iter::once(None)) + } + .map(move |ctx| (ctx, handler.clone())) +} + +pub(crate) fn intersect_type_ids( + a: Option>, + b: Option>, +) -> Option> { + match (a, b) { + (None, None) => None, + (Some(a), None) => Some(a), + (None, Some(b)) => Some(b), + (Some(a), Some(b)) => Some(a.intersection(b)), + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub(crate) struct Name(pub(crate) Option<&'static str>); +impl<'a> std::borrow::Borrow> for Name { + fn borrow(&self) -> &Option<&'a str> { + &self.0 + } +} + +#[derive(Debug, Clone)] +pub(crate) struct SubcommandMap(pub(crate) OrdMap, DynHandler>>); +impl SubcommandMap { + fn insert( + &mut self, + name: Option<&'static str>, + handlers: impl IntoIterator, DynHandler)>, + ) { + let mut for_name = self.0.remove(&name).unwrap_or_default(); + for (ctx_ty, handler) in handlers { + for_name.insert(ctx_ty, handler); + } + self.0.insert(Name(name), for_name); + } + + fn get<'a>(&'a self, ctx_ty: TypeId, name: Option<&str>) -> Option<(Name, &'a DynHandler)> { + if let Some((name, for_name)) = self.0.get_key_value(&name) { + if let Some(for_ctx) = for_name.get(&Some(ctx_ty)) { + Some((*name, for_ctx)) + } else { + for_name.get(&None).map(|h| (*name, h)) + } + } else { + None + } + } +} + +pub struct ParentHandler { + _phantom: PhantomData<(Params, InheritedParams)>, + pub(crate) subcommands: SubcommandMap, + metadata: OrdMap<&'static str, Value>, +} +impl ParentHandler { + pub fn new() -> Self { + Self { + _phantom: PhantomData, + subcommands: SubcommandMap(OrdMap::new()), + metadata: OrdMap::new(), + } + } + pub fn with_metadata(mut self, key: &'static str, value: Value) -> Self { + self.metadata.insert(key, value); + self + } +} +impl Clone for ParentHandler { + fn clone(&self) -> Self { + Self { + _phantom: PhantomData, + subcommands: self.subcommands.clone(), + metadata: self.metadata.clone(), + } + } +} +impl std::fmt::Debug for ParentHandler { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("ParentHandler") + .field(&self.subcommands) + .finish() + } +} + +struct InheritanceHandler { + _phantom: PhantomData<(Params, InheritedParams)>, + handler: H, + inherit: F, +} +impl Clone + for InheritanceHandler +{ + fn clone(&self) -> Self { + Self { + _phantom: PhantomData, + handler: self.handler.clone(), + inherit: self.inherit.clone(), + } + } +} +impl std::fmt::Debug + for InheritanceHandler +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("InheritanceHandler") + .field(&self.handler) + .finish() + } +} +impl HandlerTypes + for InheritanceHandler +where + H: HandlerTypes, + Params: Send + Sync, + InheritedParams: Send + Sync, +{ + type Params = H::Params; + type InheritedParams = Flat; + type Ok = H::Ok; + type Err = H::Err; +} +#[async_trait::async_trait] +impl Handler for InheritanceHandler +where + Params: Send + Sync + 'static, + InheritedParams: Send + Sync + 'static, + H: Handler, + F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, +{ + type Context = H::Context; + fn handle_sync( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + ) -> Result { + self.handler.handle_sync(HandleArgs { + context, + parent_method, + method, + params, + inherited_params: (self.inherit)(inherited_params.0, inherited_params.1), + raw_params, + }) + } + async fn handle_async( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + ) -> Result { + self.handler.handle_sync(HandleArgs { + context, + parent_method, + method, + params, + inherited_params: (self.inherit)(inherited_params.0, inherited_params.1), + raw_params, + }) + } + fn metadata( + &self, + method: VecDeque<&'static str>, + ctx_ty: TypeId, + ) -> OrdMap<&'static str, Value> { + self.handler.metadata(method, ctx_ty) + } + fn contexts(&self) -> Option> { + self.handler.contexts() + } + fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { + self.handler.method_from_dots(method, ctx_ty) + } +} + +impl CliBindings + for InheritanceHandler +where + Params: Send + Sync + 'static, + InheritedParams: Send + Sync + 'static, + H: CliBindings, + F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, +{ + type Context = H::Context; + fn cli_command(&self, ctx_ty: TypeId) -> Command { + self.handler.cli_command(ctx_ty) + } + fn cli_parse( + &self, + matches: &ArgMatches, + ctx_ty: TypeId, + ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { + self.handler.cli_parse(matches, ctx_ty) + } + fn cli_display( + &self, + HandleArgs { + context, + parent_method, + method, + params, + inherited_params, + raw_params, + }: HandleArgs, + result: Self::Ok, + ) -> Result<(), Self::Err> { + self.handler.cli_display( + HandleArgs { + context, + parent_method, + method, + params, + inherited_params: (self.inherit)(inherited_params.0, inherited_params.1), + raw_params, + }, + result, + ) + } +} + +impl ParentHandler { + fn get_contexts(&self) -> Option> { + let mut set = OrdSet::new(); + for ctx_ty in self.subcommands.0.values().flat_map(|c| c.keys()) { + set.insert((*ctx_ty)?); + } + Some(set) + } + pub fn subcommand(mut self, name: &'static str, handler: H) -> Self + where + H: IntoHandlers>, + { + self.subcommands + .insert(name.into(), handler.into_handlers()); + self + } + pub fn root_handler(mut self, handler: H) -> Self + where + H: IntoHandlers>, + { + self.subcommands.insert(None, handler.into_handlers()); + self + } +} + +impl HandlerTypes for ParentHandler +where + Params: Send + Sync, + InheritedParams: Send + Sync, +{ + type Params = Params; + type InheritedParams = InheritedParams; + type Ok = Value; + type Err = RpcError; +} +#[async_trait::async_trait] +impl Handler for ParentHandler +where + Params: Serialize + Send + Sync + 'static, + InheritedParams: Serialize + Send + Sync + 'static, +{ + type Context = AnyContext; + fn handle_sync( + &self, + HandleArgs { + context, + mut parent_method, + mut method, + raw_params, + .. + }: HandleArgs, + ) -> Result { + let cmd = method.pop_front(); + if let Some(cmd) = cmd { + parent_method.push_back(cmd); + } + if let Some((_, sub_handler)) = &self.subcommands.get(context.inner_type_id(), cmd) { + sub_handler.handle_sync(HandleAnyArgs { + context, + parent_method, + method, + params: raw_params, + }) + } else { + Err(yajrc::METHOD_NOT_FOUND_ERROR) + } + } + async fn handle_async( + &self, + HandleArgs { + context, + mut parent_method, + mut method, + raw_params, + .. + }: HandleArgs, + ) -> Result { + let cmd = method.pop_front(); + if let Some(cmd) = cmd { + parent_method.push_back(cmd); + } + if let Some((_, sub_handler)) = self.subcommands.get(context.inner_type_id(), cmd) { + sub_handler + .handle_async(HandleAnyArgs { + context, + parent_method, + method, + params: raw_params, + }) + .await + } else { + Err(yajrc::METHOD_NOT_FOUND_ERROR) + } + } + fn metadata( + &self, + mut method: VecDeque<&'static str>, + ctx_ty: TypeId, + ) -> OrdMap<&'static str, Value> { + let metadata = self.metadata.clone(); + if let Some((_, handler)) = self.subcommands.get(ctx_ty, method.pop_front()) { + handler.metadata(method, ctx_ty).union(metadata) + } else { + metadata + } + } + fn contexts(&self) -> Option> { + self.get_contexts() + } + fn method_from_dots(&self, method: &str, ctx_ty: TypeId) -> Option> { + let (head, tail) = if method.is_empty() { + (None, None) + } else { + method + .split_once(".") + .map(|(head, tail)| (Some(head), Some(tail))) + .unwrap_or((Some(method), None)) + }; + let (Name(name), h) = self.subcommands.get(ctx_ty, head)?; + let mut res = VecDeque::new(); + if let Some(name) = name { + res.push_back(name); + } + if let Some(tail) = tail { + res.append(&mut h.method_from_dots(tail, ctx_ty)?); + } + Some(res) + } +} + +impl CliBindings for ParentHandler +where + Params: FromArgMatches + CommandFactory + Serialize + Send + Sync + 'static, + InheritedParams: Serialize + Send + Sync + 'static, +{ + type Context = AnyContext; + fn cli_command(&self, ctx_ty: TypeId) -> Command { + let mut base = Params::command().subcommand_required(true); + for (name, handlers) in &self.subcommands.0 { + match ( + name, + if let Some(handler) = handlers.get(&Some(ctx_ty)) { + Some(handler) + } else if let Some(handler) = handlers.get(&None) { + Some(handler) + } else { + None + }, + ) { + (Name(Some(name)), Some(DynHandler::WithCli(handler))) => { + base = base.subcommand(handler.cli_command(ctx_ty).name(name)); + } + (Name(None), Some(DynHandler::WithCli(_))) => { + base = base.subcommand_required(false); + } + _ => (), + } + } + base + } + fn cli_parse( + &self, + matches: &ArgMatches, + ctx_ty: TypeId, + ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { + let root_params = imbl_value::to_value(&Params::from_arg_matches(matches)?) + .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ValueValidation, e))?; + let (name, matches) = match matches.subcommand() { + Some((name, matches)) => (Some(name), matches), + None => (None, matches), + }; + if let Some((Name(Some(name)), DynHandler::WithCli(handler))) = + self.subcommands.get(ctx_ty, name) + { + let (mut method, params) = handler.cli_parse(matches, ctx_ty)?; + method.push_front(name); + + Ok(( + method, + combine(root_params, params) + .map_err(|e| clap::Error::raw(clap::error::ErrorKind::ArgumentConflict, e))?, + )) + } else { + Ok((VecDeque::new(), root_params)) + } + } + fn cli_display( + &self, + HandleArgs { + context, + mut parent_method, + mut method, + raw_params, + .. + }: HandleArgs, + result: Self::Ok, + ) -> Result<(), Self::Err> { + let cmd = method.pop_front(); + if let Some(cmd) = cmd { + parent_method.push_back(cmd); + } + if let Some((_, DynHandler::WithCli(sub_handler))) = + self.subcommands.get(context.inner_type_id(), cmd) + { + sub_handler.cli_display( + HandleAnyArgs { + context, + parent_method, + method, + params: raw_params, + }, + result, + ) + } else { + Err(yajrc::METHOD_NOT_FOUND_ERROR) + } + } +} +impl IntoHandlers for ParentHandler +where + Self: HandlerTypes + Handler + CliBindings, + ::Params: DeserializeOwned, + ::InheritedParams: DeserializeOwned, + ::Ok: Serialize + DeserializeOwned, + RpcError: From<::Err>, +{ + fn into_handlers(self) -> impl IntoIterator, DynHandler)> { + iter_from_ctx_and_handler( + self.contexts(), + DynHandler::WithoutCli(Arc::new(AnyHandler::new(self))), + ) + } +} +impl IntoHandlers for NoCli> +where + ParentHandler: HandlerTypes + Handler, + as HandlerTypes>::Params: DeserializeOwned, + as HandlerTypes>::InheritedParams: DeserializeOwned, + as HandlerTypes>::Ok: Serialize + DeserializeOwned, + RpcError: From< as HandlerTypes>::Err>, +{ + fn into_handlers(self) -> impl IntoIterator, DynHandler)> { + iter_from_ctx_and_handler( + self.0.contexts(), + DynHandler::WithoutCli(Arc::new(AnyHandler::new(self.0))), + ) + } +} diff --git a/rpc-toolkit/src/server/mod.rs b/rpc-toolkit/src/server/mod.rs index a56f6f9..52f13f6 100644 --- a/rpc-toolkit/src/server/mod.rs +++ b/rpc-toolkit/src/server/mod.rs @@ -8,7 +8,7 @@ use imbl_value::Value; use yajrc::{RpcError, RpcMethod}; use crate::util::{invalid_request, JobRunner}; -use crate::{AnyHandler, HandleAny, HandleAnyArgs, IntoContext, ParentHandler}; +use crate::{AnyContext, AnyHandler, HandleAny, HandleAnyArgs, IntoContext, ParentHandler}; type GenericRpcMethod = yajrc::GenericRpcMethod; type RpcRequest = yajrc::RpcRequest; @@ -23,7 +23,7 @@ pub use socket::*; pub struct Server { make_ctx: Arc BoxFuture<'static, Result> + Send + Sync>, - root_handler: Arc>, + root_handler: Arc>, } impl Clone for Server { fn clone(&self) -> Self { diff --git a/rpc-toolkit/tests/handler.rs b/rpc-toolkit/tests/handler.rs index d478f17..1415599 100644 --- a/rpc-toolkit/tests/handler.rs +++ b/rpc-toolkit/tests/handler.rs @@ -120,7 +120,7 @@ fn make_api() -> ParentHandler { donde: String, } ParentHandler::new() - .subcommand_remote_cli::( + .subcommand( "echo", from_fn_async( |c: ServerContext, EchoParams { next }: EchoParams| async move { @@ -129,7 +129,8 @@ fn make_api() -> ParentHandler { Value::String(Arc::new(next)), )) }, - ), + ) + .with_remote_cli::(), ) .subcommand( "hello",