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