xref: /openbmc/telemetry/src/utils/labeled_tuple.hpp (revision 493e62eb2f2ff6cbf3282b9cb98ebe6e520b88fc)
1e2362796SWludzik, Jozef #pragma once
2e2362796SWludzik, Jozef 
3e2362796SWludzik, Jozef #include <nlohmann/json.hpp>
4e2362796SWludzik, Jozef #include <sdbusplus/message/types.hpp>
5e2362796SWludzik, Jozef 
6e2362796SWludzik, Jozef namespace utils
7e2362796SWludzik, Jozef {
8e2362796SWludzik, Jozef 
9e2362796SWludzik, Jozef inline void from_json(const nlohmann::json& j,
10e2362796SWludzik, Jozef                       sdbusplus::message::object_path& o)
11e2362796SWludzik, Jozef {
12e2362796SWludzik, Jozef     o = j.get<std::string>();
13e2362796SWludzik, Jozef }
14e2362796SWludzik, Jozef 
15e2362796SWludzik, Jozef inline void from_json(const nlohmann::json& j,
16e2362796SWludzik, Jozef                       std::vector<sdbusplus::message::object_path>& o)
17e2362796SWludzik, Jozef {
18e2362796SWludzik, Jozef     o.clear();
19e2362796SWludzik, Jozef     for (const nlohmann::json& item : j)
20e2362796SWludzik, Jozef     {
21e2362796SWludzik, Jozef         o.emplace_back(item.get<std::string>());
22e2362796SWludzik, Jozef     }
23e2362796SWludzik, Jozef }
24e2362796SWludzik, Jozef 
25e2362796SWludzik, Jozef namespace detail
26e2362796SWludzik, Jozef {
27e2362796SWludzik, Jozef 
28e2362796SWludzik, Jozef template <class T>
29e2362796SWludzik, Jozef struct has_utils_from_json
30e2362796SWludzik, Jozef {
31e2362796SWludzik, Jozef     template <class U>
32e2362796SWludzik, Jozef     static U& ref();
33e2362796SWludzik, Jozef 
34e2362796SWludzik, Jozef     template <class U>
35e2362796SWludzik, Jozef     static std::true_type check(
36e2362796SWludzik, Jozef         decltype(utils::from_json(ref<const nlohmann::json>(), ref<U>()))*);
37e2362796SWludzik, Jozef 
38e2362796SWludzik, Jozef     template <class>
39e2362796SWludzik, Jozef     static std::false_type check(...);
40e2362796SWludzik, Jozef 
41e2362796SWludzik, Jozef     static constexpr bool value =
42e2362796SWludzik, Jozef         decltype(check<std::decay_t<T>>(nullptr))::value;
43e2362796SWludzik, Jozef };
44e2362796SWludzik, Jozef 
45e2362796SWludzik, Jozef template <class T>
46e2362796SWludzik, Jozef constexpr bool has_utils_from_json_v = has_utils_from_json<T>::value;
47e2362796SWludzik, Jozef 
48e2362796SWludzik, Jozef } // namespace detail
49e2362796SWludzik, Jozef 
50e2362796SWludzik, Jozef template <class, class...>
51e2362796SWludzik, Jozef struct LabeledTuple;
52e2362796SWludzik, Jozef 
53e2362796SWludzik, Jozef template <class... Args, class... Labels>
54e2362796SWludzik, Jozef struct LabeledTuple<std::tuple<Args...>, Labels...>
55e2362796SWludzik, Jozef {
56e2362796SWludzik, Jozef     static_assert(sizeof...(Args) == sizeof...(Labels));
57e2362796SWludzik, Jozef 
58d2238194SKrzysztof Grobelny     using tuple_type = std::tuple<Args...>;
59d2238194SKrzysztof Grobelny 
60d2238194SKrzysztof Grobelny     LabeledTuple() = default;
61d2238194SKrzysztof Grobelny     LabeledTuple(const LabeledTuple&) = default;
62d2238194SKrzysztof Grobelny     LabeledTuple(LabeledTuple&&) = default;
63d2238194SKrzysztof Grobelny 
64fbeb5bf4SKrzysztof Grobelny     explicit LabeledTuple(tuple_type v) : value(std::move(v))
65d2238194SKrzysztof Grobelny     {}
66d2238194SKrzysztof Grobelny     LabeledTuple(Args... args) : value(std::move(args)...)
67d2238194SKrzysztof Grobelny     {}
68d2238194SKrzysztof Grobelny 
69d2238194SKrzysztof Grobelny     LabeledTuple& operator=(const LabeledTuple&) = default;
70d2238194SKrzysztof Grobelny     LabeledTuple& operator=(LabeledTuple&&) = default;
71d2238194SKrzysztof Grobelny 
72d2238194SKrzysztof Grobelny     nlohmann::json to_json() const
73e2362796SWludzik, Jozef     {
74e2362796SWludzik, Jozef         nlohmann::json j;
75d2238194SKrzysztof Grobelny         to_json_all(j, std::make_index_sequence<sizeof...(Args)>());
76e2362796SWludzik, Jozef         return j;
77e2362796SWludzik, Jozef     }
78e2362796SWludzik, Jozef 
79*493e62ebSKrzysztof Grobelny     const tuple_type& to_tuple() const
80*493e62ebSKrzysztof Grobelny     {
81*493e62ebSKrzysztof Grobelny         return value;
82*493e62ebSKrzysztof Grobelny     }
83*493e62ebSKrzysztof Grobelny 
84d2238194SKrzysztof Grobelny     void from_json(const nlohmann::json& j)
85e2362796SWludzik, Jozef     {
86d2238194SKrzysztof Grobelny         from_json_all(j, std::make_index_sequence<sizeof...(Args)>());
87d2238194SKrzysztof Grobelny     }
88d2238194SKrzysztof Grobelny 
893a617023SSzymon Dompke     std::string dump() const
903a617023SSzymon Dompke     {
913a617023SSzymon Dompke         return to_json().dump();
923a617023SSzymon Dompke     }
933a617023SSzymon Dompke 
94d2238194SKrzysztof Grobelny     template <size_t Idx>
95d2238194SKrzysztof Grobelny     const auto& at_index() const
96d2238194SKrzysztof Grobelny     {
97d2238194SKrzysztof Grobelny         return std::get<Idx>(value);
98d2238194SKrzysztof Grobelny     }
99d2238194SKrzysztof Grobelny 
100d2238194SKrzysztof Grobelny     template <size_t Idx>
101d2238194SKrzysztof Grobelny     auto& at_index()
102d2238194SKrzysztof Grobelny     {
103d2238194SKrzysztof Grobelny         return std::get<Idx>(value);
104d2238194SKrzysztof Grobelny     }
105d2238194SKrzysztof Grobelny 
106d2238194SKrzysztof Grobelny     template <class Label>
107d2238194SKrzysztof Grobelny     const auto& at_label() const
108d2238194SKrzysztof Grobelny     {
109d2238194SKrzysztof Grobelny         return find_item<0, Label>(*this);
110d2238194SKrzysztof Grobelny     }
111d2238194SKrzysztof Grobelny 
112d2238194SKrzysztof Grobelny     template <class Label>
113d2238194SKrzysztof Grobelny     auto& at_label()
114d2238194SKrzysztof Grobelny     {
115d2238194SKrzysztof Grobelny         return find_item<0, Label>(*this);
116d2238194SKrzysztof Grobelny     }
117d2238194SKrzysztof Grobelny 
118d2238194SKrzysztof Grobelny     bool operator==(const LabeledTuple& other) const
119d2238194SKrzysztof Grobelny     {
120d2238194SKrzysztof Grobelny         return value == other.value;
121d2238194SKrzysztof Grobelny     }
122d2238194SKrzysztof Grobelny 
123d2238194SKrzysztof Grobelny     bool operator<(const LabeledTuple& other) const
124d2238194SKrzysztof Grobelny     {
125d2238194SKrzysztof Grobelny         return value < other.value;
126e2362796SWludzik, Jozef     }
127e2362796SWludzik, Jozef 
128e2362796SWludzik, Jozef   private:
129e2362796SWludzik, Jozef     template <size_t... Idx>
130d2238194SKrzysztof Grobelny     void to_json_all(nlohmann::json& j, std::index_sequence<Idx...>) const
131e2362796SWludzik, Jozef     {
132d2238194SKrzysztof Grobelny         (to_json_item<Idx>(j), ...);
133e2362796SWludzik, Jozef     }
134e2362796SWludzik, Jozef 
135e2362796SWludzik, Jozef     template <size_t Idx>
136d2238194SKrzysztof Grobelny     void to_json_item(nlohmann::json& j) const
137e2362796SWludzik, Jozef     {
138e2362796SWludzik, Jozef         using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>;
139d2238194SKrzysztof Grobelny         j[Label::str()] = std::get<Idx>(value);
140e2362796SWludzik, Jozef     }
141e2362796SWludzik, Jozef 
142e2362796SWludzik, Jozef     template <size_t... Idx>
143d2238194SKrzysztof Grobelny     void from_json_all(const nlohmann::json& j, std::index_sequence<Idx...>)
144e2362796SWludzik, Jozef     {
145d2238194SKrzysztof Grobelny         (from_json_item<Idx>(j), ...);
146e2362796SWludzik, Jozef     }
147e2362796SWludzik, Jozef 
148e2362796SWludzik, Jozef     template <size_t Idx>
149d2238194SKrzysztof Grobelny     void from_json_item(const nlohmann::json& j)
150e2362796SWludzik, Jozef     {
151e2362796SWludzik, Jozef         using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>;
152d2238194SKrzysztof Grobelny         using T = std::tuple_element_t<Idx, tuple_type>;
153e2362796SWludzik, Jozef         const nlohmann::json& item = j.at(Label::str());
154e2362796SWludzik, Jozef         if constexpr (detail::has_utils_from_json_v<T>)
155e2362796SWludzik, Jozef         {
156e2362796SWludzik, Jozef             T& v = std::get<Idx>(value);
157e2362796SWludzik, Jozef             utils::from_json(item, v);
158e2362796SWludzik, Jozef         }
159e2362796SWludzik, Jozef         else
160e2362796SWludzik, Jozef         {
161e2362796SWludzik, Jozef             std::get<Idx>(value) = item.get<T>();
162e2362796SWludzik, Jozef         }
163e2362796SWludzik, Jozef     }
164d2238194SKrzysztof Grobelny 
165d2238194SKrzysztof Grobelny     template <size_t Idx, class Label, class Self>
166d2238194SKrzysztof Grobelny     static auto& find_item(Self& self)
167d2238194SKrzysztof Grobelny     {
168d2238194SKrzysztof Grobelny         if constexpr (std::is_same_v<Label, std::tuple_element_t<
169d2238194SKrzysztof Grobelny                                                 Idx, std::tuple<Labels...>>>)
170d2238194SKrzysztof Grobelny         {
171d2238194SKrzysztof Grobelny             return std::get<Idx>(self.value);
172d2238194SKrzysztof Grobelny         }
173d2238194SKrzysztof Grobelny         else
174d2238194SKrzysztof Grobelny         {
175b8cc78ddSKrzysztof Grobelny             static_assert(Idx + 1 < sizeof...(Args),
176b8cc78ddSKrzysztof Grobelny                           "Label not found in LabeledTuple");
177d2238194SKrzysztof Grobelny             return find_item<Idx + 1, Label>(self);
178d2238194SKrzysztof Grobelny         }
179d2238194SKrzysztof Grobelny     }
180d2238194SKrzysztof Grobelny 
181d2238194SKrzysztof Grobelny     tuple_type value;
182e2362796SWludzik, Jozef };
183e2362796SWludzik, Jozef 
184d2238194SKrzysztof Grobelny template <class... Args, class... Labels>
185dcc4e193SKrzysztof Grobelny inline void to_json(nlohmann::json& json,
186d2238194SKrzysztof Grobelny                     const LabeledTuple<std::tuple<Args...>, Labels...>& tuple)
187d2238194SKrzysztof Grobelny {
188d2238194SKrzysztof Grobelny     json = tuple.to_json();
189d2238194SKrzysztof Grobelny }
190d2238194SKrzysztof Grobelny 
191d2238194SKrzysztof Grobelny template <class... Args, class... Labels>
192dcc4e193SKrzysztof Grobelny inline void from_json(const nlohmann::json& json,
193d2238194SKrzysztof Grobelny                       LabeledTuple<std::tuple<Args...>, Labels...>& tuple)
194d2238194SKrzysztof Grobelny {
195d2238194SKrzysztof Grobelny     tuple.from_json(json);
196d2238194SKrzysztof Grobelny }
197d2238194SKrzysztof Grobelny 
198e2362796SWludzik, Jozef } // namespace utils
199