109b88f26SKrzysztof Grobelny #pragma once
209b88f26SKrzysztof Grobelny 
309b88f26SKrzysztof Grobelny #include <sdbusplus/exception.hpp>
409b88f26SKrzysztof Grobelny #include <sdbusplus/utility/type_traits.hpp>
509b88f26SKrzysztof Grobelny 
609b88f26SKrzysztof Grobelny #include <algorithm>
709b88f26SKrzysztof Grobelny #include <bitset>
809b88f26SKrzysztof Grobelny #include <optional>
909b88f26SKrzysztof Grobelny #include <stdexcept>
1009b88f26SKrzysztof Grobelny #include <string>
1109b88f26SKrzysztof Grobelny #include <string_view>
1209b88f26SKrzysztof Grobelny #include <variant>
1309b88f26SKrzysztof Grobelny 
1409b88f26SKrzysztof Grobelny namespace sdbusplus
1509b88f26SKrzysztof Grobelny {
16*c8447d52SKrzysztof Grobelny 
17*c8447d52SKrzysztof Grobelny namespace details
1809b88f26SKrzysztof Grobelny {
1909b88f26SKrzysztof Grobelny 
20*c8447d52SKrzysztof Grobelny template <typename VariantType>
21*c8447d52SKrzysztof Grobelny inline auto findProperty(
22*c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& container,
23*c8447d52SKrzysztof Grobelny     const std::string& key) noexcept
2409b88f26SKrzysztof Grobelny {
25*c8447d52SKrzysztof Grobelny     return std::find_if(
26*c8447d52SKrzysztof Grobelny         container.begin(), container.end(),
27*c8447d52SKrzysztof Grobelny         [&key](const auto& keyValue) { return keyValue.first == key; });
2809b88f26SKrzysztof Grobelny }
2909b88f26SKrzysztof Grobelny 
30*c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename ValueType>
31*c8447d52SKrzysztof Grobelny inline bool readProperty(
32*c8447d52SKrzysztof Grobelny     const OnErrorCallback& onErrorCallback,
33*c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& container,
34*c8447d52SKrzysztof Grobelny     const std::string& expectedKey,
35*c8447d52SKrzysztof Grobelny     ValueType&
36*c8447d52SKrzysztof Grobelny         outValue) noexcept(noexcept(onErrorCallback(sdbusplus::
37*c8447d52SKrzysztof Grobelny                                                         UnpackErrorReason{},
38*c8447d52SKrzysztof Grobelny                                                     std::string{})))
39*c8447d52SKrzysztof Grobelny {
40*c8447d52SKrzysztof Grobelny     auto it = findProperty(container, expectedKey);
41*c8447d52SKrzysztof Grobelny 
42*c8447d52SKrzysztof Grobelny     if (it != container.end())
43*c8447d52SKrzysztof Grobelny     {
44*c8447d52SKrzysztof Grobelny         if constexpr (std::is_pointer_v<ValueType>)
45*c8447d52SKrzysztof Grobelny         {
46*c8447d52SKrzysztof Grobelny             if (const auto* value = std::get_if<
47*c8447d52SKrzysztof Grobelny                     std::remove_cv_t<std::remove_pointer_t<ValueType>>>(
48*c8447d52SKrzysztof Grobelny                     &it->second))
49*c8447d52SKrzysztof Grobelny             {
50*c8447d52SKrzysztof Grobelny                 outValue = value;
51*c8447d52SKrzysztof Grobelny             }
52*c8447d52SKrzysztof Grobelny             else
53*c8447d52SKrzysztof Grobelny             {
54*c8447d52SKrzysztof Grobelny                 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
55*c8447d52SKrzysztof Grobelny                 return false;
56*c8447d52SKrzysztof Grobelny             }
57*c8447d52SKrzysztof Grobelny         }
58*c8447d52SKrzysztof Grobelny         else if constexpr (utility::is_optional_v<ValueType>)
59*c8447d52SKrzysztof Grobelny         {
60*c8447d52SKrzysztof Grobelny             using InnerType = typename ValueType::value_type;
61*c8447d52SKrzysztof Grobelny             static_assert(!std::is_pointer_v<InnerType>,
62*c8447d52SKrzysztof Grobelny                           "std::optional<T*> is not supported");
63*c8447d52SKrzysztof Grobelny             if (const auto value = std::get_if<InnerType>(&it->second))
64*c8447d52SKrzysztof Grobelny 
65*c8447d52SKrzysztof Grobelny             {
66*c8447d52SKrzysztof Grobelny                 outValue = *value;
67*c8447d52SKrzysztof Grobelny             }
68*c8447d52SKrzysztof Grobelny             else
69*c8447d52SKrzysztof Grobelny             {
70*c8447d52SKrzysztof Grobelny                 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
71*c8447d52SKrzysztof Grobelny                 return false;
72*c8447d52SKrzysztof Grobelny             }
73*c8447d52SKrzysztof Grobelny         }
74*c8447d52SKrzysztof Grobelny         else
75*c8447d52SKrzysztof Grobelny         {
76*c8447d52SKrzysztof Grobelny             if (const auto value = std::get_if<ValueType>(&it->second))
77*c8447d52SKrzysztof Grobelny             {
78*c8447d52SKrzysztof Grobelny                 outValue = *value;
79*c8447d52SKrzysztof Grobelny             }
80*c8447d52SKrzysztof Grobelny             else
81*c8447d52SKrzysztof Grobelny             {
82*c8447d52SKrzysztof Grobelny                 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
83*c8447d52SKrzysztof Grobelny                 return false;
84*c8447d52SKrzysztof Grobelny             }
85*c8447d52SKrzysztof Grobelny         }
86*c8447d52SKrzysztof Grobelny     }
87*c8447d52SKrzysztof Grobelny     else if constexpr (!utility::is_optional_v<ValueType> &&
88*c8447d52SKrzysztof Grobelny                        !std::is_pointer_v<ValueType>)
89*c8447d52SKrzysztof Grobelny     {
90*c8447d52SKrzysztof Grobelny         onErrorCallback(UnpackErrorReason::missingProperty, expectedKey);
9109b88f26SKrzysztof Grobelny         return false;
9209b88f26SKrzysztof Grobelny     }
9309b88f26SKrzysztof Grobelny 
94*c8447d52SKrzysztof Grobelny     return true;
9509b88f26SKrzysztof Grobelny }
9609b88f26SKrzysztof Grobelny 
97*c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename ValueType,
9809b88f26SKrzysztof Grobelny           typename... Args>
99*c8447d52SKrzysztof Grobelny inline bool readProperties(
100*c8447d52SKrzysztof Grobelny     OnErrorCallback&& onErrorCallback,
101*c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& container,
10209b88f26SKrzysztof Grobelny     const std::string& expectedKey, ValueType& outValue,
103*c8447d52SKrzysztof Grobelny     Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
104*c8447d52SKrzysztof Grobelny                                                           UnpackErrorReason{},
105*c8447d52SKrzysztof Grobelny                                                       std::string{})))
10609b88f26SKrzysztof Grobelny {
107*c8447d52SKrzysztof Grobelny     if (!readProperty(onErrorCallback, container, expectedKey, outValue))
10809b88f26SKrzysztof Grobelny     {
109*c8447d52SKrzysztof Grobelny         return false;
11009b88f26SKrzysztof Grobelny     }
11109b88f26SKrzysztof Grobelny 
11209b88f26SKrzysztof Grobelny     if constexpr (sizeof...(Args) > 0)
11309b88f26SKrzysztof Grobelny     {
114*c8447d52SKrzysztof Grobelny         return readProperties(std::forward<OnErrorCallback>(onErrorCallback),
115*c8447d52SKrzysztof Grobelny                               container, std::forward<Args>(args)...);
11609b88f26SKrzysztof Grobelny     }
11709b88f26SKrzysztof Grobelny 
118*c8447d52SKrzysztof Grobelny     return true;
11909b88f26SKrzysztof Grobelny }
12009b88f26SKrzysztof Grobelny 
121*c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename... Args>
122*c8447d52SKrzysztof Grobelny inline auto unpackPropertiesCommon(
123*c8447d52SKrzysztof Grobelny     OnErrorCallback&& onErrorCallback,
124*c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& input,
125*c8447d52SKrzysztof Grobelny     Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
126*c8447d52SKrzysztof Grobelny                                                           UnpackErrorReason{},
127*c8447d52SKrzysztof Grobelny                                                       std::string{})))
12809b88f26SKrzysztof Grobelny {
129*c8447d52SKrzysztof Grobelny     static_assert(
130*c8447d52SKrzysztof Grobelny         sizeof...(Args) % 2 == 0,
131*c8447d52SKrzysztof Grobelny         "Expected number of arguments to be even, but got odd number instead");
132*c8447d52SKrzysztof Grobelny 
133*c8447d52SKrzysztof Grobelny     return details::readProperties(
134*c8447d52SKrzysztof Grobelny         std::forward<OnErrorCallback>(onErrorCallback), input,
13509b88f26SKrzysztof Grobelny         std::forward<Args>(args)...);
13609b88f26SKrzysztof Grobelny }
13709b88f26SKrzysztof Grobelny 
138*c8447d52SKrzysztof Grobelny } // namespace details
13909b88f26SKrzysztof Grobelny 
140*c8447d52SKrzysztof Grobelny template <typename VariantType, typename... Args>
141*c8447d52SKrzysztof Grobelny inline void unpackProperties(
142*c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& input,
143*c8447d52SKrzysztof Grobelny     Args&&... args)
14409b88f26SKrzysztof Grobelny {
145*c8447d52SKrzysztof Grobelny     details::unpackPropertiesCommon(
146*c8447d52SKrzysztof Grobelny         [](const UnpackErrorReason reason, const std::string& property) {
147*c8447d52SKrzysztof Grobelny             throw exception::UnpackPropertyError(property, reason);
148*c8447d52SKrzysztof Grobelny         },
149*c8447d52SKrzysztof Grobelny         input, std::forward<Args>(args)...);
1506d83cf53SSzymon Dompke }
1516d83cf53SSzymon Dompke 
152*c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename... Args>
153*c8447d52SKrzysztof Grobelny inline bool unpackPropertiesNoThrow(
154*c8447d52SKrzysztof Grobelny     OnErrorCallback&& onErrorCallback,
155*c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& input,
1566d83cf53SSzymon Dompke     Args&&... args) noexcept
1576d83cf53SSzymon Dompke {
158*c8447d52SKrzysztof Grobelny     return details::unpackPropertiesCommon(
159*c8447d52SKrzysztof Grobelny         std::forward<OnErrorCallback>(onErrorCallback), input,
160*c8447d52SKrzysztof Grobelny         std::forward<Args>(args)...);
1616d83cf53SSzymon Dompke }
16209b88f26SKrzysztof Grobelny 
16309b88f26SKrzysztof Grobelny } // namespace sdbusplus
164