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