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