4a0330aa4db380751d8a8f3d41e56e123ce166e2
[archive/platform/core/system/libConfig.git] / src / config / from-gvariant-visitor.hpp
1 /*
2  *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Mateusz Malicki (m.malicki2@samsung.com)
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License
17  */
18
19 /**
20  * @file
21  * @author  Mateusz Malicki (m.malicki2@samsung.com)
22  * @brief   GVariant visitor
23  */
24
25 #ifndef CONFIG_FROM_GVARIANT_VISITOR_HPP
26 #define CONFIG_FROM_GVARIANT_VISITOR_HPP
27
28 #include "config/is-visitable.hpp"
29 #include "config/exception.hpp"
30 #include "config/is-union.hpp"
31
32 #include <string>
33 #include <vector>
34 #include <memory>
35 #include <cassert>
36 #include <glib.h>
37
38 namespace config {
39
40 class FromGVariantVisitor {
41 public:
42     explicit FromGVariantVisitor(GVariant* variant)
43     {
44         //Assume that the visited object is not a union
45         checkType(variant, G_VARIANT_TYPE_TUPLE);
46         mIter = g_variant_iter_new(variant);
47     }
48
49     FromGVariantVisitor(const FromGVariantVisitor& visitor)
50         : mIter(g_variant_iter_copy(visitor.mIter))
51     {
52     }
53
54     ~FromGVariantVisitor()
55     {
56         g_variant_iter_free(mIter);
57     }
58
59     FromGVariantVisitor& operator=(const FromGVariantVisitor&) = delete;
60
61     template<typename T>
62     void visit(const std::string& name, T& value)
63     {
64         auto child = makeUnique(g_variant_iter_next_value(mIter));
65         if (!child) {
66             throw config::ConfigException(
67                 "GVariant doesn't match with config. Can't set  '" + name + "'");
68         }
69         fromGVariant(child.get(), value);
70     }
71
72 private:
73     GVariantIter* mIter;
74
75     static std::unique_ptr<GVariant, decltype(&g_variant_unref)> makeUnique(GVariant* variant)
76     {
77         return std::unique_ptr<GVariant, decltype(&g_variant_unref)>(variant, g_variant_unref);
78     }
79
80     static void checkType(GVariant* object, const GVariantType* type)
81     {
82         if (!g_variant_is_of_type(object, type)) {
83             throw ConfigException("Invalid field type");
84         }
85     }
86
87     static void fromGVariant(GVariant* object, int& value)
88     {
89         checkType(object, G_VARIANT_TYPE_INT32);
90         value = g_variant_get_int32(object);
91     }
92
93     static void fromGVariant(GVariant* object, std::int64_t& value)
94     {
95         checkType(object, G_VARIANT_TYPE_INT64);
96         value = g_variant_get_int64(object);
97     }
98
99     static void fromGVariant(GVariant* object, bool& value)
100     {
101         checkType(object, G_VARIANT_TYPE_BOOLEAN);
102         value = g_variant_get_boolean(object);
103     }
104
105     static void fromGVariant(GVariant* object, double& value)
106     {
107         checkType(object, G_VARIANT_TYPE_DOUBLE);
108         value = g_variant_get_double(object);
109     }
110
111     static void fromGVariant(GVariant* object, std::string& value)
112     {
113         checkType(object, G_VARIANT_TYPE_STRING);
114         value = g_variant_get_string(object, NULL);
115     }
116
117     template<typename T>
118     static void fromGVariant(GVariant* object, std::vector<T>& value)
119     {
120         checkType(object, G_VARIANT_TYPE_ARRAY);
121         GVariantIter iter;
122         g_variant_iter_init(&iter, object);
123         int length = g_variant_iter_n_children(&iter);
124         value.resize(static_cast<size_t>(length));
125         for (int i = 0; i < length; ++i) {
126             auto child = makeUnique(g_variant_iter_next_value(&iter));
127             assert(child);
128             fromGVariant(child.get(), value[static_cast<size_t>(i)]);
129         }
130     }
131
132     template<typename T>
133     static typename std::enable_if<isUnion<T>::value>::type
134     fromGVariant(GVariant* object, T& value)
135     {
136         checkType(object, G_VARIANT_TYPE_VARIANT);
137         auto inner = makeUnique(g_variant_get_variant(object));
138
139         FromGVariantVisitor visitor(inner.get());
140         value.accept(visitor);
141     }
142
143     template<typename T>
144     static typename std::enable_if<isVisitable<T>::value && !isUnion<T>::value>::type
145     fromGVariant(GVariant* object, T& value)
146     {
147         FromGVariantVisitor visitor(object);
148         value.accept(visitor);
149     }
150
151 };
152
153 } // namespace config
154
155 #endif // CONFIG_FROM_GVARIANT_VISITOR_HPP