pub( crate ) mod private { use std::collections::HashMap; use std::rc::Rc; use core::fmt; use crate::*; use wtools::error::BasicError; // qqq : for Dima : adjust formatting /// /// Handle for command routine. /// // qqq : for Dima : make alias for Result with BasicError pub struct OnCommand( Option< Rc< dyn Fn( &instruction::Instruction ) -> Result< (), BasicError > > > ); impl OnCommand { /// Checks that OnCommand has callback to call. pub fn callable( &self ) -> bool { if self.0.is_some() { true } else { false } } /// Perform callback. pub fn perform( &self, instruction : &instruction::Instruction ) -> Result< (), BasicError > { if self.0.is_some() { let r = self.0.as_ref().unwrap(); return r( instruction ); } Ok( () ) } } impl Default for OnCommand { fn default() -> Self { Self ( Option::None ) } } impl From<&'static dyn Fn( &instruction::Instruction ) -> Result< (), BasicError >> for OnCommand { fn from( src : &'static dyn Fn( &instruction::Instruction ) -> Result< (), BasicError > ) -> Self { OnCommand( Some( Rc::new( src ) ) ) } } impl Clone for OnCommand { fn clone( &self ) -> Self { match self { OnCommand ( Option::None ) => Self ( None ), OnCommand ( Option::Some( boxed ) ) => Self ( Some( boxed.clone() ) ), } } } impl fmt::Debug for OnCommand { fn fmt( &self, f: &mut fmt::Formatter<'_> ) -> fmt::Result { match self { OnCommand ( Option::None ) => f.write_str( "None" ), OnCommand ( Option::Some( _rc ) ) => f.write_str( "OnCommand" ), } } } /// /// Command descriptor. /// #[derive( Default, Debug, Clone )] pub struct Command { /// Command common hint. pub hint : String, /// Command full hint. pub long_hint : String, /// Phrase descriptor for command. pub phrase : String, /// Command subject hint. pub subject_hint : String, /// Hints for command options. pub properties_hints : HashMap< String, String >, /// Map of aliases. pub properties_aliases : HashMap< String, Vec< String > >, /// Command routine. pub routine : OnCommand, } impl PartialEq for Command { /* qqq : for Dmytro : extend */ fn eq( &self, other: &Self ) -> bool { self.hint == other.hint && self.long_hint == other.long_hint && self.subject_hint == other.subject_hint } } impl Command { /// Generate short help for command. pub fn help_short( &self ) -> String { format!( ".{} - {}", self.phrase.replace( " ", "." ), self.hint ) } /// Generate short help for command. pub fn help_long( &self ) -> String { let properties_hints = self.properties_hints.iter().map( | ( key, value ) | format!( " {} - {}", key, value ) ).collect::< Vec< _ > >(); let properties_hints = properties_hints.join( "\n" ); format!( ".{} - {}\n{}", self.phrase.replace( " ", "." ), self.long_hint, properties_hints ) } /// Execute callback. pub fn perform( &self, instruction : &instruction::Instruction ) -> Result< (), BasicError > { if self.subject_hint.len() == 0 && instruction.subject.len() != 0 { return Err( BasicError::new( "Unexpected subject." ) ); } for ( key, _value ) in &instruction.properties_map { if self.properties_hints.get( key.as_str() ).is_none() { return Err( BasicError::new( "Unknown option." ) ); } } if self.routine.callable() { return self.routine.perform( instruction ); } Ok( () ) } } /// /// Options for command. /// #[derive( Debug, Clone, Default )] pub struct CommandOptions { ins : Command, } // // ro : null, // h : null, // lh : null, impl CommandOptions { field_str!{ hint } field_str!{ hint, h } field_str!{ long_hint } field_str!{ long_hint, lh } field_str!{ phrase } field_str!{ subject_hint } field_str!{ subject_hint, sh } field_map_str_str!{ properties_hints, property_hint } field_map_str_vec_str!{ properties_aliases, property_alias } field_routine!{ routine } field_routine!{ routine, ro } /// Command former. pub fn form( &self ) -> Command { self.ins.clone() } } } /// Protected namespace of the module. pub mod protected { pub use super::private::OnCommand; pub use super::private::Command; pub use super::private::CommandOptions; } pub use protected::*; /// Exposed namespace of the module. pub mod exposed { pub use super::private::OnCommand; pub use super::private::Command; pub use super::private::CommandOptions; } /// Namespace of the module to include with `use module::*`. pub mod prelude { pub use super::private::OnCommand; pub use super::private::Command; pub use super::private::CommandOptions; }