From 98752179a545d8a3bd62e7f765015804323953a9 Mon Sep 17 00:00:00 2001 From: Barsik Date: Mon, 1 Apr 2024 14:31:45 +0300 Subject: [PATCH] Refactor context handling in `CommandsAggregator` and `Context` Removed dependency on `anymap` and reworked how context is managed. Simplified object lifetimes by utilizing `Arc< dyn std::any::Any + Send + Sync >` in lieu of `anymap::Map`. Additionally, updated the way the context is set in `CommandsAggregator` and modified test cases to conform to these changes. --- module/move/wca/Cargo.toml | 3 +- module/move/wca/examples/wca_fluent.rs | 3 +- module/move/wca/src/ca/aggregator.rs | 51 ++++---- module/move/wca/src/ca/executor/context.rs | 111 ++++++------------ module/move/wca/tests/inc/executor/command.rs | 3 +- module/move/wca/tests/inc/executor/program.rs | 3 +- 6 files changed, 65 insertions(+), 109 deletions(-) diff --git a/module/move/wca/Cargo.toml b/module/move/wca/Cargo.toml index 9c418b4e7d..b072febd84 100644 --- a/module/move/wca/Cargo.toml +++ b/module/move/wca/Cargo.toml @@ -47,10 +47,9 @@ iter_tools = { workspace = true, features = [ "default" ] } former = { workspace = true, features = [ "default" ] } ## external -anymap = "0.12" log = "0.4" nom = "7.1" -closure = "0.3" +#closure = "0.3" eddie = { version = "0.4", optional = true } # fuzzy commands search [dev-dependencies] diff --git a/module/move/wca/examples/wca_fluent.rs b/module/move/wca/examples/wca_fluent.rs index 73f03cb48a..cf60d4000c 100644 --- a/module/move/wca/examples/wca_fluent.rs +++ b/module/move/wca/examples/wca_fluent.rs @@ -14,6 +14,7 @@ fn main() { let ca = wca::CommandsAggregator::former() + .with_context( Mutex::new( 0 ) ) .command( "echo" ) .hint( "prints all subjects and properties" ) .subject().kind( Type::String ).optional( true ).end() @@ -24,7 +25,7 @@ fn main() .hint( "This command increments a state number each time it is called consecutively. (E.g. `.inc .inc`)" ) .routine( | ctx : Context | { - let i : Arc< Mutex< i32 > > = ctx.get_or_default(); + let i : Arc< Mutex< i32 > > = ctx.get().unwrap(); let mut i = i.lock().unwrap(); println!( "i = {}", i ); *i += 1; diff --git a/module/move/wca/src/ca/aggregator.rs b/module/move/wca/src/ca/aggregator.rs index 4801a0656f..63854b1bfb 100644 --- a/module/move/wca/src/ca/aggregator.rs +++ b/module/move/wca/src/ca/aggregator.rs @@ -156,35 +156,28 @@ pub( crate ) mod private impl CommandsAggregatorFormer { - // qqq : delete on completion - // /// Setter for grammar - // /// - // /// Gets list of available commands - // pub fn grammar< V >( mut self, commands : V ) -> Self - // where - // V : Into< Vec< Command > > - // { - // let verifier = Verifier::former() - // .commands( commands ) - // .form(); - // self.storage.verifier = Some( verifier ); - // self - // } - - // /// Setter for executor - // /// - // /// Gets dictionary of routines( command name -> callback ) - // pub fn executor< H >( mut self, routines : H ) -> Self - // where - // H : Into< HashMap< String, Routine > > - // { - // let executor = ExecutorConverter::former() - // .routines( routines ) - // .form(); - // - // self.storage.executor_converter = Some( executor ); - // self - // } + /// Adds a context to the executor. + /// + /// # Arguments + /// + /// * `value` - The value to be used as the context. + /// + /// # Returns + /// + /// The modified instance of `Self`. + // `'static` means that the value must be owned or live at least as a `Context' + pub fn with_context< T >( mut self, value : T ) -> Self + where + T : Sync + Send + 'static, + { + let mut executor = self.storage.executor.unwrap_or_else( || Executor::former().form() ); + + executor.context = Context::new( value ); + + self.storage.executor = Some( executor ); + + self + } /// Setter for help content generator /// diff --git a/module/move/wca/src/ca/executor/context.rs b/module/move/wca/src/ca/executor/context.rs index 439639759a..4a338039d6 100644 --- a/module/move/wca/src/ca/executor/context.rs +++ b/module/move/wca/src/ca/executor/context.rs @@ -1,22 +1,12 @@ pub( crate ) mod private { - use std::{ sync::Arc, cell::RefCell }; - use anymap::{ Map, any::CloneAny }; + use std::sync::Arc; /// Container for contexts values /// /// # Examples: /// /// ``` - /// use wca::Context; - /// - /// let ctx = Context::default(); - /// - /// ctx.insert( 42 ); - /// assert_eq!( 42, ctx.get().unwrap() ); - /// ``` - /// - /// ``` /// # use wca::{ Routine, Handler, Context, Value, Args, Props, VerifiedCommand }; /// # use std::sync::{ Arc, Mutex }; /// let routine = Routine::from( Handler::from @@ -24,12 +14,12 @@ pub( crate ) mod private /// | ctx : Context, o : VerifiedCommand | /// { /// let first_arg : i32 = o.args.get_owned( 0 ).unwrap_or_default(); - /// let ctx_value : Arc< Mutex< i32 > > = ctx.get_or_default(); + /// let ctx_value : Arc< Mutex< i32 > > = ctx.get().unwrap(); /// /// *ctx_value.lock().unwrap() += first_arg; /// } /// ) ); - /// let ctx = Context::default(); + /// let ctx = Context::new( Mutex::new( 0 ) ); /// if let Routine::WithContext( callback ) = routine /// { /// let w_command = VerifiedCommand @@ -41,84 +31,59 @@ pub( crate ) mod private /// }; /// callback( ctx.clone(), w_command ).unwrap(); /// } - /// assert_eq!( 1, *ctx.get::< Arc< Mutex< i32 > > >().unwrap().lock().unwrap() ); + /// assert_eq!( 1, *ctx.get::< Mutex< i32 > >().unwrap().lock().unwrap() ); /// ``` - // CloneAny needs to deep clone of Context // qqq : ? - #[ derive( Debug, Clone, former::Former ) ] + #[ derive( Debug, Clone ) ] pub struct Context { - inner : Arc< RefCell< Map::< dyn CloneAny > > > - } - - impl ContextFormer - { - /// Initialize Context with some value - pub fn with< T : CloneAny >( mut self, value : T ) -> Self - { - let inner = self.storage.inner.unwrap_or_else( || Context::default().inner ); - inner.borrow_mut().insert( value ); - - self.storage.inner = Some( inner ); - self - } + inner : Arc< dyn std::any::Any + Send + Sync >, } - + impl Default for Context { fn default() -> Self { - Self { inner : Arc::new( RefCell::new( Map::< dyn CloneAny >::new() ) ) } + Self::new( () ) } } - + impl Context { - /// Insert the T value to the context. If it is already exists - replace it - pub fn insert< T : CloneAny >( &self, value : T ) - { - self.inner.borrow_mut().insert( value ); - } - - /// Removes the T value from the context - pub fn remove< T : CloneAny >( &mut self ) -> Option< T > - { - self.inner.borrow_mut().remove::< T >() - } - - // aaa : Bohdan : why unsafe? - // aaa : re-worked. - - /// Return immutable reference on interior object. - pub fn get< T : CloneAny + Clone >( &self ) -> Option< T > + /// Creates a new `Context` object with the given value. + /// + /// # Arguments + /// + /// * `value` - The value to be stored in the `Context`. The value must implement the `Send` and `Sync` traits. + /// ``` + // `'static` means that the object must be owned or live at least as a `Context' + pub fn new< T : Send + Sync + 'static >( value : T ) -> Self { - self.inner.borrow().get().cloned() - } - - /// Insert the value if it doesn't exists, or take an existing value and return mutable reference to it - pub fn get_or_insert< T : CloneAny + Clone >( &self, value : T ) -> T - { - if let Some( value ) = self.get() - { - value - } - else - { - self.insert( value ); - self.get().unwrap() - } + Self { inner : Arc::new( value ) } } + } - /// Insert default value if it doesn't exists, or take an existing value and return mutable reference to it - pub fn get_or_default< T : CloneAny + Default + Clone >( &self ) -> T + impl Context + { + /// This method retrieves a shared reference to an object of type `T` from the context. + /// + /// # Arguments + /// + /// * `&self` - The context object. + /// + /// # Type Parameters + /// + /// * `T` - The type of the object to retrieve. + /// + /// # Returns + /// + /// An `Option` containing a reference-counted smart pointer (`Arc`) to the object of type `T` if it exists in the context. + /// `None` is returned if the object does not exist or if it cannot be downcasted to type `T`. + // `'static` means that the object must be owned or live at least as a `Context' + pub fn get< T : Send + Sync + 'static >( &self ) -> Option< Arc< T > > { - self.get_or_insert( T::default() ) + self.inner.clone().downcast::< T >().ok() } - - // aaa : for Bohdan : why is it deep? how is it deep? - // aaa : how is it useful? Is it? Examples? - // - // aaa : removed } } diff --git a/module/move/wca/tests/inc/executor/command.rs b/module/move/wca/tests/inc/executor/command.rs index 63b89e4f43..095a0f5a13 100644 --- a/module/move/wca/tests/inc/executor/command.rs +++ b/module/move/wca/tests/inc/executor/command.rs @@ -137,8 +137,7 @@ tests_impls! ) .form(); let verifier = Verifier; - let mut ctx = wca::Context::default(); - ctx.insert( Arc::new( Mutex::new( 1 ) ) ); + let mut ctx = wca::Context::new( Mutex::new( 1 ) ); // init executor let executor = Executor::former() .context( ctx ) diff --git a/module/move/wca/tests/inc/executor/program.rs b/module/move/wca/tests/inc/executor/program.rs index 2efc4dbcd1..dfbccf227b 100644 --- a/module/move/wca/tests/inc/executor/program.rs +++ b/module/move/wca/tests/inc/executor/program.rs @@ -91,8 +91,7 @@ tests_impls! let verifier = Verifier; // starts with 0 - let mut ctx = wca::Context::default(); - ctx.insert( Arc::new( Mutex::new( 0 ) ) ); + let ctx = wca::Context::new( Mutex::new( 0 ) ); // init simple executor let executor = Executor::former() .context( ctx )