1*09b88f26SKrzysztof Grobelny #pragma once
2*09b88f26SKrzysztof Grobelny 
3*09b88f26SKrzysztof Grobelny #include <sdbusplus/exception.hpp>
4*09b88f26SKrzysztof Grobelny #include <sdbusplus/utility/type_traits.hpp>
5*09b88f26SKrzysztof Grobelny 
6*09b88f26SKrzysztof Grobelny #include <algorithm>
7*09b88f26SKrzysztof Grobelny #include <bitset>
8*09b88f26SKrzysztof Grobelny #include <optional>
9*09b88f26SKrzysztof Grobelny #include <stdexcept>
10*09b88f26SKrzysztof Grobelny #include <string>
11*09b88f26SKrzysztof Grobelny #include <string_view>
12*09b88f26SKrzysztof Grobelny #include <variant>
13*09b88f26SKrzysztof Grobelny 
14*09b88f26SKrzysztof Grobelny namespace sdbusplus
15*09b88f26SKrzysztof Grobelny {
16*09b88f26SKrzysztof Grobelny namespace detail
17*09b88f26SKrzysztof Grobelny {
18*09b88f26SKrzysztof Grobelny 
19*09b88f26SKrzysztof Grobelny template <typename Variant, typename ValueType>
20*09b88f26SKrzysztof Grobelny bool getIf(Variant&& variant, ValueType& outValue)
21*09b88f26SKrzysztof Grobelny {
22*09b88f26SKrzysztof Grobelny     if (auto value = std::get_if<ValueType>(&variant))
23*09b88f26SKrzysztof Grobelny     {
24*09b88f26SKrzysztof Grobelny         outValue = std::move(*value);
25*09b88f26SKrzysztof Grobelny         return true;
26*09b88f26SKrzysztof Grobelny     }
27*09b88f26SKrzysztof Grobelny 
28*09b88f26SKrzysztof Grobelny     return false;
29*09b88f26SKrzysztof Grobelny }
30*09b88f26SKrzysztof Grobelny 
31*09b88f26SKrzysztof Grobelny template <typename Container>
32*09b88f26SKrzysztof Grobelny auto findProperty(Container&& container, const std::string& key)
33*09b88f26SKrzysztof Grobelny {
34*09b88f26SKrzysztof Grobelny     if constexpr (utility::has_member_find_v<Container>)
35*09b88f26SKrzysztof Grobelny     {
36*09b88f26SKrzysztof Grobelny         return container.find(key);
37*09b88f26SKrzysztof Grobelny     }
38*09b88f26SKrzysztof Grobelny     else
39*09b88f26SKrzysztof Grobelny     {
40*09b88f26SKrzysztof Grobelny         return std::find_if(
41*09b88f26SKrzysztof Grobelny             std::begin(container), std::end(container),
42*09b88f26SKrzysztof Grobelny             [&key](const auto& keyValue) { return keyValue.first == key; });
43*09b88f26SKrzysztof Grobelny     }
44*09b88f26SKrzysztof Grobelny }
45*09b88f26SKrzysztof Grobelny 
46*09b88f26SKrzysztof Grobelny template <typename Container>
47*09b88f26SKrzysztof Grobelny bool containsProperty(Container&& container, const std::string& key)
48*09b88f26SKrzysztof Grobelny {
49*09b88f26SKrzysztof Grobelny     if constexpr (utility::has_member_contains_v<Container>)
50*09b88f26SKrzysztof Grobelny     {
51*09b88f26SKrzysztof Grobelny         return container.contains(key);
52*09b88f26SKrzysztof Grobelny     }
53*09b88f26SKrzysztof Grobelny     else
54*09b88f26SKrzysztof Grobelny     {
55*09b88f26SKrzysztof Grobelny         return findProperty(std::forward<Container>(container), key) !=
56*09b88f26SKrzysztof Grobelny                std::end(container);
57*09b88f26SKrzysztof Grobelny     }
58*09b88f26SKrzysztof Grobelny }
59*09b88f26SKrzysztof Grobelny 
60*09b88f26SKrzysztof Grobelny template <size_t Index, typename Container, size_t N, typename ValueType,
61*09b88f26SKrzysztof Grobelny           typename... Args>
62*09b88f26SKrzysztof Grobelny void readProperties(Container&& container, std::bitset<N>& assigned,
63*09b88f26SKrzysztof Grobelny                     const std::string& expectedKey, ValueType& outValue,
64*09b88f26SKrzysztof Grobelny                     Args&&... args)
65*09b88f26SKrzysztof Grobelny {
66*09b88f26SKrzysztof Grobelny     static_assert(Index < N);
67*09b88f26SKrzysztof Grobelny 
68*09b88f26SKrzysztof Grobelny     auto it = findProperty(std::forward<Container>(container), expectedKey);
69*09b88f26SKrzysztof Grobelny 
70*09b88f26SKrzysztof Grobelny     if (it != std::end(container))
71*09b88f26SKrzysztof Grobelny     {
72*09b88f26SKrzysztof Grobelny         if (getIf(it->second, outValue))
73*09b88f26SKrzysztof Grobelny         {
74*09b88f26SKrzysztof Grobelny             assigned.set(Index);
75*09b88f26SKrzysztof Grobelny         }
76*09b88f26SKrzysztof Grobelny     }
77*09b88f26SKrzysztof Grobelny 
78*09b88f26SKrzysztof Grobelny     if constexpr (sizeof...(Args) > 0)
79*09b88f26SKrzysztof Grobelny     {
80*09b88f26SKrzysztof Grobelny         readProperties<Index + 1>(std::forward<Container>(container), assigned,
81*09b88f26SKrzysztof Grobelny                                   std::forward<Args>(args)...);
82*09b88f26SKrzysztof Grobelny     }
83*09b88f26SKrzysztof Grobelny }
84*09b88f26SKrzysztof Grobelny 
85*09b88f26SKrzysztof Grobelny template <size_t Index, size_t N, typename ValueType, typename... Args>
86*09b88f26SKrzysztof Grobelny std::string findMissingProperty(std::bitset<N>& assigned,
87*09b88f26SKrzysztof Grobelny                                 const std::string& key, ValueType&,
88*09b88f26SKrzysztof Grobelny                                 Args&&... args)
89*09b88f26SKrzysztof Grobelny {
90*09b88f26SKrzysztof Grobelny     static_assert(Index < N);
91*09b88f26SKrzysztof Grobelny 
92*09b88f26SKrzysztof Grobelny     if (!assigned.test(Index))
93*09b88f26SKrzysztof Grobelny     {
94*09b88f26SKrzysztof Grobelny         return key;
95*09b88f26SKrzysztof Grobelny     }
96*09b88f26SKrzysztof Grobelny 
97*09b88f26SKrzysztof Grobelny     if constexpr (sizeof...(Args) > 0)
98*09b88f26SKrzysztof Grobelny     {
99*09b88f26SKrzysztof Grobelny         return findMissingProperty<Index + 1>(assigned,
100*09b88f26SKrzysztof Grobelny                                               std::forward<Args>(args)...);
101*09b88f26SKrzysztof Grobelny     }
102*09b88f26SKrzysztof Grobelny 
103*09b88f26SKrzysztof Grobelny     return {};
104*09b88f26SKrzysztof Grobelny }
105*09b88f26SKrzysztof Grobelny 
106*09b88f26SKrzysztof Grobelny } // namespace detail
107*09b88f26SKrzysztof Grobelny 
108*09b88f26SKrzysztof Grobelny template <typename Container, typename... Args>
109*09b88f26SKrzysztof Grobelny void unpackProperties(Container&& input, Args&&... args)
110*09b88f26SKrzysztof Grobelny {
111*09b88f26SKrzysztof Grobelny     static_assert(sizeof...(Args) % 2 == 0);
112*09b88f26SKrzysztof Grobelny 
113*09b88f26SKrzysztof Grobelny     auto assigned = std::bitset<sizeof...(Args) / 2>();
114*09b88f26SKrzysztof Grobelny 
115*09b88f26SKrzysztof Grobelny     detail::readProperties<0>(input, assigned, std::forward<Args>(args)...);
116*09b88f26SKrzysztof Grobelny 
117*09b88f26SKrzysztof Grobelny     if (!assigned.all())
118*09b88f26SKrzysztof Grobelny     {
119*09b88f26SKrzysztof Grobelny         std::string missingProperty = detail::findMissingProperty<0>(
120*09b88f26SKrzysztof Grobelny             assigned, std::forward<Args>(args)...);
121*09b88f26SKrzysztof Grobelny 
122*09b88f26SKrzysztof Grobelny         if (detail::containsProperty(std::forward<Container>(input),
123*09b88f26SKrzysztof Grobelny                                      missingProperty))
124*09b88f26SKrzysztof Grobelny         {
125*09b88f26SKrzysztof Grobelny             throw exception::UnpackPropertyError(
126*09b88f26SKrzysztof Grobelny                 missingProperty,
127*09b88f26SKrzysztof Grobelny                 exception::UnpackPropertyError::reasonTypeNotMatched);
128*09b88f26SKrzysztof Grobelny         }
129*09b88f26SKrzysztof Grobelny         else
130*09b88f26SKrzysztof Grobelny         {
131*09b88f26SKrzysztof Grobelny             throw exception::UnpackPropertyError(
132*09b88f26SKrzysztof Grobelny                 missingProperty,
133*09b88f26SKrzysztof Grobelny                 exception::UnpackPropertyError::reasonMissingProperty);
134*09b88f26SKrzysztof Grobelny         }
135*09b88f26SKrzysztof Grobelny     }
136*09b88f26SKrzysztof Grobelny }
137*09b88f26SKrzysztof Grobelny 
138*09b88f26SKrzysztof Grobelny } // namespace sdbusplus
139