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> 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> 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> 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> 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> 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> 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