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