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 #include <vector> 14 15 namespace sdbusplus 16 { 17 18 namespace details 19 { 20 21 template <typename VariantType> 22 inline auto findProperty( 23 const std::vector<std::pair<std::string, VariantType>>& container, 24 const std::string& key) noexcept 25 { 26 return std::find_if( 27 container.begin(), container.end(), 28 [&key](const auto& keyValue) { return keyValue.first == key; }); 29 } 30 31 template <typename OnErrorCallback, typename VariantType, typename ValueType> 32 inline bool readProperty( 33 const OnErrorCallback& onErrorCallback, 34 const std::vector<std::pair<std::string, VariantType>>& container, 35 const std::string& expectedKey, 36 ValueType& 37 outValue) noexcept(noexcept(onErrorCallback(sdbusplus:: 38 UnpackErrorReason{}, 39 std::string{}))) 40 { 41 auto it = findProperty(container, expectedKey); 42 43 if (it != container.end()) 44 { 45 if constexpr (std::is_pointer_v<ValueType>) 46 { 47 if (const auto* value = std::get_if< 48 std::remove_cv_t<std::remove_pointer_t<ValueType>>>( 49 &it->second)) 50 { 51 outValue = value; 52 } 53 else 54 { 55 onErrorCallback(UnpackErrorReason::wrongType, expectedKey); 56 return false; 57 } 58 } 59 else if constexpr (utility::is_optional_v<ValueType>) 60 { 61 using InnerType = typename ValueType::value_type; 62 static_assert(!std::is_pointer_v<InnerType>, 63 "std::optional<T*> is not supported"); 64 if (const auto value = std::get_if<InnerType>(&it->second)) 65 66 { 67 outValue = *value; 68 } 69 else 70 { 71 onErrorCallback(UnpackErrorReason::wrongType, expectedKey); 72 return false; 73 } 74 } 75 else 76 { 77 if (const auto value = std::get_if<ValueType>(&it->second)) 78 { 79 outValue = *value; 80 } 81 else 82 { 83 onErrorCallback(UnpackErrorReason::wrongType, expectedKey); 84 return false; 85 } 86 } 87 } 88 else if constexpr (!utility::is_optional_v<ValueType> && 89 !std::is_pointer_v<ValueType>) 90 { 91 onErrorCallback(UnpackErrorReason::missingProperty, expectedKey); 92 return false; 93 } 94 95 return true; 96 } 97 98 template <typename OnErrorCallback, typename VariantType, typename ValueType, 99 typename... Args> 100 inline bool readProperties( 101 OnErrorCallback&& onErrorCallback, 102 const std::vector<std::pair<std::string, VariantType>>& container, 103 const std::string& expectedKey, ValueType& outValue, 104 Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus:: 105 UnpackErrorReason{}, 106 std::string{}))) 107 { 108 if (!readProperty(onErrorCallback, container, expectedKey, outValue)) 109 { 110 return false; 111 } 112 113 if constexpr (sizeof...(Args) > 0) 114 { 115 return readProperties(std::forward<OnErrorCallback>(onErrorCallback), 116 container, std::forward<Args>(args)...); 117 } 118 119 return true; 120 } 121 122 template <typename OnErrorCallback, typename VariantType, typename... Args> 123 inline auto unpackPropertiesCommon( 124 OnErrorCallback&& onErrorCallback, 125 const std::vector<std::pair<std::string, VariantType>>& input, 126 Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus:: 127 UnpackErrorReason{}, 128 std::string{}))) 129 { 130 static_assert( 131 sizeof...(Args) % 2 == 0, 132 "Expected number of arguments to be even, but got odd number instead"); 133 134 return details::readProperties( 135 std::forward<OnErrorCallback>(onErrorCallback), input, 136 std::forward<Args>(args)...); 137 } 138 139 } // namespace details 140 141 template <typename VariantType, typename... Args> 142 inline void unpackProperties( 143 const std::vector<std::pair<std::string, VariantType>>& input, 144 Args&&... args) 145 { 146 details::unpackPropertiesCommon( 147 [](const UnpackErrorReason reason, const std::string& property) { 148 throw exception::UnpackPropertyError(property, reason); 149 }, 150 input, std::forward<Args>(args)...); 151 } 152 153 template <typename OnErrorCallback, typename VariantType, typename... Args> 154 inline bool unpackPropertiesNoThrow( 155 OnErrorCallback&& onErrorCallback, 156 const std::vector<std::pair<std::string, VariantType>>& input, 157 Args&&... args) noexcept 158 { 159 return details::unpackPropertiesCommon( 160 std::forward<OnErrorCallback>(onErrorCallback), input, 161 std::forward<Args>(args)...); 162 } 163 164 } // namespace sdbusplus 165