From fb32f562eb8e8fdfd8f3e66d3382e8c86cdae5e1 Mon Sep 17 00:00:00 2001
From: Christoph Pohl <christoph.pohl@kit.edu>
Date: Fri, 4 Nov 2022 18:19:41 +0100
Subject: [PATCH] Add PropertyHelper Factories and Products

---
 .../AronComponentConfigExample.cpp            |   4 +
 .../aron_component_config/CMakeLists.txt      |   2 +
 .../PropertyDefinitionVisitors.cpp            | 141 ++++++------------
 .../PropertyHelper.cpp                        | 137 +++++++++++++++++
 .../TypeDescriptorFactories/PropertyHelper.h  | 110 ++++++++++++++
 5 files changed, 297 insertions(+), 97 deletions(-)
 create mode 100644 source/RobotAPI/libraries/aron_component_config/TypeDescriptorFactories/PropertyHelper.cpp
 create mode 100644 source/RobotAPI/libraries/aron_component_config/TypeDescriptorFactories/PropertyHelper.h

diff --git a/source/RobotAPI/components/AronComponentConfigExample/AronComponentConfigExample.cpp b/source/RobotAPI/components/AronComponentConfigExample/AronComponentConfigExample.cpp
index 2f5095b5b..683fcef10 100644
--- a/source/RobotAPI/components/AronComponentConfigExample/AronComponentConfigExample.cpp
+++ b/source/RobotAPI/components/AronComponentConfigExample/AronComponentConfigExample.cpp
@@ -57,6 +57,10 @@ namespace armarx
                                                     ARMARX_TRACE;
                                                     auto& config =
                                                             aron_component_config_plugin_->config_.getWriteBuffer();
+                                                    for (const auto& [key, value] : config.subMember.subsubMember.intDictMember)
+                                                    {
+                                                        ARMARX_INFO << key << value;
+                                                    }
                                                     config.intMember--;
                                                     aron_component_config_plugin_->config_.commitWrite();
                                                 }, 1000);
diff --git a/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt b/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt
index f9e545e5c..cc784baff 100644
--- a/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt
+++ b/source/RobotAPI/libraries/aron_component_config/CMakeLists.txt
@@ -29,6 +29,7 @@ set(LIBS
 set(LIB_FILES
         PropertyDefinitionVisitors.cpp
         RemoteGuiVisitors.cpp
+        TypeDescriptorFactories/PropertyHelper.cpp
 )
 
 set(LIB_HEADERS
@@ -37,6 +38,7 @@ set(LIB_HEADERS
         RemoteGuiVisitors.h
         Util.h
         ComponentPlugin.h
+        TypeDescriptorFactories/PropertyHelper.h
 )
 
 
diff --git a/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp b/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp
index bf606b399..94bb96597 100644
--- a/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp
+++ b/source/RobotAPI/libraries/aron_component_config/PropertyDefinitionVisitors.cpp
@@ -26,6 +26,7 @@
 #include <ArmarXCore/core/application/properties/PropertyDefinition.h>
 #include <ArmarXCore/core/application/properties/PropertyUser.h>
 #include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <RobotAPI/libraries/aron_component_config/TypeDescriptorFactories/PropertyHelper.h>
 
 #include "Util.h"
 
@@ -89,8 +90,13 @@ namespace armarx::aron::component_config
     void
     PropertyDefinitionGetterVisitor::visitListOnEnter(DataInput& o, TypeInput& t)
     {
+        in_list_ = true;
         const auto& name = pathToName(o);
-        const auto& type = type::List::DynamicCast(t);
+        const auto& t_desc = type::List::DynamicCast(t)->getAcceptedType()->getDescriptor();
+        if (t_desc == type::Descriptor::OBJECT)
+        {
+            return;
+        }
         auto old_list = data::List::DynamicCast(o);
         old_list->clear();
         auto get_list = [this, & name]() -> std::vector<std::string>
@@ -100,32 +106,15 @@ namespace armarx::aron::component_config
             return simox::alg::split(list, ",");
         };
         int i = 0;
-        switch (type->getAcceptedType()->getDescriptor())
+        std::vector<std::string> vector = get_list();
+        std::for_each(vector.begin(), vector.end(), [&old_list, &i, &t_desc](const auto& el)
         {
-            case type::Descriptor::INT:
-            {
-                std::vector<std::string> vector = get_list();
-                std::for_each(vector.begin(), vector.end(), [&old_list, &i](const auto& el)
-                {
-                    old_list->addElement(make_int(std::stoi(el), old_list->getPath().withIndex(i)));
-                    i++;
-                });
-                break;
-            }
-            case type::Descriptor::STRING:
-            {
-                std::vector<std::string> vector = get_list();
-                std::for_each(vector.begin(), vector.end(), [&old_list, &i](const auto& el)
-                {
-                    old_list->addElement(make_string(el, old_list->getPath().withIndex(i)));
-                    i++;
-                });
-                break;
-            }
-            default:
-                throw armarx::NotImplementedYetException();
-        }
-        in_list_ = true;
+            old_list->addElement(factories::PropertyHelper::make(t_desc)->from_string(el,
+                                                                                      old_list->getPath()
+                                                                                              .withIndex(i)));
+            i++;
+        });
+
     }
 
     void
