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