Added GVariant visitor 61/35561/8
authorMateusz Malicki <m.malicki2@samsung.com>
Tue, 17 Feb 2015 14:30:54 +0000 (15:30 +0100)
committerMateusz Malicki <m.malicki2@samsung.com>
Wed, 18 Feb 2015 10:44:11 +0000 (11:44 +0100)
[Bug/Feature]   GVariant visitor
[Cause]         N/A
[Solution]      N/A
[Verification]  N/A

Change-Id: I66f8c94a62180b95d3684608a2c528509bf49980

packaging/libConfig.spec
src/CMakeLists.txt
src/config/from-gvariant-visitor.hpp [new file with mode: 0644]
src/config/manager.hpp
src/config/to-gvariant-visitor.hpp [new file with mode: 0644]

index 5219bac..f4ae855 100644 (file)
@@ -10,6 +10,7 @@ Summary:       Config library
 
 BuildRequires: cmake
 BuildRequires: pkgconfig(sqlite3)
+BuildRequires: pkgconfig(glib-2.0)
 
 %description
 The package provides libConfig library.
@@ -63,4 +64,4 @@ rm -rf %{buildroot}
 
 %post -p /sbin/ldconfig
 
-%postun -p /sbin/ldconfig
\ No newline at end of file
+%postun -p /sbin/ldconfig
index 911e71a..9f1d903 100644 (file)
@@ -29,7 +29,7 @@ SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY SOVERSION ${_LIB_SOVERSION_})
 SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY   VERSION ${_LIB_VERSION_})
 
 ## Link libraries #############################################################
-PKG_CHECK_MODULES(CONFIG_DEPS REQUIRED sqlite3)
+PKG_CHECK_MODULES(CONFIG_DEPS REQUIRED sqlite3 glib-2.0)
 INCLUDE_DIRECTORIES(${SRC_FOLDER})
 INCLUDE_DIRECTORIES(SYSTEM ${CONFIG_DEPS_INCLUDE_DIRS})
 TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${CONFIG_DEPS_LIBRARIES})