@@ -159,10 +148,15 @@ namespace armarx::aron::component_config
     PropertyDefinitionGetterVisitor::visitDictOnEnter(std::shared_ptr<data::Variant>& o,
                                                       const std::shared_ptr<type::Variant>& t)
     {
+        in_list_ = true;
         const auto& name = pathToName(o);
-        const auto& type = type::Dict::DynamicCast(t);
-        auto old_list = data::Dict::DynamicCast(o);
-        old_list->clear();
+        const auto& t_desc = type::Dict::DynamicCast(t)->getAcceptedType()->getDescriptor();
+        if (t_desc == type::Descriptor::OBJECT)
+        {
+            return;
+        }
+        auto old_dict = data::Dict::DynamicCast(o);
+        old_dict->clear();
         auto get_list = [this, & name]() -> std::vector<std::string>
         {
             std::string list;
@@ -170,34 +164,14 @@ namespace armarx::aron::component_config
             return simox::alg::split(list, ",");
         };
         std::vector<std::string> vector = get_list();
-        switch (type->getAcceptedType()->getDescriptor())
+        std::for_each(vector.begin(), vector.end(), [&old_dict, &t_desc](const auto& el)
         {
-            case type::Descriptor::INT:
-            {
-                std::for_each(vector.begin(), vector.end(), [&old_list](const auto& el)
-                {
-                    auto key_value = simox::alg::split(el, ":");
-                    old_list->addElement(key_value.front(),
-                                         make_int(std::stoi(key_value.back()),
-                                                  old_list->getPath().withElement(key_value.front())));
-                });
-                break;
-            }
-            case type::Descriptor::STRING:
-            {
-                std::for_each(vector.begin(), vector.end(), [&old_list](const auto& el)
-                {
-                    auto key_value = simox::alg::split(el, ":");
-                    old_list->addElement(key_value.front(),
-                                         make_string(key_value.back(),
-                                                     old_list->getPath().withElement(key_value.front())));
-                });
-                break;
-            }
-            default:
-                throw armarx::NotImplementedYetException();
-        }
-        in_list_ = true;
+            auto key_value = simox::alg::split(el, ":");
+            old_dict->addElement(key_value.front(),
+                                 factories::PropertyHelper::make(t_desc)->from_string(key_value.back(),
+                                                                                      old_dict->getPath()
+                                                                                              .withElement(key_value.front())));
+        });
     }
 
     void
@@ -303,34 +277,18 @@ namespace armarx::aron::component_config
         in_list_ = true;
         const auto& name = pathToName(l);
         const auto& t_desc = t->getAcceptedType()->getDescriptor();
+        if (t_desc == type::Descriptor::OBJECT)
+        {
+            return;
+        }
         const auto& input = l->getElements();
         std::string str;
-        switch (t_desc)
+        std::vector<std::string> vector;
+        std::transform(input.begin(), input.end(), std::back_inserter(vector), [&t_desc](const auto& el)
         {
-            case type::Descriptor::INT:
-            {
-                std::vector<int> vector;
-                std::transform(input.begin(), input.end(), std::back_inserter(vector), [](const auto& el)
-                {
-                    return data::Int::DynamicCast(el)->getValue();
-                });
-                str = simox::alg::to_string(vector, ", ");
-                break;
-            }
-            case type::Descriptor::STRING:
-            {
-                std::vector<std::string> vector;
-                std::transform(input.begin(), input.end(), std::back_inserter(vector), [](const auto& el)
-                {
-                    return data::String::DynamicCast(el)->getValue();
-                });
-                str = simox::alg::to_string(vector, ", ");
-                break;
-            }
-                // TODO: other basic types
-            default:
-                throw armarx::NotImplementedYetException();
-        }
+            return factories::PropertyHelper::make(t_desc)->to_string(el);
+        });
+        str = simox::alg::to_string(vector, ", ");
         property_definitions_->defineOptionalProperty<std::string>(name, str);
     }
 
