blob: 2183aceeeb14514ee7993805b038c3b4edc65790 [file] [log] [blame]
#pragma once
#include <sdbusplus/exception.hpp>
#include <sdbusplus/utility/type_traits.hpp>
#include <algorithm>
#include <bitset>
#include <optional>
#include <stdexcept>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
namespace sdbusplus
{
namespace details
{
template <typename VariantType>
inline auto findProperty(
const std::vector<std::pair<std::string, VariantType>>& container,
const std::string& key) noexcept
{
return std::find_if(
container.begin(), container.end(),
[&key](const auto& keyValue) { return keyValue.first == key; });
}
template <typename OnErrorCallback, typename VariantType, typename ValueType>
inline bool readProperty(
const OnErrorCallback& onErrorCallback,
const std::vector<std::pair<std::string, VariantType>>& container,
const std::string& expectedKey,
ValueType&
outValue) noexcept(noexcept(onErrorCallback(sdbusplus::
UnpackErrorReason{},
std::string{})))
{
auto it = findProperty(container, expectedKey);
if (it != container.end())
{
if constexpr (std::is_pointer_v<ValueType>)
{
if (const auto* value = std::get_if<
std::remove_cv_t<std::remove_pointer_t<ValueType>>>(
&it->second))
{
outValue = value;
}
else
{
onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
return false;
}
}
else if constexpr (utility::is_optional_v<ValueType>)
{
using InnerType = typename ValueType::value_type;
static_assert(!std::is_pointer_v<InnerType>,
"std::optional<T*> is not supported");
if (const auto value = std::get_if<InnerType>(&it->second))
{
outValue = *value;
}
else
{
onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
return false;
}
}
else
{
if (const auto value = std::get_if<ValueType>(&it->second))
{
outValue = *value;
}
else
{
onErrorCallback(UnpackErrorReason::wrongType, expectedKey);
return false;
}
}
}
else if constexpr (!utility::is_optional_v<ValueType> &&
!std::is_pointer_v<ValueType>)
{
onErrorCallback(UnpackErrorReason::missingProperty, expectedKey);
return false;
}
return true;
}
template <typename OnErrorCallback, typename VariantType, typename ValueType,
typename... Args>
inline bool readProperties(
OnErrorCallback&& onErrorCallback,
const std::vector<std::pair<std::string, VariantType>>& container,
const std::string& expectedKey, ValueType& outValue,
Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
UnpackErrorReason{},
std::string{})))
{
if (!readProperty(onErrorCallback, container, expectedKey, outValue))
{
return false;
}
if constexpr (sizeof...(Args) > 0)
{
return readProperties(std::forward<OnErrorCallback>(onErrorCallback),
container, std::forward<Args>(args)...);
}
return true;
}
template <typename OnErrorCallback, typename VariantType, typename... Args>
inline auto unpackPropertiesCommon(
OnErrorCallback&& onErrorCallback,
const std::vector<std::pair<std::string, VariantType>>& input,
Args&&... args) noexcept(noexcept(onErrorCallback(sdbusplus::
UnpackErrorReason{},
std::string{})))
{
static_assert(
sizeof...(Args) % 2 == 0,
"Expected number of arguments to be even, but got odd number instead");
return details::readProperties(
std::forward<OnErrorCallback>(onErrorCallback), input,
std::forward<Args>(args)...);
}
} // namespace details
template <typename VariantType, typename... Args>
inline void unpackProperties(
const std::vector<std::pair<std::string, VariantType>>& input,
Args&&... args)
{
details::unpackPropertiesCommon(
[](const UnpackErrorReason reason, const std::string& property) {
throw exception::UnpackPropertyError(property, reason);
},
input, std::forward<Args>(args)...);
}
template <typename OnErrorCallback, typename VariantType, typename... Args>
inline bool unpackPropertiesNoThrow(
OnErrorCallback&& onErrorCallback,
const std::vector<std::pair<std::string, VariantType>>& input,
Args&&... args) noexcept
{
return details::unpackPropertiesCommon(
std::forward<OnErrorCallback>(onErrorCallback), input,
std::forward<Args>(args)...);
}
} // namespace sdbusplus