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