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> 1309b88f26SKrzysztof Grobelny 1409b88f26SKrzysztof Grobelny namespace sdbusplus 1509b88f26SKrzysztof Grobelny { 16*c8447d52SKrzysztof Grobelny 17*c8447d52SKrzysztof Grobelny namespace details 1809b88f26SKrzysztof Grobelny { 1909b88f26SKrzysztof Grobelny 20*c8447d52SKrzysztof Grobelny template <typename VariantType> 21*c8447d52SKrzysztof Grobelny inline auto findProperty( 22*c8447d52SKrzysztof Grobelny const std::vector<std::pair<std::string, VariantType>>& container, 23*c8447d52SKrzysztof Grobelny const std::string& key) noexcept 2409b88f26SKrzysztof Grobelny { 25*c8447d52SKrzysztof Grobelny return std::find_if( 26*c8447d52SKrzysztof Grobelny container.begin(), container.end(), 27*c8447d52SKrzysztof Grobelny [&key](const auto& keyValue) { return keyValue.first == key; }); 2809b88f26SKrzysztof Grobelny } 2909b88f26SKrzysztof Grobelny 30*c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename ValueType> 31*c8447d52SKrzysztof Grobelny inline bool readProperty( 32*c8447d52SKrzysztof Grobelny const OnErrorCallback& onErrorCallback, 33*c8447d52SKrzysztof Grobelny const std::vector<std::pair<std::string, VariantType>>& container, 34*c8447d52SKrzysztof Grobelny const std::string& expectedKey, 35*c8447d52SKrzysztof Grobelny ValueType& 36*c8447d52SKrzysztof Grobelny outValue) noexcept(noexcept(onErrorCallback(sdbusplus:: 37*c8447d52SKrzysztof Grobelny UnpackErrorReason{}, 38*c8447d52SKrzysztof Grobelny std::string{}))) 39*c8447d52SKrzysztof Grobelny { 40*c8447d52SKrzysztof Grobelny auto it = findProperty(container, expectedKey); 41*c8447d52SKrzysztof Grobelny 42*c8447d52SKrzysztof Grobelny if (it != container.end()) 43*c8447d52SKrzysztof Grobelny { 44*c8447d52SKrzysztof Grobelny if constexpr (std::is_pointer_v<ValueType>) 45*c8447d52SKrzysztof Grobelny { 46*c8447d52SKrzysztof Grobelny if (const auto* value = std::get_if< 47*c8447d52SKrzysztof Grobelny std::remove_cv_t<std::remove_pointer_t<ValueType>>>( 48*c8447d52SKrzysztof Grobelny &it->second)) 49*c8447d52SKrzysztof Grobelny { 50*c8447d52SKrzysztof Grobelny outValue = value; 51*c8447d52SKrzysztof Grobelny } 52*c8447d52SKrzysztof Grobelny else 53*c8447d52SKrzysztof Grobelny { 54*c8447d52SKrzysztof Grobelny onErrorCallback(UnpackErrorReason::wrongType, expectedKey); 55*c8447d52SKrzysztof Grobelny return false; 56*c8447d52SKrzysztof Grobelny } 57*c8447d52SKrzysztof Grobelny } 58*c8447d52SKrzysztof Grobelny else if constexpr (utility::is_optional_v<ValueType>) 59*c8447d52SKrzysztof Grobelny { 60*c8447d52SKrzysztof Grobelny using InnerType = typename ValueType::value_type; 61*c8447d52SKrzysztof Grobelny static_assert(!std::is_pointer_v<InnerType>, 62*c8447d52SKrzysztof Grobelny "std::optional<T*> is not supported"); 63*c8447d52SKrzysztof Grobelny if (const auto value = std::get_if<InnerType>(&it->second)) 64*c8447d52SKrzysztof Grobelny 65*c8447d52SKrzysztof Grobelny { 66*c8447d52SKrzysztof Grobelny outValue = *value; 67*c8447d52SKrzysztof Grobelny } 68*c8447d52SKrzysztof Grobelny else 69*c8447d52SKrzysztof Grobelny { 70*c8447d52SKrzysztof Grobelny onErrorCallback(UnpackErrorReason::wrongType, expectedKey); 71*c8447d52SKrzysztof Grobelny return false; 72*c8447d52SKrzysztof Grobelny } 73*c8447d52SKrzysztof Grobelny } 74*c8447d52SKrzysztof Grobelny else 75*c8447d52SKrzysztof Grobelny { 76*c8447d52SKrzysztof Grobelny if (const auto value = std::get_if<ValueType>(&it->second)) 77*c8447d52SKrzysztof Grobelny { 78*c8447d52SKrzysztof Grobelny outValue = *value; 79*c8447d52SKrzysztof Grobelny } 80*c8447d52SKrzysztof Grobelny else 81*c8447d52SKrzysztof Grobelny { 82*c8447d52SKrzysztof Grobelny onErrorCallback(UnpackErrorReason::wrongType, expectedKey); 83*c8447d52SKrzysztof Grobelny return false; 84*c8447d52SKrzysztof Grobelny } 85*c8447d52SKrzysztof Grobelny } 86*c8447d52SKrzysztof Grobelny } 87*c8447d52SKrzysztof Grobelny else if constexpr (!utility::is_optional_v<ValueType> && 88*c8447d52SKrzysztof Grobelny !std::is_pointer_v<ValueType>) 89*c8447d52SKrzysztof Grobelny { 90*c8447d52SKrzysztof Grobelny onErrorCallback(UnpackErrorReason::missingProperty, expectedKey); 9109b88f26SKrzysztof Grobelny return false; 9209b88f26SKrzysztof Grobelny } 9309b88f26SKrzysztof Grobelny 94*c8447d52SKrzysztof Grobelny return true; 9509b88f26SKrzysztof Grobelny } 9609b88f26SKrzysztof Grobelny 97*c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename ValueType, 9809b88f26SKrzysztof Grobelny typename... Args> 99*c8447d52SKrzysztof Grobelny inline bool readProperties( 100*c8447d52SKrzysztof Grobelny OnErrorCallback&& onErrorCallback, 101*c8447d52SKrzysztof Grobelny const std::vector<std::pair<std::string, VariantType>>& container, 10209b88f26SKrzysztof Grobelny const std::string& expectedKey, ValueType& outValue, 103*c8447d52SKrzysztof Grobelny Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus:: 104*c8447d52SKrzysztof Grobelny UnpackErrorReason{}, 105*c8447d52SKrzysztof Grobelny std::string{}))) 10609b88f26SKrzysztof Grobelny { 107*c8447d52SKrzysztof Grobelny if (!readProperty(onErrorCallback, container, expectedKey, outValue)) 10809b88f26SKrzysztof Grobelny { 109*c8447d52SKrzysztof Grobelny return false; 11009b88f26SKrzysztof Grobelny } 11109b88f26SKrzysztof Grobelny 11209b88f26SKrzysztof Grobelny if constexpr (sizeof...(Args) > 0) 11309b88f26SKrzysztof Grobelny { 114*c8447d52SKrzysztof Grobelny return readProperties(std::forward<OnErrorCallback>(onErrorCallback), 115*c8447d52SKrzysztof Grobelny container, std::forward<Args>(args)...); 11609b88f26SKrzysztof Grobelny } 11709b88f26SKrzysztof Grobelny 118*c8447d52SKrzysztof Grobelny return true; 11909b88f26SKrzysztof Grobelny } 12009b88f26SKrzysztof Grobelny 121*c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename... Args> 122*c8447d52SKrzysztof Grobelny inline auto unpackPropertiesCommon( 123*c8447d52SKrzysztof Grobelny OnErrorCallback&& onErrorCallback, 124*c8447d52SKrzysztof Grobelny const std::vector<std::pair<std::string, VariantType>>& input, 125*c8447d52SKrzysztof Grobelny Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus:: 126*c8447d52SKrzysztof Grobelny UnpackErrorReason{}, 127*c8447d52SKrzysztof Grobelny std::string{}))) 12809b88f26SKrzysztof Grobelny { 129*c8447d52SKrzysztof Grobelny static_assert( 130*c8447d52SKrzysztof Grobelny sizeof...(Args) % 2 == 0, 131*c8447d52SKrzysztof Grobelny "Expected number of arguments to be even, but got odd number instead"); 132*c8447d52SKrzysztof Grobelny 133*c8447d52SKrzysztof Grobelny return details::readProperties( 134*c8447d52SKrzysztof Grobelny std::forward<OnErrorCallback>(onErrorCallback), input, 13509b88f26SKrzysztof Grobelny std::forward<Args>(args)...); 13609b88f26SKrzysztof Grobelny } 13709b88f26SKrzysztof Grobelny 138*c8447d52SKrzysztof Grobelny } // namespace details 13909b88f26SKrzysztof Grobelny 140*c8447d52SKrzysztof Grobelny template <typename VariantType, typename... Args> 141*c8447d52SKrzysztof Grobelny inline void unpackProperties( 142*c8447d52SKrzysztof Grobelny const std::vector<std::pair<std::string, VariantType>>& input, 143*c8447d52SKrzysztof Grobelny Args&&... args) 14409b88f26SKrzysztof Grobelny { 145*c8447d52SKrzysztof Grobelny details::unpackPropertiesCommon( 146*c8447d52SKrzysztof Grobelny [](const UnpackErrorReason reason, const std::string& property) { 147*c8447d52SKrzysztof Grobelny throw exception::UnpackPropertyError(property, reason); 148*c8447d52SKrzysztof Grobelny }, 149*c8447d52SKrzysztof Grobelny input, std::forward<Args>(args)...); 1506d83cf53SSzymon Dompke } 1516d83cf53SSzymon Dompke 152*c8447d52SKrzysztof Grobelny template <typename OnErrorCallback, typename VariantType, typename... Args> 153*c8447d52SKrzysztof Grobelny inline bool unpackPropertiesNoThrow( 154*c8447d52SKrzysztof Grobelny OnErrorCallback&& onErrorCallback, 155*c8447d52SKrzysztof Grobelny const std::vector<std::pair<std::string, VariantType>>& input, 1566d83cf53SSzymon Dompke Args&&... args) noexcept 1576d83cf53SSzymon Dompke { 158*c8447d52SKrzysztof Grobelny return details::unpackPropertiesCommon( 159*c8447d52SKrzysztof Grobelny std::forward<OnErrorCallback>(onErrorCallback), input, 160*c8447d52SKrzysztof Grobelny std::forward<Args>(args)...); 1616d83cf53SSzymon Dompke } 16209b88f26SKrzysztof Grobelny 16309b88f26SKrzysztof Grobelny } // namespace sdbusplus 164