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