diff --git a/src/config/from-gvariant-visitor.hpp b/src/config/from-gvariant-visitor.hpp
new file mode 100644 (file)
index 0000000..ba7dc7e
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki (m.malicki2@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   GVariant visitor
+ */
+
+#ifndef CONFIG_FROM_GVARIANT_VISITOR_HPP
+#define CONFIG_FROM_GVARIANT_VISITOR_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/exception.hpp"
+#include "config/is-union.hpp"
+
+#include <string>
+#include <vector>
+#include <cassert>
+#include <glib.h>
+
+namespace config {
+
+class FromGVariantVisitor {
+public:
+    explicit FromGVariantVisitor(GVariant* variant)
+    {
+        //Assume that the visited object is not a union
+        checkType(variant, G_VARIANT_TYPE_TUPLE);
+        mIter = g_variant_iter_new(variant);
+    }
+
+    FromGVariantVisitor(const FromGVariantVisitor& visitor)
+        : mIter(g_variant_iter_copy(visitor.mIter))
+    {
+    }
+
+    ~FromGVariantVisitor()
+    {
+        g_variant_iter_free(mIter);
+    }
+
+    FromGVariantVisitor& operator=(const FromGVariantVisitor&) = delete;
+
+    template<typename T>
+    void visit(const std::string& name, T& value)
+    {
+        GVariant* child = g_variant_iter_next_value(mIter);
+        if (child == NULL) {
+            throw config::ConfigException(
+                "GVariant doesn't match with config. Can't set  '" + name + "'");
+        }
+        fromGVariant(child, value);
+        g_variant_unref(child);
+    }
+
+private:
+    GVariantIter* mIter;
+
+    explicit FromGVariantVisitor(GVariant* variant, bool isUnion)
+    {
+        if (isUnion) {
+            checkType(variant, G_VARIANT_TYPE_VARIANT);
+            variant = g_variant_get_variant(variant);
+        }
+        checkType(variant, G_VARIANT_TYPE_TUPLE);
+        mIter = g_variant_iter_new(variant);
+    }
+
+    static void checkType(GVariant* object, const GVariantType* type)
+    {
+        if (!g_variant_is_of_type(object, type)) {
+            throw ConfigException("Invalid field type");
+        }
+    }
+
+    static void fromGVariant(GVariant* object, int& value)
+    {
+        checkType(object, G_VARIANT_TYPE_INT32);
+        value = g_variant_get_int32(object);
+    }
+
+    static void fromGVariant(GVariant* object, std::int64_t& value)
+    {
+        checkType(object, G_VARIANT_TYPE_INT64);
+        value = g_variant_get_int64(object);
+    }
+
+    static void fromGVariant(GVariant* object, bool& value)
+    {
+        checkType(object, G_VARIANT_TYPE_BOOLEAN);
+        value = g_variant_get_boolean(object);
+    }
+
+    static void fromGVariant(GVariant* object, double& value)
+    {
+        checkType(object, G_VARIANT_TYPE_DOUBLE);
+        value = g_variant_get_double(object);
+    }
+
+    static void fromGVariant(GVariant* object, std::string& value)
+    {
+        checkType(object, G_VARIANT_TYPE_STRING);
+        value = g_variant_get_string(object, NULL);
+    }
+
+    template<typename T>
+    static void fromGVariant(GVariant* object, std::vector<T>& value)
+    {
+        checkType(object, G_VARIANT_TYPE_ARRAY);
+        GVariantIter iter;
+        g_variant_iter_init(&iter, object);
+        int length = g_variant_iter_n_children(&iter);
+        value.resize(static_cast<size_t>(length));
+        for (int i = 0; i < length; ++i) {
+            GVariant* child = g_variant_iter_next_value(&iter);
+            assert(child != NULL);
+            fromGVariant(child, value[static_cast<size_t>(i)]);
+            g_variant_unref(child);
+        }
+    }
+
+    template<typename T>
+    static typename std::enable_if<isVisitable<T>::value>::type
+    fromGVariant(GVariant* object, T& value)
+    {
+        FromGVariantVisitor visitor(object, isUnion<T>::value);
+        value.accept(visitor);
+    }
+
+};
+
+} // namespace config
+
+#endif // CONFIG_FROM_GVARIANT_VISITOR_HPP
index 7afde48..7b000f2 100644 (file)
 #ifndef CONFIG_MANAGER_HPP
 #define CONFIG_MANAGER_HPP
 
+#include "config/to-gvariant-visitor.hpp"
 #include "config/to-json-visitor.hpp"
 #include "config/to-kvstore-visitor.hpp"
 #include "config/to-fdstore-visitor.hpp"
+#include "config/from-gvariant-visitor.hpp"
 #include "config/from-json-visitor.hpp"
 #include "config/from-kvstore-visitor.hpp"
 #include "config/from-fdstore-visitor.hpp"
 #include "config/from-kvjson-visitor.hpp"
 #include "config/fs-utils.hpp"
-
+#include "config/is-union.hpp"
 
 namespace config {
 
 /**
+ * Fills the configuration with data stored in the GVariant
+ *
+ * @param gvariant   configuration in GVariant type
+ * @param config     visitable structure to fill
+ */
+template <class Config>
+void loadFromGVariant(GVariant* gvariant, Config& config)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+    static_assert(!isUnion<Config>::value, "Don't use CONFIG_DECLARE_UNION in top level config");
+
+    FromGVariantVisitor visitor(gvariant);
+    config.accept(visitor);
+}
+
+/**
+ * Saves the config in a GVariant
+ *
+ * @param config   visitable structure to convert
+ */
+template <class Config>
+GVariant* saveToGVariant(const Config& config)
+{
+    static_assert(isVisitable<Config>::value, "Use CONFIG_REGISTER macro");
+    static_assert(!isUnion<Config>::value, "Don't use CONFIG_DECLARE_UNION in top level config");
+
+    ToGVariantVisitor visitor;
+    config.accept(visitor);
+    return visitor.toVariant();
+}
+
+/**
  * Fills the configuration with data stored in the json string
  *
  * @param jsonString configuration in a json format
diff --git a/src/config/to-gvariant-visitor.hpp b/src/config/to-gvariant-visitor.hpp
new file mode 100644 (file)
index 0000000..e8476fc
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  Contact: Mateusz Malicki (m.malicki2@samsung.com)
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License
+ */
+
+/**
+ * @file
+ * @author  Mateusz Malicki (m.malicki2@samsung.com)
+ * @brief   GVariant visitor
+ */
+
+#ifndef CONFIG_TO_GVARIANT_VISITOR_HPP
+#define CONFIG_TO_GVARIANT_VISITOR_HPP
+
+#include "config/is-visitable.hpp"
+#include "config/is-union.hpp"
+
+#include <string>
+#include <vector>
+#include <glib.h>
+
+namespace config {
+
+class ToGVariantVisitor {
+
+public:
+    ToGVariantVisitor()
+        : mBuilder(g_variant_builder_new(G_VARIANT_TYPE_TUPLE))
+    {
+    }
+
+    ToGVariantVisitor(const ToGVariantVisitor& visitor)
+        : mBuilder(visitor.mBuilder ? g_variant_builder_ref(visitor.mBuilder) : nullptr)
+    {
+    }
+
+    ~ToGVariantVisitor()
+    {
+        if (mBuilder) {
+            g_variant_builder_unref(mBuilder);
+        }
+    }
+
+    ToGVariantVisitor& operator=(const ToGVariantVisitor&) = delete;
+
+    GVariant* toVariant()
+    {
+        if (mBuilder) {
+            GVariant* ret = g_variant_builder_end(mBuilder);
+            g_variant_builder_unref(mBuilder);
+            mBuilder = nullptr;
+            return ret;
+        }
+        return nullptr;
+    }
+
+    template<typename T>
+    void visit(const std::string& /* name */, const T& value)
+    {
+        writeInternal(value);
+    }
+private:
+    GVariantBuilder* mBuilder;
+
+    void writeInternal(std::int32_t value) { add("i", value); };
+    void writeInternal(std::int64_t value) { add("x", value); };
+    void writeInternal(bool value) { add("b", value); };
+    void writeInternal(double value) { add("d", value); };
+    void writeInternal(const std::string& value) { add("s", value.c_str()); };
+
+    template<typename T>
+    void writeInternal(const std::vector<T>& value)
+    {
+        if (!value.empty()) {
+            g_variant_builder_open(mBuilder, G_VARIANT_TYPE_ARRAY);
+            for (const T& v : value) {
+                writeInternal(v);
+            }
+            g_variant_builder_close(mBuilder);
+        } else {
+            g_variant_builder_add(mBuilder, "as", NULL);
+        }
+    }
+
+    template<typename T>
+    typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value>::type
+    writeInternal(const T& value)
+    {
+        ToGVariantVisitor visitor;
+        value.accept(visitor);
+        g_variant_builder_add_value(mBuilder, visitor.toVariant());
+    }
+
+    template<typename T>
+    typename std::enable_if<isVisitable<T>::value && isUnion<T>::value>::type
+    writeInternal(const T& value)
+    {
+        ToGVariantVisitor visitor;
+        value.accept(visitor);
+        add("v", visitor.toVariant());
+    }
+
+    template<typename Value>
+    void add(const char* type, Value value) {
+        g_variant_builder_add(mBuilder, type, value);
+    }
+};
+
+} // namespace config
+
+#endif // CONFIG_TO_GVARIANT_VISITOR_HPP