blob: aa63d888d091a7f299318cf991e0372e1e042997 [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>
Krzysztof Grobelnyaf955672022-06-27 09:12:28 +020013#include <vector>
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020014
15namespace sdbusplus
16{
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010017
18namespace details
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020019{
20
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010021template <typename VariantType>
22inline auto findProperty(
23 const std::vector<std::pair<std::string, VariantType>>& container,
24 const std::string& key) noexcept
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020025{
Patrick Williams6db88382023-10-20 11:18:17 -050026 return std::find_if(
27 container.begin(), container.end(),
28 [&key](const auto& keyValue) { return keyValue.first == key; });
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020029}
30
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010031template <typename OnErrorCallback, typename VariantType, typename ValueType>
32inline bool readProperty(
33 const OnErrorCallback& onErrorCallback,
34 const std::vector<std::pair<std::string, VariantType>>& container,
35 const std::string& expectedKey,
36 ValueType&
37 outValue) noexcept(noexcept(onErrorCallback(sdbusplus::
38 UnpackErrorReason{},
39 std::string{})))
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020040{
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010041 auto it = findProperty(container, expectedKey);
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020042
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010043 if (it != container.end())
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020044 {
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010045 if constexpr (std::is_pointer_v<ValueType>)
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020046 {
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010047 if (const auto* value = std::get_if<
48 std::remove_cv_t<std::remove_pointer_t<ValueType>>>(
49 &it->second))
Szymon Dompke6d83cf52021-10-19 16:31:29 +020050 {
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010051 outValue = value;
Szymon Dompke6d83cf52021-10-19 16:31:29 +020052 }
53 else
54 {
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010055 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
56 return false;
57 }
58 }
59 else if constexpr (utility::is_optional_v<ValueType>)
60 {
61 using InnerType = typename ValueType::value_type;
62 static_assert(!std::is_pointer_v<InnerType>,
63 "std::optional<T*> is not supported");
64 if (const auto value = std::get_if<InnerType>(&it->second))
65
66 {
67 outValue = *value;
68 }
69 else
70 {
71 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
72 return false;
73 }
74 }
75 else
76 {
77 if (const auto value = std::get_if<ValueType>(&it->second))
78 {
79 outValue = *value;
80 }
81 else
82 {
83 onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
84 return false;
Szymon Dompke6d83cf52021-10-19 16:31:29 +020085 }
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +020086 }
87 }
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010088 else if constexpr (!utility::is_optional_v<ValueType> &&
89 !std::is_pointer_v<ValueType>)
90 {
91 onErrorCallback(UnpackErrorReason::missingProperty, expectedKey);
92 return false;
93 }
94
95 return true;
Szymon Dompke6d83cf52021-10-19 16:31:29 +020096}
97
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +010098template <typename OnErrorCallback, typename VariantType, typename ValueType,
99 typename... Args>
100inline bool readProperties(
101 OnErrorCallback&& onErrorCallback,
102 const std::vector<std::pair<std::string, VariantType>>& container,
103 const std::string& expectedKey, ValueType& outValue,
104 Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
105 UnpackErrorReason{},
106 std::string{})))
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200107{
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100108 if (!readProperty(onErrorCallback, container, expectedKey, outValue))
109 {
110 return false;
111 }
112
113 if constexpr (sizeof...(Args) > 0)
114 {
115 return readProperties(std::forward<OnErrorCallback>(onErrorCallback),
116 container, std::forward<Args>(args)...);
117 }
118
119 return true;
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200120}
121
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100122template <typename OnErrorCallback, typename VariantType, typename... Args>
123inline auto unpackPropertiesCommon(
124 OnErrorCallback&& onErrorCallback,
125 const std::vector<std::pair<std::string, VariantType>>& input,
126 Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
127 UnpackErrorReason{},
128 std::string{})))
Szymon Dompke6d83cf52021-10-19 16:31:29 +0200129{
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100130 static_assert(
131 sizeof...(Args) % 2 == 0,
132 "Expected number of arguments to be even, but got odd number instead");
133
134 return details::readProperties(
135 std::forward<OnErrorCallback>(onErrorCallback), input,
136 std::forward<Args>(args)...);
137}
138
139} // namespace details
140
141template <typename VariantType, typename... Args>
142inline void unpackProperties(
143 const std::vector<std::pair<std::string, VariantType>>& input,
144 Args&&... args)
145{
146 details::unpackPropertiesCommon(
147 [](const UnpackErrorReason reason, const std::string& property) {
Patrick Williams06f265f2024-08-16 15:19:49 -0400148 throw exception::UnpackPropertyError(property, reason);
149 },
Krzysztof Grobelnyc8447d52022-01-05 13:21:37 +0100150 input, std::forward<Args>(args)...);
151}
152
153template <typename OnErrorCallback, typename VariantType, typename... Args>
154inline bool unpackPropertiesNoThrow(
155 OnErrorCallback&& onErrorCallback,
156 const std::vector<std::pair<std::string, VariantType>>& input,
157 Args&&... args) noexcept
158{
159 return details::unpackPropertiesCommon(
160 std::forward<OnErrorCallback>(onErrorCallback), input,
161 std::forward<Args>(args)...);
Krzysztof Grobelny09b88f22020-09-02 14:49:01 +0200162}
163
164} // namespace sdbusplus