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 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 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 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 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 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 154*3a1c297aSPatrick Williams explicit LabeledTuple(tuple_type v) : value(std::move(v)) {} 155*3a1c297aSPatrick 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 160d2238194SKrzysztof 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 167493e62ebSKrzysztof Grobelny const tuple_type& to_tuple() const 168493e62ebSKrzysztof Grobelny { 169493e62ebSKrzysztof Grobelny return value; 170493e62ebSKrzysztof Grobelny } 171493e62ebSKrzysztof Grobelny 172d2238194SKrzysztof 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 1773a617023SSzymon Dompke std::string dump() const 1783a617023SSzymon Dompke { 1793a617023SSzymon Dompke return to_json().dump(); 1803a617023SSzymon Dompke } 1813a617023SSzymon Dompke 182d2238194SKrzysztof Grobelny template <size_t Idx> 183d2238194SKrzysztof 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> 189d2238194SKrzysztof Grobelny auto& at_index() 190d2238194SKrzysztof Grobelny { 191d2238194SKrzysztof Grobelny return std::get<Idx>(value); 192d2238194SKrzysztof Grobelny } 193d2238194SKrzysztof Grobelny 194d2238194SKrzysztof Grobelny template <class Label> 195d2238194SKrzysztof 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> 201d2238194SKrzysztof Grobelny auto& at_label() 202d2238194SKrzysztof Grobelny { 203d2238194SKrzysztof Grobelny return find_item<0, Label>(*this); 204d2238194SKrzysztof Grobelny } 205d2238194SKrzysztof Grobelny 206d2238194SKrzysztof Grobelny bool operator==(const LabeledTuple& other) const 207d2238194SKrzysztof Grobelny { 2080253f6d3SSzymon Dompke return std::apply( 2090253f6d3SSzymon Dompke [&](auto&&... x) { 2100253f6d3SSzymon Dompke return std::apply( 211*3a1c297aSPatrick Williams [&](auto&&... y) { return (true && ... && detail::eq(x, y)); }, 2120253f6d3SSzymon Dompke value); 2130253f6d3SSzymon Dompke }, 2140253f6d3SSzymon Dompke other.value); 215d2238194SKrzysztof Grobelny } 216d2238194SKrzysztof Grobelny 217d2238194SKrzysztof Grobelny bool operator<(const LabeledTuple& other) const 218d2238194SKrzysztof Grobelny { 219d2238194SKrzysztof Grobelny return value < other.value; 220e2362796SWludzik, Jozef } 221e2362796SWludzik, Jozef 222e2362796SWludzik, Jozef private: 223e2362796SWludzik, Jozef template <size_t... Idx> 224d2238194SKrzysztof Grobelny void to_json_all(nlohmann::json& j, std::index_sequence<Idx...>) const 225e2362796SWludzik, Jozef { 226d2238194SKrzysztof Grobelny (to_json_item<Idx>(j), ...); 227e2362796SWludzik, Jozef } 228e2362796SWludzik, Jozef 229e2362796SWludzik, Jozef template <size_t Idx> 230d2238194SKrzysztof Grobelny void to_json_item(nlohmann::json& j) const 231e2362796SWludzik, Jozef { 232e2362796SWludzik, Jozef using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>; 2330253f6d3SSzymon Dompke using T = std::tuple_element_t<Idx, tuple_type>; 2340253f6d3SSzymon Dompke nlohmann::json& item = j[Label::str()]; 2350253f6d3SSzymon Dompke if constexpr (detail::has_utils_to_json_v<T>) 2360253f6d3SSzymon Dompke { 2370253f6d3SSzymon Dompke utils::to_json(item, std::get<Idx>(value)); 2380253f6d3SSzymon Dompke } 2390253f6d3SSzymon Dompke else 2400253f6d3SSzymon Dompke { 2410253f6d3SSzymon Dompke item = std::get<Idx>(value); 2420253f6d3SSzymon Dompke } 243e2362796SWludzik, Jozef } 244e2362796SWludzik, Jozef 245e2362796SWludzik, Jozef template <size_t... Idx> 246d2238194SKrzysztof Grobelny void from_json_all(const nlohmann::json& j, std::index_sequence<Idx...>) 247e2362796SWludzik, Jozef { 248d2238194SKrzysztof Grobelny (from_json_item<Idx>(j), ...); 249e2362796SWludzik, Jozef } 250e2362796SWludzik, Jozef 251e2362796SWludzik, Jozef template <size_t Idx> 252d2238194SKrzysztof Grobelny void from_json_item(const nlohmann::json& j) 253e2362796SWludzik, Jozef { 254e2362796SWludzik, Jozef using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>; 255d2238194SKrzysztof Grobelny using T = std::tuple_element_t<Idx, tuple_type>; 256e2362796SWludzik, Jozef const nlohmann::json& item = j.at(Label::str()); 257e2362796SWludzik, Jozef if constexpr (detail::has_utils_from_json_v<T>) 258e2362796SWludzik, Jozef { 259e2362796SWludzik, Jozef T& v = std::get<Idx>(value); 260e2362796SWludzik, Jozef utils::from_json(item, v); 261e2362796SWludzik, Jozef } 262e2362796SWludzik, Jozef else 263e2362796SWludzik, Jozef { 264e2362796SWludzik, Jozef std::get<Idx>(value) = item.get<T>(); 265e2362796SWludzik, Jozef } 266e2362796SWludzik, Jozef } 267d2238194SKrzysztof Grobelny 268d2238194SKrzysztof Grobelny template <size_t Idx, class Label, class Self> 269d2238194SKrzysztof Grobelny static auto& find_item(Self& self) 270d2238194SKrzysztof Grobelny { 271d2238194SKrzysztof Grobelny if constexpr (std::is_same_v<Label, std::tuple_element_t< 272d2238194SKrzysztof Grobelny Idx, std::tuple<Labels...>>>) 273d2238194SKrzysztof Grobelny { 274d2238194SKrzysztof Grobelny return std::get<Idx>(self.value); 275d2238194SKrzysztof Grobelny } 276d2238194SKrzysztof Grobelny else 277d2238194SKrzysztof Grobelny { 278b8cc78ddSKrzysztof Grobelny static_assert(Idx + 1 < sizeof...(Args), 279b8cc78ddSKrzysztof Grobelny "Label not found in LabeledTuple"); 280d2238194SKrzysztof Grobelny return find_item<Idx + 1, Label>(self); 281d2238194SKrzysztof Grobelny } 282d2238194SKrzysztof Grobelny } 283d2238194SKrzysztof Grobelny 284d2238194SKrzysztof Grobelny tuple_type value; 285e2362796SWludzik, Jozef }; 286e2362796SWludzik, Jozef 287d2238194SKrzysztof Grobelny template <class... Args, class... Labels> 288dcc4e193SKrzysztof Grobelny inline void to_json(nlohmann::json& json, 289d2238194SKrzysztof Grobelny const LabeledTuple<std::tuple<Args...>, Labels...>& tuple) 290d2238194SKrzysztof Grobelny { 291d2238194SKrzysztof Grobelny json = tuple.to_json(); 292d2238194SKrzysztof Grobelny } 293d2238194SKrzysztof Grobelny 294d2238194SKrzysztof Grobelny template <class... Args, class... Labels> 295dcc4e193SKrzysztof Grobelny inline void from_json(const nlohmann::json& json, 296d2238194SKrzysztof Grobelny LabeledTuple<std::tuple<Args...>, Labels...>& tuple) 297d2238194SKrzysztof Grobelny { 298d2238194SKrzysztof Grobelny tuple.from_json(json); 299d2238194SKrzysztof Grobelny } 300d2238194SKrzysztof Grobelny 301e2362796SWludzik, Jozef } // namespace utils 302