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