1e2362796SWludzik, Jozef #pragma once
2e2362796SWludzik, Jozef
3e2362796SWludzik, Jozef #include <nlohmann/json.hpp>
4e2362796SWludzik, Jozef #include <sdbusplus/message/types.hpp>
5e2362796SWludzik, Jozef
60253f6d3SSzymon Dompke #include <cmath>
70253f6d3SSzymon Dompke #include <limits>
80253f6d3SSzymon Dompke
9e2362796SWludzik, Jozef namespace utils
10e2362796SWludzik, Jozef {
11e2362796SWludzik, Jozef
120253f6d3SSzymon Dompke namespace numeric_literals
130253f6d3SSzymon Dompke {
140253f6d3SSzymon Dompke constexpr std::string_view NaN = "NaN";
150253f6d3SSzymon Dompke constexpr std::string_view infinity = "inf";
160253f6d3SSzymon Dompke constexpr std::string_view infinity_negative = "-inf";
170253f6d3SSzymon Dompke } // namespace numeric_literals
180253f6d3SSzymon Dompke
from_json(const nlohmann::json & j,sdbusplus::message::object_path & o)19e2362796SWludzik, Jozef inline void from_json(const nlohmann::json& j,
20e2362796SWludzik, Jozef sdbusplus::message::object_path& o)
21e2362796SWludzik, Jozef {
22e2362796SWludzik, Jozef o = j.get<std::string>();
23e2362796SWludzik, Jozef }
24e2362796SWludzik, Jozef
from_json(const nlohmann::json & j,std::vector<sdbusplus::message::object_path> & o)25e2362796SWludzik, Jozef inline void from_json(const nlohmann::json& j,
26e2362796SWludzik, Jozef std::vector<sdbusplus::message::object_path>& o)
27e2362796SWludzik, Jozef {
28e2362796SWludzik, Jozef o.clear();
29e2362796SWludzik, Jozef for (const nlohmann::json& item : j)
30e2362796SWludzik, Jozef {
31e2362796SWludzik, Jozef o.emplace_back(item.get<std::string>());
32e2362796SWludzik, Jozef }
33e2362796SWludzik, Jozef }
34e2362796SWludzik, Jozef
to_json(nlohmann::json & j,const double & val)350253f6d3SSzymon Dompke inline void to_json(nlohmann::json& j, const double& val)
360253f6d3SSzymon Dompke {
370253f6d3SSzymon Dompke if (std::isnan(val))
380253f6d3SSzymon Dompke {
390253f6d3SSzymon Dompke j = numeric_literals::NaN;
400253f6d3SSzymon Dompke }
410253f6d3SSzymon Dompke else if (val == std::numeric_limits<double>::infinity())
420253f6d3SSzymon Dompke {
430253f6d3SSzymon Dompke j = numeric_literals::infinity;
440253f6d3SSzymon Dompke }
450253f6d3SSzymon Dompke else if (val == -std::numeric_limits<double>::infinity())
460253f6d3SSzymon Dompke {
470253f6d3SSzymon Dompke j = numeric_literals::infinity_negative;
480253f6d3SSzymon Dompke }
490253f6d3SSzymon Dompke else
500253f6d3SSzymon Dompke {
510253f6d3SSzymon Dompke j = val;
520253f6d3SSzymon Dompke }
530253f6d3SSzymon Dompke }
540253f6d3SSzymon Dompke
from_json(const nlohmann::json & j,double & val)550253f6d3SSzymon Dompke inline void from_json(const nlohmann::json& j, double& val)
560253f6d3SSzymon Dompke {
570253f6d3SSzymon Dompke if (j.is_number())
580253f6d3SSzymon Dompke {
590253f6d3SSzymon Dompke val = j.get<double>();
600253f6d3SSzymon Dompke }
610253f6d3SSzymon Dompke else
620253f6d3SSzymon Dompke {
630253f6d3SSzymon Dompke auto str_val = j.get<std::string>();
640253f6d3SSzymon Dompke if (str_val == numeric_literals::NaN)
650253f6d3SSzymon Dompke {
660253f6d3SSzymon Dompke val = std::numeric_limits<double>::quiet_NaN();
670253f6d3SSzymon Dompke }
680253f6d3SSzymon Dompke else if (str_val == numeric_literals::infinity)
690253f6d3SSzymon Dompke {
700253f6d3SSzymon Dompke val = std::numeric_limits<double>::infinity();
710253f6d3SSzymon Dompke }
720253f6d3SSzymon Dompke else if (str_val == numeric_literals::infinity_negative)
730253f6d3SSzymon Dompke {
740253f6d3SSzymon Dompke val = -std::numeric_limits<double>::infinity();
750253f6d3SSzymon Dompke }
760253f6d3SSzymon Dompke else
770253f6d3SSzymon Dompke {
780253f6d3SSzymon Dompke throw std::invalid_argument("Unknown numeric literal");
790253f6d3SSzymon Dompke }
800253f6d3SSzymon Dompke }
810253f6d3SSzymon Dompke }
820253f6d3SSzymon Dompke
83e2362796SWludzik, Jozef namespace detail
84e2362796SWludzik, Jozef {
85e2362796SWludzik, Jozef
86e2362796SWludzik, Jozef template <class T>
87e2362796SWludzik, Jozef struct has_utils_from_json
88e2362796SWludzik, Jozef {
89e2362796SWludzik, Jozef template <class U>
90e2362796SWludzik, Jozef static U& ref();
91e2362796SWludzik, Jozef
92e2362796SWludzik, Jozef template <class U>
93e2362796SWludzik, Jozef static std::true_type check(
94e2362796SWludzik, Jozef decltype(utils::from_json(ref<const nlohmann::json>(), ref<U>()))*);
95e2362796SWludzik, Jozef
96e2362796SWludzik, Jozef template <class>
97e2362796SWludzik, Jozef static std::false_type check(...);
98e2362796SWludzik, Jozef
99e2362796SWludzik, Jozef static constexpr bool value =
100e2362796SWludzik, Jozef decltype(check<std::decay_t<T>>(nullptr))::value;
101e2362796SWludzik, Jozef };
102e2362796SWludzik, Jozef
103e2362796SWludzik, Jozef template <class T>
104e2362796SWludzik, Jozef constexpr bool has_utils_from_json_v = has_utils_from_json<T>::value;
105e2362796SWludzik, Jozef
1060253f6d3SSzymon Dompke template <class T>
1070253f6d3SSzymon Dompke struct has_utils_to_json
1080253f6d3SSzymon Dompke {
1090253f6d3SSzymon Dompke template <class U>
1100253f6d3SSzymon Dompke static U& ref();
1110253f6d3SSzymon Dompke
1120253f6d3SSzymon Dompke template <class U>
1130253f6d3SSzymon Dompke static std::true_type
1140253f6d3SSzymon Dompke check(decltype(utils::to_json(ref<nlohmann::json>(), ref<const U>()))*);
1150253f6d3SSzymon Dompke
1160253f6d3SSzymon Dompke template <class>
1170253f6d3SSzymon Dompke static std::false_type check(...);
1180253f6d3SSzymon Dompke
1190253f6d3SSzymon Dompke static constexpr bool value =
1200253f6d3SSzymon Dompke decltype(check<std::decay_t<T>>(nullptr))::value;
1210253f6d3SSzymon Dompke };
1220253f6d3SSzymon Dompke
1230253f6d3SSzymon Dompke template <class T>
1240253f6d3SSzymon Dompke constexpr bool has_utils_to_json_v = has_utils_to_json<T>::value;
1250253f6d3SSzymon Dompke
eq(const auto & a,const auto & b)1260253f6d3SSzymon Dompke bool eq(const auto& a, const auto& b)
1270253f6d3SSzymon Dompke {
1280253f6d3SSzymon Dompke if constexpr (std::is_same<std::decay_t<decltype(a)>, double>())
1290253f6d3SSzymon Dompke {
1300253f6d3SSzymon Dompke if (std::isnan(a))
1310253f6d3SSzymon Dompke {
1320253f6d3SSzymon Dompke return std::isnan(b);
1330253f6d3SSzymon Dompke }
1340253f6d3SSzymon Dompke }
1350253f6d3SSzymon Dompke return a == b;
1360253f6d3SSzymon Dompke }
1370253f6d3SSzymon Dompke
138e2362796SWludzik, Jozef } // namespace detail
139e2362796SWludzik, Jozef
140e2362796SWludzik, Jozef template <class, class...>
141e2362796SWludzik, Jozef struct LabeledTuple;
142e2362796SWludzik, Jozef
143e2362796SWludzik, Jozef template <class... Args, class... Labels>
144e2362796SWludzik, Jozef struct LabeledTuple<std::tuple<Args...>, Labels...>
145e2362796SWludzik, Jozef {
146e2362796SWludzik, Jozef static_assert(sizeof...(Args) == sizeof...(Labels));
147e2362796SWludzik, Jozef
148d2238194SKrzysztof Grobelny using tuple_type = std::tuple<Args...>;
149d2238194SKrzysztof Grobelny
150d2238194SKrzysztof Grobelny LabeledTuple() = default;
151d2238194SKrzysztof Grobelny LabeledTuple(const LabeledTuple&) = default;
152d2238194SKrzysztof Grobelny LabeledTuple(LabeledTuple&&) = default;
153d2238194SKrzysztof Grobelny
LabeledTupleutils::LabeledTuple1543a1c297aSPatrick Williams explicit LabeledTuple(tuple_type v) : value(std::move(v)) {}
LabeledTupleutils::LabeledTuple1553a1c297aSPatrick Williams LabeledTuple(Args... args) : value(std::move(args)...) {}
156d2238194SKrzysztof Grobelny
157d2238194SKrzysztof Grobelny LabeledTuple& operator=(const LabeledTuple&) = default;
158d2238194SKrzysztof Grobelny LabeledTuple& operator=(LabeledTuple&&) = default;
159d2238194SKrzysztof Grobelny
to_jsonutils::LabeledTuple160d2238194SKrzysztof Grobelny nlohmann::json to_json() const
161e2362796SWludzik, Jozef {
162e2362796SWludzik, Jozef nlohmann::json j;
163d2238194SKrzysztof Grobelny to_json_all(j, std::make_index_sequence<sizeof...(Args)>());
164e2362796SWludzik, Jozef return j;
165e2362796SWludzik, Jozef }
166e2362796SWludzik, Jozef
to_tupleutils::LabeledTuple167493e62ebSKrzysztof Grobelny const tuple_type& to_tuple() const
168493e62ebSKrzysztof Grobelny {
169493e62ebSKrzysztof Grobelny return value;
170493e62ebSKrzysztof Grobelny }
171493e62ebSKrzysztof Grobelny
from_jsonutils::LabeledTuple172d2238194SKrzysztof Grobelny void from_json(const nlohmann::json& j)
173e2362796SWludzik, Jozef {
174d2238194SKrzysztof Grobelny from_json_all(j, std::make_index_sequence<sizeof...(Args)>());
175d2238194SKrzysztof Grobelny }
176d2238194SKrzysztof Grobelny
dumputils::LabeledTuple1773a617023SSzymon Dompke std::string dump() const
1783a617023SSzymon Dompke {
1793a617023SSzymon Dompke return to_json().dump();
1803a617023SSzymon Dompke }
1813a617023SSzymon Dompke
182d2238194SKrzysztof Grobelny template <size_t Idx>
at_indexutils::LabeledTuple183d2238194SKrzysztof Grobelny const auto& at_index() const
184d2238194SKrzysztof Grobelny {
185d2238194SKrzysztof Grobelny return std::get<Idx>(value);
186d2238194SKrzysztof Grobelny }
187d2238194SKrzysztof Grobelny
188d2238194SKrzysztof Grobelny template <size_t Idx>
at_indexutils::LabeledTuple189d2238194SKrzysztof Grobelny auto& at_index()
190d2238194SKrzysztof Grobelny {
191d2238194SKrzysztof Grobelny return std::get<Idx>(value);
192d2238194SKrzysztof Grobelny }
193d2238194SKrzysztof Grobelny
194d2238194SKrzysztof Grobelny template <class Label>
at_labelutils::LabeledTuple195d2238194SKrzysztof Grobelny const auto& at_label() const
196d2238194SKrzysztof Grobelny {
197d2238194SKrzysztof Grobelny return find_item<0, Label>(*this);
198d2238194SKrzysztof Grobelny }
199d2238194SKrzysztof Grobelny
200d2238194SKrzysztof Grobelny template <class Label>
at_labelutils::LabeledTuple201d2238194SKrzysztof Grobelny auto& at_label()
202d2238194SKrzysztof Grobelny {
203d2238194SKrzysztof Grobelny return find_item<0, Label>(*this);
204d2238194SKrzysztof Grobelny }
205d2238194SKrzysztof Grobelny
operator ==utils::LabeledTuple206d2238194SKrzysztof Grobelny bool operator==(const LabeledTuple& other) const
207d2238194SKrzysztof Grobelny {
208*f535cad6SPatrick Williams return std::apply([&](auto&&... x) {
209*f535cad6SPatrick Williams return std::apply([&](auto&&... y) {
210*f535cad6SPatrick Williams return (true && ... && detail::eq(x, y));
211*f535cad6SPatrick Williams }, value);
212*f535cad6SPatrick Williams }, other.value);
213d2238194SKrzysztof Grobelny }
214d2238194SKrzysztof Grobelny
operator <utils::LabeledTuple215d2238194SKrzysztof Grobelny bool operator<(const LabeledTuple& other) const
216d2238194SKrzysztof Grobelny {
217d2238194SKrzysztof Grobelny return value < other.value;
218e2362796SWludzik, Jozef }
219e2362796SWludzik, Jozef
220e2362796SWludzik, Jozef private:
221e2362796SWludzik, Jozef template <size_t... Idx>
to_json_allutils::LabeledTuple222d2238194SKrzysztof Grobelny void to_json_all(nlohmann::json& j, std::index_sequence<Idx...>) const
223e2362796SWludzik, Jozef {
224d2238194SKrzysztof Grobelny (to_json_item<Idx>(j), ...);
225e2362796SWludzik, Jozef }
226e2362796SWludzik, Jozef
227e2362796SWludzik, Jozef template <size_t Idx>
to_json_itemutils::LabeledTuple228d2238194SKrzysztof Grobelny void to_json_item(nlohmann::json& j) const
229e2362796SWludzik, Jozef {
230e2362796SWludzik, Jozef using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>;
2310253f6d3SSzymon Dompke using T = std::tuple_element_t<Idx, tuple_type>;
2320253f6d3SSzymon Dompke nlohmann::json& item = j[Label::str()];
2330253f6d3SSzymon Dompke if constexpr (detail::has_utils_to_json_v<T>)
2340253f6d3SSzymon Dompke {
2350253f6d3SSzymon Dompke utils::to_json(item, std::get<Idx>(value));
2360253f6d3SSzymon Dompke }
2370253f6d3SSzymon Dompke else
2380253f6d3SSzymon Dompke {
2390253f6d3SSzymon Dompke item = std::get<Idx>(value);
2400253f6d3SSzymon Dompke }
241e2362796SWludzik, Jozef }
242e2362796SWludzik, Jozef
243e2362796SWludzik, Jozef template <size_t... Idx>
from_json_allutils::LabeledTuple244d2238194SKrzysztof Grobelny void from_json_all(const nlohmann::json& j, std::index_sequence<Idx...>)
245e2362796SWludzik, Jozef {
246d2238194SKrzysztof Grobelny (from_json_item<Idx>(j), ...);
247e2362796SWludzik, Jozef }
248e2362796SWludzik, Jozef
249e2362796SWludzik, Jozef template <size_t Idx>
from_json_itemutils::LabeledTuple250d2238194SKrzysztof Grobelny void from_json_item(const nlohmann::json& j)
251e2362796SWludzik, Jozef {
252e2362796SWludzik, Jozef using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>;
253d2238194SKrzysztof Grobelny using T = std::tuple_element_t<Idx, tuple_type>;
254e2362796SWludzik, Jozef const nlohmann::json& item = j.at(Label::str());
255e2362796SWludzik, Jozef if constexpr (detail::has_utils_from_json_v<T>)
256e2362796SWludzik, Jozef {
257e2362796SWludzik, Jozef T& v = std::get<Idx>(value);
258e2362796SWludzik, Jozef utils::from_json(item, v);
259e2362796SWludzik, Jozef }
260e2362796SWludzik, Jozef else
261e2362796SWludzik, Jozef {
262e2362796SWludzik, Jozef std::get<Idx>(value) = item.get<T>();
263e2362796SWludzik, Jozef }
264e2362796SWludzik, Jozef }
265d2238194SKrzysztof Grobelny
266d2238194SKrzysztof Grobelny template <size_t Idx, class Label, class Self>
find_itemutils::LabeledTuple267d2238194SKrzysztof Grobelny static auto& find_item(Self& self)
268d2238194SKrzysztof Grobelny {
269d2238194SKrzysztof Grobelny if constexpr (std::is_same_v<Label, std::tuple_element_t<
270d2238194SKrzysztof Grobelny Idx, std::tuple<Labels...>>>)
271d2238194SKrzysztof Grobelny {
272d2238194SKrzysztof Grobelny return std::get<Idx>(self.value);
273d2238194SKrzysztof Grobelny }
274d2238194SKrzysztof Grobelny else
275d2238194SKrzysztof Grobelny {
276b8cc78ddSKrzysztof Grobelny static_assert(Idx + 1 < sizeof...(Args),
277b8cc78ddSKrzysztof Grobelny "Label not found in LabeledTuple");
278d2238194SKrzysztof Grobelny return find_item<Idx + 1, Label>(self);
279d2238194SKrzysztof Grobelny }
280d2238194SKrzysztof Grobelny }
281d2238194SKrzysztof Grobelny
282d2238194SKrzysztof Grobelny tuple_type value;
283e2362796SWludzik, Jozef };
284e2362796SWludzik, Jozef
285d2238194SKrzysztof Grobelny template <class... Args, class... Labels>
to_json(nlohmann::json & json,const LabeledTuple<std::tuple<Args...>,Labels...> & tuple)286dcc4e193SKrzysztof Grobelny inline void to_json(nlohmann::json& json,
287d2238194SKrzysztof Grobelny const LabeledTuple<std::tuple<Args...>, Labels...>& tuple)
288d2238194SKrzysztof Grobelny {
289d2238194SKrzysztof Grobelny json = tuple.to_json();
290d2238194SKrzysztof Grobelny }
291d2238194SKrzysztof Grobelny
292d2238194SKrzysztof Grobelny template <class... Args, class... Labels>
from_json(const nlohmann::json & json,LabeledTuple<std::tuple<Args...>,Labels...> & tuple)293dcc4e193SKrzysztof Grobelny inline void from_json(const nlohmann::json& json,
294d2238194SKrzysztof Grobelny LabeledTuple<std::tuple<Args...>, Labels...>& tuple)
295d2238194SKrzysztof Grobelny {
296d2238194SKrzysztof Grobelny tuple.from_json(json);
297d2238194SKrzysztof Grobelny }
298d2238194SKrzysztof Grobelny
299e2362796SWludzik, Jozef } // namespace utils
300