@@ -346,27 +304,16 @@ namespace armarx::aron::component_config
         in_list_ = true;
         const auto& name = pathToName(d);
         const auto& t_desc = t->getAcceptedType()->getDescriptor();
+        if (t_desc == type::Descriptor::OBJECT)
+        {
+            return;
+        }
         const auto& input = d->getElements();
         std::stringstream ss;
         for (const auto& [key, el]: input)
         {
             ss << key << ":";
-            switch (t_desc)
-            {
-                case type::Descriptor::INT:
-                {
-                    ss << data::Int::DynamicCast(el)->getValue();
-                    break;
-                }
-                case type::Descriptor::STRING:
-                {
-                    ss << data::String::DynamicCast(el)->getValue();
-                    break;
-                }
-                    // TODO: other basic types
-                default:
-                    throw armarx::NotImplementedYetException();
-            }
+            ss << factories::PropertyHelper::make(t_desc)->to_string(el);
             ss << ",";
         }
         std::string value = ss.str();
diff --git a/source/RobotAPI/libraries/aron_component_config/TypeDescriptorFactories/PropertyHelper.cpp b/source/RobotAPI/libraries/aron_component_config/TypeDescriptorFactories/PropertyHelper.cpp
new file mode 100644
index 000000000..14771c282
--- /dev/null
+++ b/source/RobotAPI/libraries/aron_component_config/TypeDescriptorFactories/PropertyHelper.cpp
@@ -0,0 +1,137 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI
+ * @author     Christoph Pohl ( christoph dot pohl at kit dot edu )
+ * @date       04.11.22
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#include <RobotAPI/libraries/aron/core/data/variant/All.h>
+#include <ArmarXCore/core/application/properties/PropertyDefinitionContainer.h>
+#include "PropertyHelper.h"
+
+namespace armarx::aron::component_config::products
+{
+    template <>
+    std::string
+    PropertyHelper<type::Descriptor::INT>::to_string(const data::VariantPtr& ptr) const
+    {
+        return simox::alg::to_string(data::Int::DynamicCast(ptr)->getValue());
+    }
+
+    template <>
+    std::string
+    PropertyHelper<type::Descriptor::BOOL>::to_string(const data::VariantPtr& ptr) const
+    {
+        return simox::alg::to_string(data::Bool::DynamicCast(ptr)->getValue());
+    }
+
+    template <>
+    std::string
+    PropertyHelper<type::Descriptor::STRING>::to_string(const data::VariantPtr& ptr) const
+    {
+        return data::String::DynamicCast(ptr)->getValue();
+    }
+
+    template <>
+    std::string
+    PropertyHelper<type::Descriptor::FLOAT>::to_string(const data::VariantPtr& ptr) const
+    {
+        return simox::alg::to_string(data::Float::DynamicCast(ptr)->getValue());
+    }
+
+    template <>
+    std::string
+    PropertyHelper<type::Descriptor::INT_ENUM>::to_string(const data::VariantPtr& ptr) const
+    {
+        // TODO: this is should use the name of the enum value
+        return simox::alg::to_string(data::Int::DynamicCast(ptr)->getValue());
+    }
+
+    template <>
+    std::string
+    PropertyHelper<type::Descriptor::DOUBLE>::to_string(const data::VariantPtr& ptr) const
+    {
+        return simox::alg::to_string(data::Double::DynamicCast(ptr)->getValue());
+    }
+
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::INT>::from_string(const std::string& string,
+                                                                 const armarx::aron::Path& path) const
+    {
+        return make_int(std::stoi(string), path);
+    }
+
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::FLOAT>::from_string(const std::string& string,
+                                                                 const armarx::aron::Path& path) const
+    {
+        return make_float(std::stof(string), path);
+    }
+
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::DOUBLE>::from_string(const std::string& string,
+                                                                 const armarx::aron::Path& path) const
+    {
+        return make_double(std::stod(string), path);
+    }
+
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::BOOL>::from_string(const std::string& string,
+                                                                 const armarx::aron::Path& path) const
+    {
+        if (string == "true")
+        {
+            return make_bool(true, path);
+        }
+        else if (string == "false")
+        {
+            return make_bool(false, path);
+        }
+        throw armarx::InvalidArgumentException("Boolean string has to be either true or false");
+    }
+
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::INT_ENUM>::from_string(const std::string& string,
+                                                                 const armarx::aron::Path& path) const
+    {
+        // TODO: this might not work
+        return make_int(std::stoi(string), path);
+    }
+
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::STRING>::from_string(const std::string& string,
+                                                                 const armarx::aron::Path& path) const
+    {
+        return make_string(string, path);
+    }
+
+
+
+    template struct products::PropertyHelper<type::Descriptor::INT>;
+    template struct products::PropertyHelper<type::Descriptor::STRING>;
+    template struct products::PropertyHelper<type::Descriptor::BOOL>;
+    template struct products::PropertyHelper<type::Descriptor::FLOAT>;
+    template struct products::PropertyHelper<type::Descriptor::DOUBLE>;
+    template struct products::PropertyHelper<type::Descriptor::INT_ENUM>;
+}
\ No newline at end of file
diff --git a/source/RobotAPI/libraries/aron_component_config/TypeDescriptorFactories/PropertyHelper.h b/source/RobotAPI/libraries/aron_component_config/TypeDescriptorFactories/PropertyHelper.h
new file mode 100644
index 000000000..cfb5ef2ba
--- /dev/null
+++ b/source/RobotAPI/libraries/aron_component_config/TypeDescriptorFactories/PropertyHelper.h
@@ -0,0 +1,110 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI
+ * @author     Christoph Pohl ( christoph dot pohl at kit dot edu )
+ * @date       04.11.22
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+
+#pragma once
+
+#include <ArmarXCore/util/CPPUtility/SelfRegisteringFactory.h>
+#include <ArmarXCore/core/application/properties/forward_declarations.h>
+#include <RobotAPI/libraries/aron/core/Descriptor.h>
+#include <RobotAPI/libraries/aron/core/data/variant/Variant.h>
+
+namespace armarx::aron::component_config
+{
+    namespace factories
+    {
+        struct PropertyHelper : armarx::Factory<PropertyHelper, type::Descriptor>
+        {
+            explicit PropertyHelper(Key)
+            {
+            };
+
+            virtual ~PropertyHelper() = default;
+
+            virtual std::string to_string(const armarx::aron::data::VariantPtr&) const = 0;
+            virtual aron::data::VariantPtr from_string(const std::string&, const armarx::aron::Path& path) const = 0;
+        };
+    }
+    namespace products
+    {
+        template <type::Descriptor DescT>
+        struct PropertyHelper : factories::PropertyHelper::Registrar<PropertyHelper<DescT>>
+        {
+            using RegistrarT = factories::PropertyHelper::Registrar<PropertyHelper<DescT>>;
+            static constexpr type::Descriptor id = DescT;
+
+            explicit PropertyHelper() : RegistrarT(typename RegistrarT::Registration())
+            {
+            };
+
+            [[nodiscard]] std::string to_string(const data::VariantPtr& ptr) const override;
+            [[nodiscard]] aron::data::VariantPtr from_string(const std::string&, const armarx::aron::Path& path) const override;
+        };
+
+
+    }
+
+    template <>
+    std::string
+    products::PropertyHelper<type::Descriptor::INT>::to_string(const data::VariantPtr& ptr) const;
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::INT>::from_string(const std::string&, const armarx::aron::Path& path) const;
+    template <>
+    std::string
+    products::PropertyHelper<type::Descriptor::FLOAT>::to_string(const data::VariantPtr& ptr) const;
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::FLOAT>::from_string(const std::string&, const armarx::aron::Path& path) const;
+    template <>
+    std::string
+    products::PropertyHelper<type::Descriptor::BOOL>::to_string(const data::VariantPtr& ptr) const;
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::BOOL>::from_string(const std::string&, const armarx::aron::Path& path) const;
+    template <>
+    std::string
+    products::PropertyHelper<type::Descriptor::STRING>::to_string(const data::VariantPtr& ptr) const;
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::STRING>::from_string(const std::string&, const armarx::aron::Path& path) const;
+    template <>
+    std::string
+    products::PropertyHelper<type::Descriptor::DOUBLE>::to_string(const data::VariantPtr& ptr) const;
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::DOUBLE>::from_string(const std::string&, const armarx::aron::Path& path) const;
+    template <>
+    std::string
+    products::PropertyHelper<type::Descriptor::INT_ENUM>::to_string(const data::VariantPtr& ptr) const;
+    template <>
+    aron::data::VariantPtr
+    products::PropertyHelper<type::Descriptor::INT_ENUM>::from_string(const std::string&, const armarx::aron::Path& path) const;
+
+
+    extern template struct products::PropertyHelper<type::Descriptor::INT>;
+    extern template struct products::PropertyHelper<type::Descriptor::FLOAT>;
+    extern template struct products::PropertyHelper<type::Descriptor::DOUBLE>;
+    extern template struct products::PropertyHelper<type::Descriptor::STRING>;
+    extern template struct products::PropertyHelper<type::Descriptor::BOOL>;
+    extern template struct products::PropertyHelper<type::Descriptor::INT_ENUM>;
+}
+
-- 
GitLab