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