xref: /openbmc/sdbusplus/include/sdbusplus/unpack_properties.hpp (revision c8447d52245048934007ab74348c0e11947caf0d)
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