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