1e2362796SWludzik, Jozef #pragma once 2e2362796SWludzik, Jozef 3e2362796SWludzik, Jozef #include <nlohmann/json.hpp> 4e2362796SWludzik, Jozef #include <sdbusplus/message/types.hpp> 5e2362796SWludzik, Jozef 6*0253f6d3SSzymon Dompke #include <cmath> 7*0253f6d3SSzymon Dompke #include <limits> 8*0253f6d3SSzymon Dompke 9e2362796SWludzik, Jozef namespace utils 10e2362796SWludzik, Jozef { 11e2362796SWludzik, Jozef 12*0253f6d3SSzymon Dompke namespace numeric_literals 13*0253f6d3SSzymon Dompke { 14*0253f6d3SSzymon Dompke constexpr std::string_view NaN = "NaN"; 15*0253f6d3SSzymon Dompke constexpr std::string_view infinity = "inf"; 16*0253f6d3SSzymon Dompke constexpr std::string_view infinity_negative = "-inf"; 17*0253f6d3SSzymon Dompke } // namespace numeric_literals 18*0253f6d3SSzymon 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 35*0253f6d3SSzymon Dompke inline void to_json(nlohmann::json& j, const double& val) 36*0253f6d3SSzymon Dompke { 37*0253f6d3SSzymon Dompke if (std::isnan(val)) 38*0253f6d3SSzymon Dompke { 39*0253f6d3SSzymon Dompke j = numeric_literals::NaN; 40*0253f6d3SSzymon Dompke } 41*0253f6d3SSzymon Dompke else if (val == std::numeric_limits<double>::infinity()) 42*0253f6d3SSzymon Dompke { 43*0253f6d3SSzymon Dompke j = numeric_literals::infinity; 44*0253f6d3SSzymon Dompke } 45*0253f6d3SSzymon Dompke else if (val == -std::numeric_limits<double>::infinity()) 46*0253f6d3SSzymon Dompke { 47*0253f6d3SSzymon Dompke j = numeric_literals::infinity_negative; 48*0253f6d3SSzymon Dompke } 49*0253f6d3SSzymon Dompke else 50*0253f6d3SSzymon Dompke { 51*0253f6d3SSzymon Dompke j = val; 52*0253f6d3SSzymon Dompke } 53*0253f6d3SSzymon Dompke } 54*0253f6d3SSzymon Dompke 55*0253f6d3SSzymon Dompke inline void from_json(const nlohmann::json& j, double& val) 56*0253f6d3SSzymon Dompke { 57*0253f6d3SSzymon Dompke if (j.is_number()) 58*0253f6d3SSzymon Dompke { 59*0253f6d3SSzymon Dompke val = j.get<double>(); 60*0253f6d3SSzymon Dompke } 61*0253f6d3SSzymon Dompke else 62*0253f6d3SSzymon Dompke { 63*0253f6d3SSzymon Dompke auto str_val = j.get<std::string>(); 64*0253f6d3SSzymon Dompke if (str_val == numeric_literals::NaN) 65*0253f6d3SSzymon Dompke { 66*0253f6d3SSzymon Dompke val = std::numeric_limits<double>::quiet_NaN(); 67*0253f6d3SSzymon Dompke } 68*0253f6d3SSzymon Dompke else if (str_val == numeric_literals::infinity) 69*0253f6d3SSzymon Dompke { 70*0253f6d3SSzymon Dompke val = std::numeric_limits<double>::infinity(); 71*0253f6d3SSzymon Dompke } 72*0253f6d3SSzymon Dompke else if (str_val == numeric_literals::infinity_negative) 73*0253f6d3SSzymon Dompke { 74*0253f6d3SSzymon Dompke val = -std::numeric_limits<double>::infinity(); 75*0253f6d3SSzymon Dompke } 76*0253f6d3SSzymon Dompke else 77*0253f6d3SSzymon Dompke { 78*0253f6d3SSzymon Dompke throw std::invalid_argument("Unknown numeric literal"); 79*0253f6d3SSzymon Dompke } 80*0253f6d3SSzymon Dompke } 81*0253f6d3SSzymon Dompke } 82*0253f6d3SSzymon 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 106*0253f6d3SSzymon Dompke template <class T> 107*0253f6d3SSzymon Dompke struct has_utils_to_json 108*0253f6d3SSzymon Dompke { 109*0253f6d3SSzymon Dompke template <class U> 110*0253f6d3SSzymon Dompke static U& ref(); 111*0253f6d3SSzymon Dompke 112*0253f6d3SSzymon Dompke template <class U> 113*0253f6d3SSzymon Dompke static std::true_type 114*0253f6d3SSzymon Dompke check(decltype(utils::to_json(ref<nlohmann::json>(), ref<const U>()))*); 115*0253f6d3SSzymon Dompke 116*0253f6d3SSzymon Dompke template <class> 117*0253f6d3SSzymon Dompke static std::false_type check(...); 118*0253f6d3SSzymon Dompke 119*0253f6d3SSzymon Dompke static constexpr bool value = 120*0253f6d3SSzymon Dompke decltype(check<std::decay_t<T>>(nullptr))::value; 121*0253f6d3SSzymon Dompke }; 122*0253f6d3SSzymon Dompke 123*0253f6d3SSzymon Dompke template <class T> 124*0253f6d3SSzymon Dompke constexpr bool has_utils_to_json_v = has_utils_to_json<T>::value; 125*0253f6d3SSzymon Dompke 126*0253f6d3SSzymon Dompke bool eq(const auto& a, const auto& b) 127*0253f6d3SSzymon Dompke { 128*0253f6d3SSzymon Dompke if constexpr (std::is_same<std::decay_t<decltype(a)>, double>()) 129*0253f6d3SSzymon Dompke { 130*0253f6d3SSzymon Dompke if (std::isnan(a)) 131*0253f6d3SSzymon Dompke { 132*0253f6d3SSzymon Dompke return std::isnan(b); 133*0253f6d3SSzymon Dompke } 134*0253f6d3SSzymon Dompke } 135*0253f6d3SSzymon Dompke return a == b; 136*0253f6d3SSzymon Dompke } 137*0253f6d3SSzymon 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 154fbeb5bf4SKrzysztof Grobelny explicit LabeledTuple(tuple_type v) : value(std::move(v)) 155d2238194SKrzysztof Grobelny {} 156d2238194SKrzysztof Grobelny LabeledTuple(Args... args) : value(std::move(args)...) 157d2238194SKrzysztof Grobelny {} 158d2238194SKrzysztof Grobelny 159d2238194SKrzysztof Grobelny LabeledTuple& operator=(const LabeledTuple&) = default; 160d2238194SKrzysztof Grobelny LabeledTuple& operator=(LabeledTuple&&) = default; 161d2238194SKrzysztof Grobelny 162d2238194SKrzysztof Grobelny nlohmann::json to_json() const 163e2362796SWludzik, Jozef { 164e2362796SWludzik, Jozef nlohmann::json j; 165d2238194SKrzysztof Grobelny to_json_all(j, std::make_index_sequence<sizeof...(Args)>()); 166e2362796SWludzik, Jozef return j; 167e2362796SWludzik, Jozef } 168e2362796SWludzik, Jozef 169493e62ebSKrzysztof Grobelny const tuple_type& to_tuple() const 170493e62ebSKrzysztof Grobelny { 171493e62ebSKrzysztof Grobelny return value; 172493e62ebSKrzysztof Grobelny } 173493e62ebSKrzysztof Grobelny 174d2238194SKrzysztof Grobelny void from_json(const nlohmann::json& j) 175e2362796SWludzik, Jozef { 176d2238194SKrzysztof Grobelny from_json_all(j, std::make_index_sequence<sizeof...(Args)>()); 177d2238194SKrzysztof Grobelny } 178d2238194SKrzysztof Grobelny 1793a617023SSzymon Dompke std::string dump() const 1803a617023SSzymon Dompke { 1813a617023SSzymon Dompke return to_json().dump(); 1823a617023SSzymon Dompke } 1833a617023SSzymon Dompke 184d2238194SKrzysztof Grobelny template <size_t Idx> 185d2238194SKrzysztof Grobelny const auto& at_index() const 186d2238194SKrzysztof Grobelny { 187d2238194SKrzysztof Grobelny return std::get<Idx>(value); 188d2238194SKrzysztof Grobelny } 189d2238194SKrzysztof Grobelny 190d2238194SKrzysztof Grobelny template <size_t Idx> 191d2238194SKrzysztof Grobelny auto& at_index() 192d2238194SKrzysztof Grobelny { 193d2238194SKrzysztof Grobelny return std::get<Idx>(value); 194d2238194SKrzysztof Grobelny } 195d2238194SKrzysztof Grobelny 196d2238194SKrzysztof Grobelny template <class Label> 197d2238194SKrzysztof Grobelny const auto& at_label() const 198d2238194SKrzysztof Grobelny { 199d2238194SKrzysztof Grobelny return find_item<0, Label>(*this); 200d2238194SKrzysztof Grobelny } 201d2238194SKrzysztof Grobelny 202d2238194SKrzysztof Grobelny template <class Label> 203d2238194SKrzysztof Grobelny auto& at_label() 204d2238194SKrzysztof Grobelny { 205d2238194SKrzysztof Grobelny return find_item<0, Label>(*this); 206d2238194SKrzysztof Grobelny } 207d2238194SKrzysztof Grobelny 208d2238194SKrzysztof Grobelny bool operator==(const LabeledTuple& other) const 209d2238194SKrzysztof Grobelny { 210*0253f6d3SSzymon Dompke return std::apply( 211*0253f6d3SSzymon Dompke [&](auto&&... x) { 212*0253f6d3SSzymon Dompke return std::apply( 213*0253f6d3SSzymon Dompke [&](auto&&... y) { 214*0253f6d3SSzymon Dompke return (true && ... && detail::eq(x, y)); 215*0253f6d3SSzymon Dompke }, 216*0253f6d3SSzymon Dompke value); 217*0253f6d3SSzymon Dompke }, 218*0253f6d3SSzymon Dompke other.value); 219d2238194SKrzysztof Grobelny } 220d2238194SKrzysztof Grobelny 221d2238194SKrzysztof Grobelny bool operator<(const LabeledTuple& other) const 222d2238194SKrzysztof Grobelny { 223d2238194SKrzysztof Grobelny return value < other.value; 224e2362796SWludzik, Jozef } 225e2362796SWludzik, Jozef 226e2362796SWludzik, Jozef private: 227e2362796SWludzik, Jozef template <size_t... Idx> 228d2238194SKrzysztof Grobelny void to_json_all(nlohmann::json& j, std::index_sequence<Idx...>) const 229e2362796SWludzik, Jozef { 230d2238194SKrzysztof Grobelny (to_json_item<Idx>(j), ...); 231e2362796SWludzik, Jozef } 232e2362796SWludzik, Jozef 233e2362796SWludzik, Jozef template <size_t Idx> 234d2238194SKrzysztof Grobelny void to_json_item(nlohmann::json& j) const 235e2362796SWludzik, Jozef { 236e2362796SWludzik, Jozef using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>; 237*0253f6d3SSzymon Dompke using T = std::tuple_element_t<Idx, tuple_type>; 238*0253f6d3SSzymon Dompke nlohmann::json& item = j[Label::str()]; 239*0253f6d3SSzymon Dompke if constexpr (detail::has_utils_to_json_v<T>) 240*0253f6d3SSzymon Dompke { 241*0253f6d3SSzymon Dompke utils::to_json(item, std::get<Idx>(value)); 242*0253f6d3SSzymon Dompke } 243*0253f6d3SSzymon Dompke else 244*0253f6d3SSzymon Dompke { 245*0253f6d3SSzymon Dompke item = std::get<Idx>(value); 246*0253f6d3SSzymon Dompke } 247e2362796SWludzik, Jozef } 248e2362796SWludzik, Jozef 249e2362796SWludzik, Jozef template <size_t... Idx> 250d2238194SKrzysztof Grobelny void from_json_all(const nlohmann::json& j, std::index_sequence<Idx...>) 251e2362796SWludzik, Jozef { 252d2238194SKrzysztof Grobelny (from_json_item<Idx>(j), ...); 253e2362796SWludzik, Jozef } 254e2362796SWludzik, Jozef 255e2362796SWludzik, Jozef template <size_t Idx> 256d2238194SKrzysztof Grobelny void from_json_item(const nlohmann::json& j) 257e2362796SWludzik, Jozef { 258e2362796SWludzik, Jozef using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>; 259d2238194SKrzysztof Grobelny using T = std::tuple_element_t<Idx, tuple_type>; 260e2362796SWludzik, Jozef const nlohmann::json& item = j.at(Label::str()); 261e2362796SWludzik, Jozef if constexpr (detail::has_utils_from_json_v<T>) 262e2362796SWludzik, Jozef { 263e2362796SWludzik, Jozef T& v = std::get<Idx>(value); 264e2362796SWludzik, Jozef utils::from_json(item, v); 265e2362796SWludzik, Jozef } 266e2362796SWludzik, Jozef else 267e2362796SWludzik, Jozef { 268e2362796SWludzik, Jozef std::get<Idx>(value) = item.get<T>(); 269e2362796SWludzik, Jozef } 270e2362796SWludzik, Jozef } 271d2238194SKrzysztof Grobelny 272d2238194SKrzysztof Grobelny template <size_t Idx, class Label, class Self> 273d2238194SKrzysztof Grobelny static auto& find_item(Self& self) 274d2238194SKrzysztof Grobelny { 275d2238194SKrzysztof Grobelny if constexpr (std::is_same_v<Label, std::tuple_element_t< 276d2238194SKrzysztof Grobelny Idx, std::tuple<Labels...>>>) 277d2238194SKrzysztof Grobelny { 278d2238194SKrzysztof Grobelny return std::get<Idx>(self.value); 279d2238194SKrzysztof Grobelny } 280d2238194SKrzysztof Grobelny else 281d2238194SKrzysztof Grobelny { 282b8cc78ddSKrzysztof Grobelny static_assert(Idx + 1 < sizeof...(Args), 283b8cc78ddSKrzysztof Grobelny "Label not found in LabeledTuple"); 284d2238194SKrzysztof Grobelny return find_item<Idx + 1, Label>(self); 285d2238194SKrzysztof Grobelny } 286d2238194SKrzysztof Grobelny } 287d2238194SKrzysztof Grobelny 288d2238194SKrzysztof Grobelny tuple_type value; 289e2362796SWludzik, Jozef }; 290e2362796SWludzik, Jozef 291d2238194SKrzysztof Grobelny template <class... Args, class... Labels> 292dcc4e193SKrzysztof Grobelny inline void to_json(nlohmann::json& json, 293d2238194SKrzysztof Grobelny const LabeledTuple<std::tuple<Args...>, Labels...>& tuple) 294d2238194SKrzysztof Grobelny { 295d2238194SKrzysztof Grobelny json = tuple.to_json(); 296d2238194SKrzysztof Grobelny } 297d2238194SKrzysztof Grobelny 298d2238194SKrzysztof Grobelny template <class... Args, class... Labels> 299dcc4e193SKrzysztof Grobelny inline void from_json(const nlohmann::json& json, 300d2238194SKrzysztof Grobelny LabeledTuple<std::tuple<Args...>, Labels...>& tuple) 301d2238194SKrzysztof Grobelny { 302d2238194SKrzysztof Grobelny tuple.from_json(json); 303d2238194SKrzysztof Grobelny } 304d2238194SKrzysztof Grobelny 305e2362796SWludzik, Jozef } // namespace utils 306