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 const tuple_type& to_tuple() const 80 { 81 return value; 82 } 83 84 void from_json(const nlohmann::json& j) 85 { 86 from_json_all(j, std::make_index_sequence<sizeof...(Args)>()); 87 } 88 89 std::string dump() const 90 { 91 return to_json().dump(); 92 } 93 94 template <size_t Idx> 95 const auto& at_index() const 96 { 97 return std::get<Idx>(value); 98 } 99 100 template <size_t Idx> 101 auto& at_index() 102 { 103 return std::get<Idx>(value); 104 } 105 106 template <class Label> 107 const auto& at_label() const 108 { 109 return find_item<0, Label>(*this); 110 } 111 112 template <class Label> 113 auto& at_label() 114 { 115 return find_item<0, Label>(*this); 116 } 117 118 bool operator==(const LabeledTuple& other) const 119 { 120 return value == other.value; 121 } 122 123 bool operator<(const LabeledTuple& other) const 124 { 125 return value < other.value; 126 } 127 128 private: 129 template <size_t... Idx> 130 void to_json_all(nlohmann::json& j, std::index_sequence<Idx...>) const 131 { 132 (to_json_item<Idx>(j), ...); 133 } 134 135 template <size_t Idx> 136 void to_json_item(nlohmann::json& j) const 137 { 138 using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>; 139 j[Label::str()] = std::get<Idx>(value); 140 } 141 142 template <size_t... Idx> 143 void from_json_all(const nlohmann::json& j, std::index_sequence<Idx...>) 144 { 145 (from_json_item<Idx>(j), ...); 146 } 147 148 template <size_t Idx> 149 void from_json_item(const nlohmann::json& j) 150 { 151 using Label = std::tuple_element_t<Idx, std::tuple<Labels...>>; 152 using T = std::tuple_element_t<Idx, tuple_type>; 153 const nlohmann::json& item = j.at(Label::str()); 154 if constexpr (detail::has_utils_from_json_v<T>) 155 { 156 T& v = std::get<Idx>(value); 157 utils::from_json(item, v); 158 } 159 else 160 { 161 std::get<Idx>(value) = item.get<T>(); 162 } 163 } 164 165 template <size_t Idx, class Label, class Self> 166 static auto& find_item(Self& self) 167 { 168 if constexpr (std::is_same_v<Label, std::tuple_element_t< 169 Idx, std::tuple<Labels...>>>) 170 { 171 return std::get<Idx>(self.value); 172 } 173 else 174 { 175 static_assert(Idx + 1 < sizeof...(Args), 176 "Label not found in LabeledTuple"); 177 return find_item<Idx + 1, Label>(self); 178 } 179 } 180 181 tuple_type value; 182 }; 183 184 template <class... Args, class... Labels> 185 inline void to_json(nlohmann::json& json, 186 const LabeledTuple<std::tuple<Args...>, Labels...>& tuple) 187 { 188 json = tuple.to_json(); 189 } 190 191 template <class... Args, class... Labels> 192 inline void from_json(const nlohmann::json& json, 193 LabeledTuple<std::tuple<Args...>, Labels...>& tuple) 194 { 195 tuple.from_json(json); 196 } 197 198 } // namespace utils 199