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