1 #pragma once
2
3 #include <sdbusplus/exception.hpp>
4 #include <sdbusplus/utility/type_traits.hpp>
5
6 #include <algorithm>
7 #include <bitset>
8 #include <optional>
9 #include <stdexcept>
10 #include <string>
11 #include <string_view>
12 #include <variant>
13 #include <vector>
14
15 namespace sdbusplus
16 {
17
18 namespace details
19 {
20
21 template <typename VariantType>
findProperty(const std::vector<std::pair<std::string,VariantType>> & container,const std::string & key)22 inline auto findProperty(
23 const std::vector<std::pair<std::string, VariantType>>& container,
24 const std::string& key) noexcept
25 {
26 return std::find_if(
27 container.begin(), container.end(),
28 [&key](const auto& keyValue) { return keyValue.first == key; });
29 }
30
31 template <typename OnErrorCallback, typename VariantType, typename ValueType>
readProperty(const OnErrorCallback & onErrorCallback,const std::vector<std::pair<std::string,VariantType>> & container,const std::string & expectedKey,ValueType & outValue)32 inline bool readProperty(
33 const OnErrorCallback& onErrorCallback,
34 const std::vector<std::pair<std::string, VariantType>>& container,
35 const std::string& expectedKey,
36 ValueType&
37 outValue) noexcept(noexcept(onErrorCallback(sdbusplus::
38 UnpackErrorReason{},
39 std::string{})))
40 {
41 auto it = findProperty(container, expectedKey);
42
43 if (it != container.end())
44 {
45 if constexpr (std::is_pointer_v<ValueType>)
46 {
47 if (const auto* value = std::get_if<
48 std::remove_cv_t<std::remove_pointer_t<ValueType>>>(
49 &it->second))
50 {
51 outValue = value;
52 }
53 else
54 {
55 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
56 return false;
57 }
58 }
59 else if constexpr (utility::is_optional_v<ValueType>)
60 {
61 using InnerType = typename ValueType::value_type;
62 static_assert(!std::is_pointer_v<InnerType>,
63 "std::optional<T*> is not supported");
64 if (const auto value = std::get_if<InnerType>(&it->second))
65
66 {
67 outValue = *value;
68 }
69 else
70 {
71 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
72 return false;
73 }
74 }
75 else
76 {
77 if (const auto value = std::get_if<ValueType>(&it->second))
78 {
79 outValue = *value;
80 }
81 else
82 {
83 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
84 return false;
85 }
86 }
87 }
88 else if constexpr (!utility::is_optional_v<ValueType> &&
89 !std::is_pointer_v<ValueType>)
90 {
91 onErrorCallback(UnpackErrorReason::missingProperty, expectedKey);
92 return false;
93 }
94
95 return true;
96 }
97
98 template <typename OnErrorCallback, typename VariantType, typename ValueType,
99 typename... Args>
readProperties(OnErrorCallback && onErrorCallback,const std::vector<std::pair<std::string,VariantType>> & container,const std::string & expectedKey,ValueType & outValue,Args &&...args)100 inline bool readProperties(
101 OnErrorCallback&& onErrorCallback,
102 const std::vector<std::pair<std::string, VariantType>>& container,
103 const std::string& expectedKey, ValueType& outValue,
104 Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
105 UnpackErrorReason{},
106 std::string{})))
107 {
108 if (!readProperty(onErrorCallback, container, expectedKey, outValue))
109 {
110 return false;
111 }
112
113 if constexpr (sizeof...(Args) > 0)
114 {
115 return readProperties(std::forward<OnErrorCallback>(onErrorCallback),
116 container, std::forward<Args>(args)...);
117 }
118
119 return true;
120 }
121
122 template <typename OnErrorCallback, typename VariantType, typename... Args>
unpackPropertiesCommon(OnErrorCallback && onErrorCallback,const std::vector<std::pair<std::string,VariantType>> & input,Args &&...args)123 inline auto unpackPropertiesCommon(
124 OnErrorCallback&& onErrorCallback,
125 const std::vector<std::pair<std::string, VariantType>>& input,
126 Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
127 UnpackErrorReason{},
128 std::string{})))
129 {
130 static_assert(
131 sizeof...(Args) % 2 == 0,
132 "Expected number of arguments to be even, but got odd number instead");
133
134 return details::readProperties(
135 std::forward<OnErrorCallback>(onErrorCallback), input,
136 std::forward<Args>(args)...);
137 }
138
139 } // namespace details
140
141 template <typename VariantType, typename... Args>
unpackProperties(const std::vector<std::pair<std::string,VariantType>> & input,Args &&...args)142 inline void unpackProperties(
143 const std::vector<std::pair<std::string, VariantType>>& input,
144 Args&&... args)
145 {
146 details::unpackPropertiesCommon(
147 [](const UnpackErrorReason reason, const std::string& property) {
148 throw exception::UnpackPropertyError(property, reason);
149 },
150 input, std::forward<Args>(args)...);
151 }
152
153 template <typename OnErrorCallback, typename VariantType, typename... Args>
unpackPropertiesNoThrow(OnErrorCallback && onErrorCallback,const std::vector<std::pair<std::string,VariantType>> & input,Args &&...args)154 inline bool unpackPropertiesNoThrow(
155 OnErrorCallback&& onErrorCallback,
156 const std::vector<std::pair<std::string, VariantType>>& input,
157 Args&&... args) noexcept
158 {
159 return details::unpackPropertiesCommon(
160 std::forward<OnErrorCallback>(onErrorCallback), input,
161 std::forward<Args>(args)...);
162 }
163
164 } // namespace sdbusplus
165