From b0363023a51dd52ce2c4346f9dfdf9015ada42be Mon Sep 17 00:00:00 2001
From: Ian McInerney <ian.s.mcinerney@ieee.org>
Date: Fri, 30 Sep 2022 00:43:39 +0100
Subject: [PATCH] Parameterize the tool manager RunAction function to ensure
 type stabilty

---
 common/tool/tool_manager.cpp |  6 +++---
 include/tool/tool_manager.h  | 34 ++++++++++++++++++++++++++++++----
 2 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/common/tool/tool_manager.cpp b/common/tool/tool_manager.cpp
index 96e8055d2f..4c6cb8bc80 100644
--- a/common/tool/tool_manager.cpp
+++ b/common/tool/tool_manager.cpp
@@ -285,7 +285,7 @@ bool TOOL_MANAGER::InvokeTool( const std::string& aToolName )
 }
 
 
-bool TOOL_MANAGER::RunAction( const std::string& aActionName, bool aNow, std::any aParam )
+bool TOOL_MANAGER::doRunAction( const std::string& aActionName, bool aNow, std::any aParam )
 {
     TOOL_ACTION* action = m_actionMgr->FindAction( aActionName );
 
@@ -295,7 +295,7 @@ bool TOOL_MANAGER::RunAction( const std::string& aActionName, bool aNow, std::an
         return false;
     }
 
-    RunAction( *action, aNow, aParam );
+    doRunAction( *action, aNow, aParam );
 
     return false;
 }
@@ -319,7 +319,7 @@ VECTOR2D TOOL_MANAGER::GetCursorPosition() const
 }
 
 
-bool TOOL_MANAGER::RunAction( const TOOL_ACTION& aAction, bool aNow, std::any aParam )
+bool TOOL_MANAGER::doRunAction( const TOOL_ACTION& aAction, bool aNow, std::any aParam )
 {
     if( m_shuttingDown )
         return true;
diff --git a/include/tool/tool_manager.h b/include/tool/tool_manager.h
index 26857c6c74..7368432715 100644
--- a/include/tool/tool_manager.h
+++ b/include/tool/tool_manager.h
@@ -131,6 +131,9 @@ public:
      *
      * The common format for action names is "application.ToolName.Action".
      *
+     * Note: The type of the optional parameter must match exactly with the type the consuming
+     *       action is expecting, otherwise an assert will occur when reading the paramter.
+     *
      * @param aActionName is the name of action to be invoked.
      * @param aNow decides if the action has to be run immediately or after the current coroutine
      *             is preemptied.
@@ -138,14 +141,21 @@ public:
      *               depends on the action.
      * @return False if the action was not found.
      */
-    bool RunAction( const std::string& aActionName, bool aNow, std::any aParam );
+    template<typename T>
+    bool RunAction( const std::string& aActionName, bool aNow, T aParam )
+    {
+        // Use a cast to ensure the proper type is stored inside the parameter
+        std::any a( static_cast<T>( aParam ) );
+
+        return doRunAction( aActionName, aNow, a );
+    }
 
     bool RunAction( const std::string& aActionName, bool aNow = false )
     {
         // Default initialize the parameter argument to an empty std::any
         std::any a;
 
-        return RunAction( aActionName, aNow, a );
+        return doRunAction( aActionName, aNow, a );
     }
 
     /**
@@ -154,6 +164,9 @@ public:
      * This function will only return if the action has been handled when the action is run
      * immediately (aNow = true), otherwise it will always return false.
      *
+     * Note: The type of the optional parameter must match exactly with the type the consuming
+     *       action is expecting, otherwise an assert will occur when reading the paramter.
+     *
      * @param aAction is the action to be invoked.
      * @param aNow decides if the action has to be run immediately or after the current coroutine
      *             is preemptied.
@@ -161,14 +174,21 @@ public:
      *               depends on the action.
      * @return True if the action was handled immediately
      */
-    bool RunAction( const TOOL_ACTION& aAction, bool aNow, std::any aParam );
+    template<typename T>
+    bool RunAction( const TOOL_ACTION& aAction, bool aNow, T aParam )
+    {
+        // Use a cast to ensure the proper type is stored inside the parameter
+        std::any a( static_cast<T>( aParam ) );
+
+        return doRunAction( aAction, aNow, a );
+    }
 
     bool RunAction( const TOOL_ACTION& aAction, bool aNow = false )
     {
         // Default initialize the parameter argument to an empty std::any
         std::any a;
 
-        return RunAction( aAction, aNow, a );
+        return doRunAction( aAction, aNow, a );
     }
 
     /**
@@ -441,6 +461,12 @@ public:
 private:
     typedef std::pair<TOOL_EVENT_LIST, TOOL_STATE_FUNC> TRANSITION;
 
+    /**
+     * Helper function to actually run an action.
+     */
+    bool doRunAction( const TOOL_ACTION& aAction, bool aNow, std::any aParam );
+    bool doRunAction( const std::string& aActionName, bool aNow, std::any aParam );
+
     /**
      * Pass an event at first to the active tools, then to all others.
      */