1*09b88f26SKrzysztof Grobelny #pragma once 2*09b88f26SKrzysztof Grobelny 3*09b88f26SKrzysztof Grobelny #include <sdbusplus/exception.hpp> 4*09b88f26SKrzysztof Grobelny #include <sdbusplus/utility/type_traits.hpp> 5*09b88f26SKrzysztof Grobelny 6*09b88f26SKrzysztof Grobelny #include <algorithm> 7*09b88f26SKrzysztof Grobelny #include <bitset> 8*09b88f26SKrzysztof Grobelny #include <optional> 9*09b88f26SKrzysztof Grobelny #include <stdexcept> 10*09b88f26SKrzysztof Grobelny #include <string> 11*09b88f26SKrzysztof Grobelny #include <string_view> 12*09b88f26SKrzysztof Grobelny #include <variant> 13*09b88f26SKrzysztof Grobelny 14*09b88f26SKrzysztof Grobelny namespace sdbusplus 15*09b88f26SKrzysztof Grobelny { 16*09b88f26SKrzysztof Grobelny namespace detail 17*09b88f26SKrzysztof Grobelny { 18*09b88f26SKrzysztof Grobelny 19*09b88f26SKrzysztof Grobelny template <typename Variant, typename ValueType> 20*09b88f26SKrzysztof Grobelny bool getIf(Variant&& variant, ValueType& outValue) 21*09b88f26SKrzysztof Grobelny { 22*09b88f26SKrzysztof Grobelny if (auto value = std::get_if<ValueType>(&variant)) 23*09b88f26SKrzysztof Grobelny { 24*09b88f26SKrzysztof Grobelny outValue = std::move(*value); 25*09b88f26SKrzysztof Grobelny return true; 26*09b88f26SKrzysztof Grobelny } 27*09b88f26SKrzysztof Grobelny 28*09b88f26SKrzysztof Grobelny return false; 29*09b88f26SKrzysztof Grobelny } 30*09b88f26SKrzysztof Grobelny 31*09b88f26SKrzysztof Grobelny template <typename Container> 32*09b88f26SKrzysztof Grobelny auto findProperty(Container&& container, const std::string& key) 33*09b88f26SKrzysztof Grobelny { 34*09b88f26SKrzysztof Grobelny if constexpr (utility::has_member_find_v<Container>) 35*09b88f26SKrzysztof Grobelny { 36*09b88f26SKrzysztof Grobelny return container.find(key); 37*09b88f26SKrzysztof Grobelny } 38*09b88f26SKrzysztof Grobelny else 39*09b88f26SKrzysztof Grobelny { 40*09b88f26SKrzysztof Grobelny return std::find_if( 41*09b88f26SKrzysztof Grobelny std::begin(container), std::end(container), 42*09b88f26SKrzysztof Grobelny [&key](const auto& keyValue) { return keyValue.first == key; }); 43*09b88f26SKrzysztof Grobelny } 44*09b88f26SKrzysztof Grobelny } 45*09b88f26SKrzysztof Grobelny 46*09b88f26SKrzysztof Grobelny template <typename Container> 47*09b88f26SKrzysztof Grobelny bool containsProperty(Container&& container, const std::string& key) 48*09b88f26SKrzysztof Grobelny { 49*09b88f26SKrzysztof Grobelny if constexpr (utility::has_member_contains_v<Container>) 50*09b88f26SKrzysztof Grobelny { 51*09b88f26SKrzysztof Grobelny return container.contains(key); 52*09b88f26SKrzysztof Grobelny } 53*09b88f26SKrzysztof Grobelny else 54*09b88f26SKrzysztof Grobelny { 55*09b88f26SKrzysztof Grobelny return findProperty(std::forward<Container>(container), key) != 56*09b88f26SKrzysztof Grobelny std::end(container); 57*09b88f26SKrzysztof Grobelny } 58*09b88f26SKrzysztof Grobelny } 59*09b88f26SKrzysztof Grobelny 60*09b88f26SKrzysztof Grobelny template <size_t Index, typename Container, size_t N, typename ValueType, 61*09b88f26SKrzysztof Grobelny typename... Args> 62*09b88f26SKrzysztof Grobelny void readProperties(Container&& container, std::bitset<N>& assigned, 63*09b88f26SKrzysztof Grobelny const std::string& expectedKey, ValueType& outValue, 64*09b88f26SKrzysztof Grobelny Args&&... args) 65*09b88f26SKrzysztof Grobelny { 66*09b88f26SKrzysztof Grobelny static_assert(Index < N); 67*09b88f26SKrzysztof Grobelny 68*09b88f26SKrzysztof Grobelny auto it = findProperty(std::forward<Container>(container), expectedKey); 69*09b88f26SKrzysztof Grobelny 70*09b88f26SKrzysztof Grobelny if (it != std::end(container)) 71*09b88f26SKrzysztof Grobelny { 72*09b88f26SKrzysztof Grobelny if (getIf(it->second, outValue)) 73*09b88f26SKrzysztof Grobelny { 74*09b88f26SKrzysztof Grobelny assigned.set(Index); 75*09b88f26SKrzysztof Grobelny } 76*09b88f26SKrzysztof Grobelny } 77*09b88f26SKrzysztof Grobelny 78*09b88f26SKrzysztof Grobelny if constexpr (sizeof...(Args) > 0) 79*09b88f26SKrzysztof Grobelny { 80*09b88f26SKrzysztof Grobelny readProperties<Index + 1>(std::forward<Container>(container), assigned, 81*09b88f26SKrzysztof Grobelny std::forward<Args>(args)...); 82*09b88f26SKrzysztof Grobelny } 83*09b88f26SKrzysztof Grobelny } 84*09b88f26SKrzysztof Grobelny 85*09b88f26SKrzysztof Grobelny template <size_t Index, size_t N, typename ValueType, typename... Args> 86*09b88f26SKrzysztof Grobelny std::string findMissingProperty(std::bitset<N>& assigned, 87*09b88f26SKrzysztof Grobelny const std::string& key, ValueType&, 88*09b88f26SKrzysztof Grobelny Args&&... args) 89*09b88f26SKrzysztof Grobelny { 90*09b88f26SKrzysztof Grobelny static_assert(Index < N); 91*09b88f26SKrzysztof Grobelny 92*09b88f26SKrzysztof Grobelny if (!assigned.test(Index)) 93*09b88f26SKrzysztof Grobelny { 94*09b88f26SKrzysztof Grobelny return key; 95*09b88f26SKrzysztof Grobelny } 96*09b88f26SKrzysztof Grobelny 97*09b88f26SKrzysztof Grobelny if constexpr (sizeof...(Args) > 0) 98*09b88f26SKrzysztof Grobelny { 99*09b88f26SKrzysztof Grobelny return findMissingProperty<Index + 1>(assigned, 100*09b88f26SKrzysztof Grobelny std::forward<Args>(args)...); 101*09b88f26SKrzysztof Grobelny } 102*09b88f26SKrzysztof Grobelny 103*09b88f26SKrzysztof Grobelny return {}; 104*09b88f26SKrzysztof Grobelny } 105*09b88f26SKrzysztof Grobelny 106*09b88f26SKrzysztof Grobelny } // namespace detail 107*09b88f26SKrzysztof Grobelny 108*09b88f26SKrzysztof Grobelny template <typename Container, typename... Args> 109*09b88f26SKrzysztof Grobelny void unpackProperties(Container&& input, Args&&... args) 110*09b88f26SKrzysztof Grobelny { 111*09b88f26SKrzysztof Grobelny static_assert(sizeof...(Args) % 2 == 0); 112*09b88f26SKrzysztof Grobelny 113*09b88f26SKrzysztof Grobelny auto assigned = std::bitset<sizeof...(Args) / 2>(); 114*09b88f26SKrzysztof Grobelny 115*09b88f26SKrzysztof Grobelny detail::readProperties<0>(input, assigned, std::forward<Args>(args)...); 116*09b88f26SKrzysztof Grobelny 117*09b88f26SKrzysztof Grobelny if (!assigned.all()) 118*09b88f26SKrzysztof Grobelny { 119*09b88f26SKrzysztof Grobelny std::string missingProperty = detail::findMissingProperty<0>( 120*09b88f26SKrzysztof Grobelny assigned, std::forward<Args>(args)...); 121*09b88f26SKrzysztof Grobelny 122*09b88f26SKrzysztof Grobelny if (detail::containsProperty(std::forward<Container>(input), 123*09b88f26SKrzysztof Grobelny missingProperty)) 124*09b88f26SKrzysztof Grobelny { 125*09b88f26SKrzysztof Grobelny throw exception::UnpackPropertyError( 126*09b88f26SKrzysztof Grobelny missingProperty, 127*09b88f26SKrzysztof Grobelny exception::UnpackPropertyError::reasonTypeNotMatched); 128*09b88f26SKrzysztof Grobelny } 129*09b88f26SKrzysztof Grobelny else 130*09b88f26SKrzysztof Grobelny { 131*09b88f26SKrzysztof Grobelny throw exception::UnpackPropertyError( 132*09b88f26SKrzysztof Grobelny missingProperty, 133*09b88f26SKrzysztof Grobelny exception::UnpackPropertyError::reasonMissingProperty); 134*09b88f26SKrzysztof Grobelny } 135*09b88f26SKrzysztof Grobelny } 136*09b88f26SKrzysztof Grobelny } 137*09b88f26SKrzysztof Grobelny 138*09b88f26SKrzysztof Grobelny } // namespace sdbusplus 139