use std::any::TypeId; use std::collections::VecDeque; use std::fmt::Debug; use clap::builder::{IntoResettable, StyledStr}; use clap::{CommandFactory, FromArgMatches}; use imbl_value::imbl::OrdMap; use imbl_value::Value; use serde::de::DeserializeOwned; use serde::Serialize; use yajrc::RpcError; use crate::util::{Flat, PhantomData}; use crate::{ CallRemote, CallRemoteHandler, CliBindings, DynHandler, Handler, HandlerArgs, HandlerArgsFor, HandlerFor, HandlerTypes, OrEmpty, PrintCliResult, WithContext, }; pub trait HandlerExt: HandlerFor + Sized { fn no_cli(self) -> NoCli; fn no_display(self) -> NoDisplay; fn with_custom_display(self, display: P) -> CustomDisplay where P: PrintCliResult< C, Params = Self::Params, InheritedParams = Self::InheritedParams, Ok = Self::Ok, Err = Self::Err, >; fn with_custom_display_fn( self, display: F, ) -> CustomDisplayFn where F: Fn(HandlerArgsFor, Self::Ok) -> Result<(), Self::Err>; fn with_inherited( self, f: F, ) -> InheritanceHandler where F: Fn(Params, InheritedParams) -> Self::InheritedParams; fn with_call_remote(self) -> RemoteCaller; fn with_about(self, message: M) -> WithAbout where M: IntoResettable; } impl + Sized> HandlerExt for T { fn no_cli(self) -> NoCli { NoCli(self) } fn no_display(self) -> NoDisplay { NoDisplay(self) } fn with_custom_display(self, display: P) -> CustomDisplay where P: PrintCliResult< C, 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(HandlerArgsFor, Self::Ok) -> Result<(), Self::Err>, { CustomDisplayFn { _phantom: PhantomData::new(), print: display, handler: self, } } fn with_inherited( self, f: F, ) -> InheritanceHandler where F: Fn(Params, InheritedParams) -> Self::InheritedParams, { InheritanceHandler { _phantom: PhantomData::new(), handler: self, inherit: f, } } fn with_call_remote(self) -> RemoteCaller { RemoteCaller { _phantom: PhantomData::new(), handler: self, } } fn with_about(self, message: M) -> WithAbout where M: IntoResettable, { WithAbout { handler: self, message, } } } #[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; } #[cfg(feature = "ts-rs")] impl crate::handler::HandlerTS for NoCli where H: crate::handler::HandlerTS, { fn type_info(&self) -> Option { self.0.type_info() } } impl HandlerFor for NoCli where Context: crate::Context, H: HandlerFor, { fn handle_sync( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, ) -> Result { 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, ) -> Result { 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> { self.0.method_from_dots(method) } } impl CliBindings for NoCli where Context: crate::Context, H: HandlerTypes, { const NO_CLI: bool = true; fn cli_command(&self) -> clap::Command { unimplemented!() } fn cli_parse( &self, _: &clap::ArgMatches, ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { unimplemented!() } fn cli_display(&self, _: HandlerArgsFor, _: Self::Ok) -> Result<(), Self::Err> { unimplemented!() } } #[derive(Debug, Clone)] pub struct NoDisplay(pub H); impl HandlerTypes for NoDisplay { type Params = H::Params; type InheritedParams = H::InheritedParams; type Ok = H::Ok; type Err = H::Err; } #[cfg(feature = "ts-rs")] impl crate::handler::HandlerTS for NoDisplay where H: crate::handler::HandlerTS, { fn type_info(&self) -> Option { self.0.type_info() } } impl HandlerFor for NoDisplay where Context: crate::Context, H: HandlerFor, { fn handle_sync( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, ) -> Result { 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, ) -> Result { 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> { self.0.method_from_dots(method) } } impl PrintCliResult for NoDisplay where Context: crate::Context, H: HandlerTypes, H::Params: FromArgMatches + CommandFactory + Serialize, { fn print(&self, _: HandlerArgsFor, _: Self::Ok) -> Result<(), Self::Err> { Ok(()) } } impl CliBindings for NoDisplay where Context: crate::Context, Self: HandlerTypes, Self::Params: CommandFactory + FromArgMatches + Serialize, Self: PrintCliResult, { fn cli_command(&self) -> clap::Command { Self::Params::command() } fn cli_parse( &self, matches: &clap::ArgMatches, ) -> 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, handle_args: HandlerArgsFor, result: Self::Ok, ) -> Result<(), Self::Err> { self.print(handle_args, result) } } #[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; } #[cfg(feature = "ts-rs")] impl crate::handler::HandlerTS for CustomDisplay where H: crate::handler::HandlerTS, P: Send + Sync + Clone + 'static, { fn type_info(&self) -> Option { self.handler.type_info() } } impl HandlerFor for CustomDisplay where Context: crate::Context, H: HandlerFor, P: Send + Sync + Clone + 'static, { fn handle_sync( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, ) -> Result { 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, ) -> Result { 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> { self.handler.method_from_dots(method) } } impl PrintCliResult for CustomDisplay where Context: crate::Context, H: HandlerTypes, P: PrintCliResult< Context, Params = H::Params, InheritedParams = H::InheritedParams, Ok = H::Ok, Err = H::Err, > + Send + Sync + Clone + 'static, { fn print( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, result: Self::Ok, ) -> Result<(), Self::Err> { self.print.print( HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }, result, ) } } impl CliBindings for CustomDisplay where Context: crate::Context, Self: HandlerTypes, Self::Params: CommandFactory + FromArgMatches + Serialize, Self: PrintCliResult, { fn cli_command(&self) -> clap::Command { Self::Params::command() } fn cli_parse( &self, matches: &clap::ArgMatches, ) -> 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, handle_args: HandlerArgsFor, result: Self::Ok, ) -> Result<(), Self::Err> { self.print(handle_args, result) } } pub struct CustomDisplayFn { _phantom: PhantomData, print: F, handler: H, } impl Clone for CustomDisplayFn { fn clone(&self) -> Self { Self { _phantom: PhantomData::new(), 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; } #[cfg(feature = "ts-rs")] impl crate::handler::HandlerTS for CustomDisplayFn where H: crate::handler::HandlerTS, F: Send + Sync + Clone + 'static, Context: 'static, { fn type_info(&self) -> Option { self.handler.type_info() } } impl HandlerFor for CustomDisplayFn where Context: crate::Context, C: 'static, H: HandlerFor, F: Send + Sync + Clone + 'static, { fn handle_sync( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, ) -> Result { 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, ) -> Result { 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> { self.handler.method_from_dots(method) } } impl PrintCliResult for CustomDisplayFn where Context: crate::Context, H: HandlerTypes, F: Fn(HandlerArgsFor, H::Ok) -> Result<(), H::Err> + Send + Sync + Clone + 'static, { fn print( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, result: Self::Ok, ) -> Result<(), Self::Err> { (self.print)( HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }, result, ) } } impl CliBindings for CustomDisplayFn where Context: crate::Context, Self: HandlerTypes, Self::Params: CommandFactory + FromArgMatches + Serialize, Self: PrintCliResult, { fn cli_command(&self) -> clap::Command { Self::Params::command() } fn cli_parse( &self, matches: &clap::ArgMatches, ) -> 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, handle_args: HandlerArgsFor, result: Self::Ok, ) -> Result<(), Self::Err> { self.print(handle_args, result) } } pub struct RemoteCaller { _phantom: PhantomData<(Context, RemoteContext)>, handler: H, } impl Clone for RemoteCaller { fn clone(&self) -> Self { Self { _phantom: PhantomData::new(), handler: self.handler.clone(), } } } impl Debug for RemoteCaller { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_tuple("RemoteCaller").field(&self.handler).finish() } } impl Handler for WithContext> where Context: crate::Context + CallRemote, RemoteContext: crate::Context, H: HandlerFor + CliBindings, H::Ok: Serialize + DeserializeOwned, H::Err: From, H::Params: Serialize + DeserializeOwned, H::InheritedParams: OrEmpty, RpcError: From, Inherited: Send + Sync + 'static, { type H = H; fn handler_for(self) -> Option> { if TypeId::of::() == TypeId::of::() { DynHandler::new(self.handler.handler.no_cli()) } else if TypeId::of::() == TypeId::of::() { DynHandler::new(CallRemoteHandler::::new( self.handler.handler, )) } else { None } } } pub struct InheritanceHandler { _phantom: PhantomData<(Params, InheritedParams)>, handler: H, inherit: F, } impl Clone for InheritanceHandler { fn clone(&self) -> Self { Self { _phantom: PhantomData::new(), 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; } #[cfg(feature = "ts-rs")] impl crate::handler::HandlerTS for InheritanceHandler where Params: Send + Sync + 'static, InheritedParams: Send + Sync + 'static, H: crate::handler::HandlerTS, { fn type_info(&self) -> Option { self.handler.type_info() } } impl HandlerFor for InheritanceHandler where Context: crate::Context, Params: Send + Sync + 'static, InheritedParams: Send + Sync + 'static, H: HandlerFor, F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, { fn handle_sync( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, ) -> Result { self.handler.handle_sync(HandlerArgs { context, parent_method, method, params, inherited_params: (self.inherit)(inherited_params.0, inherited_params.1), raw_params, }) } async fn handle_async( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, ) -> Result { self.handler .handle_async(HandlerArgs { context, parent_method, method, params, inherited_params: (self.inherit)(inherited_params.0, inherited_params.1), 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> { self.handler.method_from_dots(method) } } impl CliBindings for InheritanceHandler where Context: crate::Context, Params: Send + Sync + 'static, InheritedParams: Send + Sync + 'static, H: CliBindings, F: Fn(Params, InheritedParams) -> H::InheritedParams + Send + Sync + Clone + 'static, { fn cli_command(&self) -> clap::Command { self.handler.cli_command() } fn cli_parse( &self, matches: &clap::ArgMatches, ) -> Result<(VecDeque<&'static str>, Value), clap::Error> { self.handler.cli_parse(matches) } fn cli_display( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, result: Self::Ok, ) -> Result<(), Self::Err> { self.handler.cli_display( HandlerArgs { context, parent_method, method, params, inherited_params: (self.inherit)(inherited_params.0, inherited_params.1), raw_params, }, result, ) } } #[derive(Debug, Clone)] pub struct WithAbout { handler: H, message: M, } impl HandlerTypes for WithAbout where H: HandlerTypes, { type Params = H::Params; type InheritedParams = H::InheritedParams; type Ok = H::Ok; type Err = H::Err; } #[cfg(feature = "ts-rs")] impl crate::handler::HandlerTS for WithAbout where H: crate::handler::HandlerTS, M: Clone + Send + Sync + 'static, { fn type_info(&self) -> Option { self.handler.type_info() } } impl HandlerFor for WithAbout where Context: crate::Context, H: HandlerFor, M: Clone + Send + Sync + 'static, { fn handle_sync( &self, HandlerArgs { context, parent_method, method, params, inherited_params, raw_params, }: HandlerArgsFor, ) -> Result { 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, ) -> Result { 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> { self.handler.method_from_dots(method) } } impl CliBindings for WithAbout where Context: crate::Context, H: CliBindings, M: IntoResettable + Clone, { fn cli_command(&self) -> clap::Command { self.handler.cli_command().about(self.message.clone()) } 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, result: Self::Ok, ) -> Result<(), Self::Err> { self.handler.cli_display(handler, result) } }