109b88f26SKrzysztof Grobelny #pragma once 209b88f26SKrzysztof Grobelny 309b88f26SKrzysztof Grobelny #include <sdbusplus/exception.hpp> 409b88f26SKrzysztof Grobelny #include <sdbusplus/utility/type_traits.hpp> 509b88f26SKrzysztof Grobelny 609b88f26SKrzysztof Grobelny #include <algorithm> 709b88f26SKrzysztof Grobelny #include <bitset> 809b88f26SKrzysztof Grobelny #include <optional> 909b88f26SKrzysztof Grobelny #include <stdexcept> 1009b88f26SKrzysztof Grobelny #include <string> 1109b88f26SKrzysztof Grobelny #include <string_view> 1209b88f26SKrzysztof Grobelny #include <variant> 1309b88f26SKrzysztof Grobelny 1409b88f26SKrzysztof Grobelny namespace sdbusplus 1509b88f26SKrzysztof Grobelny { 1609b88f26SKrzysztof Grobelny namespace detail 1709b88f26SKrzysztof Grobelny { 1809b88f26SKrzysztof Grobelny 1909b88f26SKrzysztof Grobelny template <typename Variant, typename ValueType> 20*6d83cf53SSzymon Dompke bool getIf(Variant&& variant, ValueType& outValue) noexcept 2109b88f26SKrzysztof Grobelny { 2209b88f26SKrzysztof Grobelny if (auto value = std::get_if<ValueType>(&variant)) 2309b88f26SKrzysztof Grobelny { 2409b88f26SKrzysztof Grobelny outValue = std::move(*value); 2509b88f26SKrzysztof Grobelny return true; 2609b88f26SKrzysztof Grobelny } 2709b88f26SKrzysztof Grobelny 2809b88f26SKrzysztof Grobelny return false; 2909b88f26SKrzysztof Grobelny } 3009b88f26SKrzysztof Grobelny 3109b88f26SKrzysztof Grobelny template <typename Container> 32*6d83cf53SSzymon Dompke auto findProperty(Container&& container, const std::string& key) noexcept 3309b88f26SKrzysztof Grobelny { 3409b88f26SKrzysztof Grobelny if constexpr (utility::has_member_find_v<Container>) 3509b88f26SKrzysztof Grobelny { 3609b88f26SKrzysztof Grobelny return container.find(key); 3709b88f26SKrzysztof Grobelny } 3809b88f26SKrzysztof Grobelny else 3909b88f26SKrzysztof Grobelny { 4009b88f26SKrzysztof Grobelny return std::find_if( 4109b88f26SKrzysztof Grobelny std::begin(container), std::end(container), 4209b88f26SKrzysztof Grobelny [&key](const auto& keyValue) { return keyValue.first == key; }); 4309b88f26SKrzysztof Grobelny } 4409b88f26SKrzysztof Grobelny } 4509b88f26SKrzysztof Grobelny 4609b88f26SKrzysztof Grobelny template <typename Container> 47*6d83cf53SSzymon Dompke bool containsProperty(Container&& container, const std::string& key) noexcept 4809b88f26SKrzysztof Grobelny { 4909b88f26SKrzysztof Grobelny if constexpr (utility::has_member_contains_v<Container>) 5009b88f26SKrzysztof Grobelny { 5109b88f26SKrzysztof Grobelny return container.contains(key); 5209b88f26SKrzysztof Grobelny } 5309b88f26SKrzysztof Grobelny else 5409b88f26SKrzysztof Grobelny { 5509b88f26SKrzysztof Grobelny return findProperty(std::forward<Container>(container), key) != 5609b88f26SKrzysztof Grobelny std::end(container); 5709b88f26SKrzysztof Grobelny } 5809b88f26SKrzysztof Grobelny } 5909b88f26SKrzysztof Grobelny 6009b88f26SKrzysztof Grobelny template <size_t Index, typename Container, size_t N, typename ValueType, 6109b88f26SKrzysztof Grobelny typename... Args> 6209b88f26SKrzysztof Grobelny void readProperties(Container&& container, std::bitset<N>& assigned, 6309b88f26SKrzysztof Grobelny const std::string& expectedKey, ValueType& outValue, 64*6d83cf53SSzymon Dompke Args&&... args) noexcept 6509b88f26SKrzysztof Grobelny { 6609b88f26SKrzysztof Grobelny static_assert(Index < N); 6709b88f26SKrzysztof Grobelny 6809b88f26SKrzysztof Grobelny auto it = findProperty(std::forward<Container>(container), expectedKey); 6909b88f26SKrzysztof Grobelny 7009b88f26SKrzysztof Grobelny if (it != std::end(container)) 7109b88f26SKrzysztof Grobelny { 7209b88f26SKrzysztof Grobelny if (getIf(it->second, outValue)) 7309b88f26SKrzysztof Grobelny { 7409b88f26SKrzysztof Grobelny assigned.set(Index); 7509b88f26SKrzysztof Grobelny } 7609b88f26SKrzysztof Grobelny } 7709b88f26SKrzysztof Grobelny 7809b88f26SKrzysztof Grobelny if constexpr (sizeof...(Args) > 0) 7909b88f26SKrzysztof Grobelny { 8009b88f26SKrzysztof Grobelny readProperties<Index + 1>(std::forward<Container>(container), assigned, 8109b88f26SKrzysztof Grobelny std::forward<Args>(args)...); 8209b88f26SKrzysztof Grobelny } 8309b88f26SKrzysztof Grobelny } 8409b88f26SKrzysztof Grobelny 8509b88f26SKrzysztof Grobelny template <size_t Index, size_t N, typename ValueType, typename... Args> 8609b88f26SKrzysztof Grobelny std::string findMissingProperty(std::bitset<N>& assigned, 8709b88f26SKrzysztof Grobelny const std::string& key, ValueType&, 88*6d83cf53SSzymon Dompke Args&&... args) noexcept 8909b88f26SKrzysztof Grobelny { 9009b88f26SKrzysztof Grobelny static_assert(Index < N); 9109b88f26SKrzysztof Grobelny 9209b88f26SKrzysztof Grobelny if (!assigned.test(Index)) 9309b88f26SKrzysztof Grobelny { 9409b88f26SKrzysztof Grobelny return key; 9509b88f26SKrzysztof Grobelny } 9609b88f26SKrzysztof Grobelny 9709b88f26SKrzysztof Grobelny if constexpr (sizeof...(Args) > 0) 9809b88f26SKrzysztof Grobelny { 9909b88f26SKrzysztof Grobelny return findMissingProperty<Index + 1>(assigned, 10009b88f26SKrzysztof Grobelny std::forward<Args>(args)...); 10109b88f26SKrzysztof Grobelny } 10209b88f26SKrzysztof Grobelny 10309b88f26SKrzysztof Grobelny return {}; 10409b88f26SKrzysztof Grobelny } 10509b88f26SKrzysztof Grobelny 106*6d83cf53SSzymon Dompke template <bool ReturnBadProperty, typename Container, typename... Args> 107*6d83cf53SSzymon Dompke auto unpackPropertiesCommon(Container&& input, 108*6d83cf53SSzymon Dompke Args&&... args) noexcept(ReturnBadProperty) 10909b88f26SKrzysztof Grobelny { 11009b88f26SKrzysztof Grobelny static_assert(sizeof...(Args) % 2 == 0); 11109b88f26SKrzysztof Grobelny 11209b88f26SKrzysztof Grobelny auto assigned = std::bitset<sizeof...(Args) / 2>(); 11309b88f26SKrzysztof Grobelny 11409b88f26SKrzysztof Grobelny detail::readProperties<0>(input, assigned, std::forward<Args>(args)...); 11509b88f26SKrzysztof Grobelny 11609b88f26SKrzysztof Grobelny if (!assigned.all()) 11709b88f26SKrzysztof Grobelny { 118*6d83cf53SSzymon Dompke auto missingProperty = detail::findMissingProperty<0>( 11909b88f26SKrzysztof Grobelny assigned, std::forward<Args>(args)...); 12009b88f26SKrzysztof Grobelny 121*6d83cf53SSzymon Dompke if constexpr (ReturnBadProperty) 122*6d83cf53SSzymon Dompke { 123*6d83cf53SSzymon Dompke return std::optional{missingProperty}; 124*6d83cf53SSzymon Dompke } 125*6d83cf53SSzymon Dompke else 126*6d83cf53SSzymon Dompke { 12709b88f26SKrzysztof Grobelny if (detail::containsProperty(std::forward<Container>(input), 12809b88f26SKrzysztof Grobelny missingProperty)) 12909b88f26SKrzysztof Grobelny { 13009b88f26SKrzysztof Grobelny throw exception::UnpackPropertyError( 13109b88f26SKrzysztof Grobelny missingProperty, 13209b88f26SKrzysztof Grobelny exception::UnpackPropertyError::reasonTypeNotMatched); 13309b88f26SKrzysztof Grobelny } 13409b88f26SKrzysztof Grobelny else 13509b88f26SKrzysztof Grobelny { 13609b88f26SKrzysztof Grobelny throw exception::UnpackPropertyError( 13709b88f26SKrzysztof Grobelny missingProperty, 13809b88f26SKrzysztof Grobelny exception::UnpackPropertyError::reasonMissingProperty); 13909b88f26SKrzysztof Grobelny } 14009b88f26SKrzysztof Grobelny } 14109b88f26SKrzysztof Grobelny } 142*6d83cf53SSzymon Dompke return std::conditional_t<ReturnBadProperty, std::optional<std::string>, 143*6d83cf53SSzymon Dompke void>(); 144*6d83cf53SSzymon Dompke } 145*6d83cf53SSzymon Dompke 146*6d83cf53SSzymon Dompke } // namespace detail 147*6d83cf53SSzymon Dompke 148*6d83cf53SSzymon Dompke template <typename Container, typename... Args> 149*6d83cf53SSzymon Dompke void unpackProperties(Container&& input, Args&&... args) 150*6d83cf53SSzymon Dompke { 151*6d83cf53SSzymon Dompke detail::unpackPropertiesCommon<false, Container, Args...>( 152*6d83cf53SSzymon Dompke std::forward<Container>(input), std::forward<Args>(args)...); 153*6d83cf53SSzymon Dompke } 154*6d83cf53SSzymon Dompke 155*6d83cf53SSzymon Dompke template <typename Container, typename... Args> 156*6d83cf53SSzymon Dompke std::optional<std::string> unpackPropertiesNoThrow(Container&& input, 157*6d83cf53SSzymon Dompke Args&&... args) noexcept 158*6d83cf53SSzymon Dompke { 159*6d83cf53SSzymon Dompke return detail::unpackPropertiesCommon<true, Container, Args...>( 160*6d83cf53SSzymon Dompke std::forward<Container>(input), std::forward<Args>(args)...); 161*6d83cf53SSzymon Dompke } 16209b88f26SKrzysztof Grobelny 16309b88f26SKrzysztof Grobelny } // namespace sdbusplus 164