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>
13af955670SKrzysztof Grobelny #include <vector>
1409b88f26SKrzysztof Grobelny 
1509b88f26SKrzysztof Grobelny namespace sdbusplus
1609b88f26SKrzysztof Grobelny {
17c8447d52SKrzysztof Grobelny 
18c8447d52SKrzysztof Grobelny namespace details
1909b88f26SKrzysztof Grobelny {
2009b88f26SKrzysztof Grobelny 
21c8447d52SKrzysztof Grobelny template <typename VariantType>
findProperty(const std::vector<std::pair<std::string,VariantType>> & container,const std::string & key)22c8447d52SKrzysztof Grobelny inline auto findProperty(
23c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& container,
24c8447d52SKrzysztof Grobelny     const std::string& key) noexcept
2509b88f26SKrzysztof Grobelny {
26*6db88387SPatrick Williams     return std::find_if(
27*6db88387SPatrick Williams         container.begin(), container.end(),
28*6db88387SPatrick Williams         [&key](const auto& keyValue) { return keyValue.first == key; });
2909b88f26SKrzysztof Grobelny }
3009b88f26SKrzysztof Grobelny 
31c8447d52SKrzysztof Grobelny 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)32c8447d52SKrzysztof Grobelny inline bool readProperty(
33c8447d52SKrzysztof Grobelny     const OnErrorCallback& onErrorCallback,
34c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& container,
35c8447d52SKrzysztof Grobelny     const std::string& expectedKey,
36c8447d52SKrzysztof Grobelny     ValueType&
37c8447d52SKrzysztof Grobelny         outValue) noexcept(noexcept(onErrorCallback(sdbusplus::
38c8447d52SKrzysztof Grobelny                                                         UnpackErrorReason{},
39c8447d52SKrzysztof Grobelny                                                     std::string{})))
40c8447d52SKrzysztof Grobelny {
41c8447d52SKrzysztof Grobelny     auto it = findProperty(container, expectedKey);
42c8447d52SKrzysztof Grobelny 
43c8447d52SKrzysztof Grobelny     if (it != container.end())
44c8447d52SKrzysztof Grobelny     {
45c8447d52SKrzysztof Grobelny         if constexpr (std::is_pointer_v<ValueType>)
46c8447d52SKrzysztof Grobelny         {
47c8447d52SKrzysztof Grobelny             if (const auto* value = std::get_if<
48c8447d52SKrzysztof Grobelny                     std::remove_cv_t<std::remove_pointer_t<ValueType>>>(
49c8447d52SKrzysztof Grobelny                     &it->second))
50c8447d52SKrzysztof Grobelny             {
51c8447d52SKrzysztof Grobelny                 outValue = value;
52c8447d52SKrzysztof Grobelny             }
53c8447d52SKrzysztof Grobelny             else
54c8447d52SKrzysztof Grobelny             {
55c8447d52SKrzysztof Grobelny                 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
56c8447d52SKrzysztof Grobelny                 return false;
57c8447d52SKrzysztof Grobelny             }
58c8447d52SKrzysztof Grobelny         }
59c8447d52SKrzysztof Grobelny         else if constexpr (utility::is_optional_v<ValueType>)
60c8447d52SKrzysztof Grobelny         {
61c8447d52SKrzysztof Grobelny             using InnerType = typename ValueType::value_type;
62c8447d52SKrzysztof Grobelny             static_assert(!std::is_pointer_v<InnerType>,
63c8447d52SKrzysztof Grobelny                           "std::optional<T*> is not supported");
64c8447d52SKrzysztof Grobelny             if (const auto value = std::get_if<InnerType>(&it->second))
65c8447d52SKrzysztof Grobelny 
66c8447d52SKrzysztof Grobelny             {
67c8447d52SKrzysztof Grobelny                 outValue = *value;
68c8447d52SKrzysztof Grobelny             }
69c8447d52SKrzysztof Grobelny             else
70c8447d52SKrzysztof Grobelny             {
71c8447d52SKrzysztof Grobelny                 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
72c8447d52SKrzysztof Grobelny                 return false;
73c8447d52SKrzysztof Grobelny             }
74c8447d52SKrzysztof Grobelny         }
75c8447d52SKrzysztof Grobelny         else
76c8447d52SKrzysztof Grobelny         {
77c8447d52SKrzysztof Grobelny             if (const auto value = std::get_if<ValueType>(&it->second))
78c8447d52SKrzysztof Grobelny             {
79c8447d52SKrzysztof Grobelny                 outValue = *value;
80c8447d52SKrzysztof Grobelny             }
81c8447d52SKrzysztof Grobelny             else
82c8447d52SKrzysztof Grobelny             {
83c8447d52SKrzysztof Grobelny                 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
84c8447d52SKrzysztof Grobelny                 return false;
85c8447d52SKrzysztof Grobelny             }
86c8447d52SKrzysztof Grobelny         }
87c8447d52SKrzysztof Grobelny     }
88c8447d52SKrzysztof Grobelny     else if constexpr (!utility::is_optional_v<ValueType> &&
89c8447d52SKrzysztof Grobelny                        !std::is_pointer_v<ValueType>)
90c8447d52SKrzysztof Grobelny     {
91c8447d52SKrzysztof Grobelny         onErrorCallback(UnpackErrorReason::missingProperty, expectedKey);
9209b88f26SKrzysztof Grobelny         return false;
9309b88f26SKrzysztof Grobelny     }
9409b88f26SKrzysztof Grobelny 
95c8447d52SKrzysztof Grobelny     return true;
9609b88f26SKrzysztof Grobelny }
9709b88f26SKrzysztof Grobelny 
98c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename ValueType,
9909b88f26SKrzysztof Grobelny           typename... Args>
readProperties(OnErrorCallback && onErrorCallback,const std::vector<std::pair<std::string,VariantType>> & container,const std::string & expectedKey,ValueType & outValue,Args &&...args)100c8447d52SKrzysztof Grobelny inline bool readProperties(
101c8447d52SKrzysztof Grobelny     OnErrorCallback&& onErrorCallback,
102c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& container,
10309b88f26SKrzysztof Grobelny     const std::string& expectedKey, ValueType& outValue,
104c8447d52SKrzysztof Grobelny     Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
105c8447d52SKrzysztof Grobelny                                                           UnpackErrorReason{},
106c8447d52SKrzysztof Grobelny                                                       std::string{})))
10709b88f26SKrzysztof Grobelny {
108c8447d52SKrzysztof Grobelny     if (!readProperty(onErrorCallback, container, expectedKey, outValue))
10909b88f26SKrzysztof Grobelny     {
110c8447d52SKrzysztof Grobelny         return false;
11109b88f26SKrzysztof Grobelny     }
11209b88f26SKrzysztof Grobelny 
11309b88f26SKrzysztof Grobelny     if constexpr (sizeof...(Args) > 0)
11409b88f26SKrzysztof Grobelny     {
115c8447d52SKrzysztof Grobelny         return readProperties(std::forward<OnErrorCallback>(onErrorCallback),
116c8447d52SKrzysztof Grobelny                               container, std::forward<Args>(args)...);
11709b88f26SKrzysztof Grobelny     }
11809b88f26SKrzysztof Grobelny 
119c8447d52SKrzysztof Grobelny     return true;
12009b88f26SKrzysztof Grobelny }
12109b88f26SKrzysztof Grobelny 
122c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename... Args>
unpackPropertiesCommon(OnErrorCallback && onErrorCallback,const std::vector<std::pair<std::string,VariantType>> & input,Args &&...args)123c8447d52SKrzysztof Grobelny inline auto unpackPropertiesCommon(
124c8447d52SKrzysztof Grobelny     OnErrorCallback&& onErrorCallback,
125c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& input,
126c8447d52SKrzysztof Grobelny     Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
127c8447d52SKrzysztof Grobelny                                                           UnpackErrorReason{},
128c8447d52SKrzysztof Grobelny                                                       std::string{})))
12909b88f26SKrzysztof Grobelny {
130c8447d52SKrzysztof Grobelny     static_assert(
131c8447d52SKrzysztof Grobelny         sizeof...(Args) % 2 == 0,
132c8447d52SKrzysztof Grobelny         "Expected number of arguments to be even, but got odd number instead");
133c8447d52SKrzysztof Grobelny 
134c8447d52SKrzysztof Grobelny     return details::readProperties(
135c8447d52SKrzysztof Grobelny         std::forward<OnErrorCallback>(onErrorCallback), input,
13609b88f26SKrzysztof Grobelny         std::forward<Args>(args)...);
13709b88f26SKrzysztof Grobelny }
13809b88f26SKrzysztof Grobelny 
139c8447d52SKrzysztof Grobelny } // namespace details
14009b88f26SKrzysztof Grobelny 
141c8447d52SKrzysztof Grobelny template <typename VariantType, typename... Args>
unpackProperties(const std::vector<std::pair<std::string,VariantType>> & input,Args &&...args)142c8447d52SKrzysztof Grobelny inline void unpackProperties(
143c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& input,
144c8447d52SKrzysztof Grobelny     Args&&... args)
14509b88f26SKrzysztof Grobelny {
146c8447d52SKrzysztof Grobelny     details::unpackPropertiesCommon(
147c8447d52SKrzysztof Grobelny         [](const UnpackErrorReason reason, const std::string& property) {
148c8447d52SKrzysztof Grobelny             throw exception::UnpackPropertyError(property, reason);
149c8447d52SKrzysztof Grobelny         },
150c8447d52SKrzysztof Grobelny         input, std::forward<Args>(args)...);
1516d83cf53SSzymon Dompke }
1526d83cf53SSzymon Dompke 
153c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename... Args>
unpackPropertiesNoThrow(OnErrorCallback && onErrorCallback,const std::vector<std::pair<std::string,VariantType>> & input,Args &&...args)154c8447d52SKrzysztof Grobelny inline bool unpackPropertiesNoThrow(
155c8447d52SKrzysztof Grobelny     OnErrorCallback&& onErrorCallback,
156c8447d52SKrzysztof Grobelny     const std::vector<std::pair<std::string, VariantType>>& input,
1576d83cf53SSzymon Dompke     Args&&... args) noexcept
1586d83cf53SSzymon Dompke {
159c8447d52SKrzysztof Grobelny     return details::unpackPropertiesCommon(
160c8447d52SKrzysztof Grobelny         std::forward<OnErrorCallback>(onErrorCallback), input,
161c8447d52SKrzysztof Grobelny         std::forward<Args>(args)...);
1626d83cf53SSzymon Dompke }
16309b88f26SKrzysztof Grobelny 
16409b88f26SKrzysztof Grobelny } // namespace sdbusplus
165