blob: 4c1adfa681c28438630e6f2abc9c9ce9ee707163 [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>
Szymon Dompke6d83cf52021-10-19 16:31:29 +020020bool getIf(Variant&& variant, ValueType& outValue) noexcept
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020021{
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>
Szymon Dompke6d83cf52021-10-19 16:31:29 +020032auto findProperty(Container&& container, const std::string& key) noexcept
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020033{
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>
Szymon Dompke6d83cf52021-10-19 16:31:29 +020047bool containsProperty(Container&& container, const std::string& key) noexcept
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020048{
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,
Szymon Dompke6d83cf52021-10-19 16:31:29 +020064 Args&&... args) noexcept
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020065{
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&,
Szymon Dompke6d83cf52021-10-19 16:31:29 +020088 Args&&... args) noexcept
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020089{
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
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200106template <bool ReturnBadProperty, typename Container, typename... Args>
107auto unpackPropertiesCommon(Container&& input,
108 Args&&... args) noexcept(ReturnBadProperty)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200109{
110 static_assert(sizeof...(Args) % 2 == 0);
111
112 auto assigned = std::bitset<sizeof...(Args) / 2>();
113
114 detail::readProperties<0>(input, assigned, std::forward<Args>(args)...);
115
116 if (!assigned.all())
117 {
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200118 auto missingProperty = detail::findMissingProperty<0>(
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200119 assigned, std::forward<Args>(args)...);
120
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200121 if constexpr (ReturnBadProperty)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200122 {
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200123 return std::optional{missingProperty};
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200124 }
125 else
126 {
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200127 if (detail::containsProperty(std::forward<Container>(input),
128 missingProperty))
129 {
130 throw exception::UnpackPropertyError(
131 missingProperty,
132 exception::UnpackPropertyError::reasonTypeNotMatched);
133 }
134 else
135 {
136 throw exception::UnpackPropertyError(
137 missingProperty,
138 exception::UnpackPropertyError::reasonMissingProperty);
139 }
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200140 }
141 }
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200142 return std::conditional_t<ReturnBadProperty, std::optional<std::string>,
143 void>();
144}
145
146} // namespace detail
147
148template <typename Container, typename... Args>
149void unpackProperties(Container&& input, Args&&... args)
150{
151 detail::unpackPropertiesCommon<false, Container, Args...>(
152 std::forward<Container>(input), std::forward<Args>(args)...);
153}
154
155template <typename Container, typename... Args>
156std::optional<std::string> unpackPropertiesNoThrow(Container&& input,
157 Args&&... args) noexcept
158{
159 return detail::unpackPropertiesCommon<true, Container, Args...>(
160 std::forward<Container>(input), std::forward<Args>(args)...);
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200161}
162
163} // namespace sdbusplus