1 #pragma once
2
3 #include <optional>
4 #include <string>
5 #include <string_view>
6 #include <variant>
7
8 namespace sdbusplus
9 {
10
11 namespace message
12 {
13
14 namespace details
15 {
16
17 /** Simple wrapper class for std::string to allow conversion to and from an
18 * alternative typename. */
19 struct string_wrapper
20 {
21 std::string str;
22
23 string_wrapper() = default;
24 string_wrapper(const string_wrapper&) = default;
25 string_wrapper& operator=(const string_wrapper&) = default;
26 string_wrapper(string_wrapper&&) = default;
27 string_wrapper& operator=(string_wrapper&&) = default;
28 ~string_wrapper() = default;
29
string_wrappersdbusplus::message::details::string_wrapper30 string_wrapper(const std::string& str_in) : str(str_in) {}
string_wrappersdbusplus::message::details::string_wrapper31 string_wrapper(std::string&& str_in) : str(std::move(str_in)) {}
32
operator const std::string&sdbusplus::message::details::string_wrapper33 operator const std::string&() const volatile&
34 {
35 return const_cast<const string_wrapper*>(this)->str;
36 }
operator std::string&&sdbusplus::message::details::string_wrapper37 operator std::string&&() &&
38 {
39 return std::move(str);
40 }
41
operator ==sdbusplus::message::details::string_wrapper42 bool operator==(const string_wrapper& r) const
43 {
44 return str == r.str;
45 }
operator !=sdbusplus::message::details::string_wrapper46 bool operator!=(const string_wrapper& r) const
47 {
48 return str != r.str;
49 }
operator <sdbusplus::message::details::string_wrapper50 bool operator<(const string_wrapper& r) const
51 {
52 return str < r.str;
53 }
operator ==sdbusplus::message::details::string_wrapper54 bool operator==(const std::string& r) const
55 {
56 return str == r;
57 }
operator !=sdbusplus::message::details::string_wrapper58 bool operator!=(const std::string& r) const
59 {
60 return str != r;
61 }
operator <sdbusplus::message::details::string_wrapper62 bool operator<(const std::string& r) const
63 {
64 return str < r;
65 }
66
operator ==(const std::string & l,const string_wrapper & r)67 friend bool operator==(const std::string& l, const string_wrapper& r)
68 {
69 return l == r.str;
70 }
operator !=(const std::string & l,const string_wrapper & r)71 friend bool operator!=(const std::string& l, const string_wrapper& r)
72 {
73 return l != r.str;
74 }
operator <(const std::string & l,const string_wrapper & r)75 friend bool operator<(const std::string& l, const string_wrapper& r)
76 {
77 return l < r.str;
78 }
79 };
80
81 /** Simple wrapper class for std::string to allow conversion to and from an
82 * alternative typename. */
83 struct string_path_wrapper
84 {
85 std::string str;
86
87 string_path_wrapper() = default;
88 string_path_wrapper(const string_path_wrapper&) = default;
89 string_path_wrapper& operator=(const string_path_wrapper&) = default;
90 string_path_wrapper(string_path_wrapper&&) = default;
91 string_path_wrapper& operator=(string_path_wrapper&&) = default;
92 ~string_path_wrapper() = default;
93
string_path_wrappersdbusplus::message::details::string_path_wrapper94 string_path_wrapper(const std::string& str_in) : str(str_in) {}
string_path_wrappersdbusplus::message::details::string_path_wrapper95 string_path_wrapper(std::string&& str_in) : str(std::move(str_in)) {}
96
operator const std::string&sdbusplus::message::details::string_path_wrapper97 operator const std::string&() const volatile&
98 {
99 return const_cast<const string_path_wrapper*>(this)->str;
100 }
operator std::string&&sdbusplus::message::details::string_path_wrapper101 operator std::string&&() &&
102 {
103 return std::move(str);
104 }
105
operator ==sdbusplus::message::details::string_path_wrapper106 bool operator==(const string_path_wrapper& r) const
107 {
108 return str == r.str;
109 }
operator !=sdbusplus::message::details::string_path_wrapper110 bool operator!=(const string_path_wrapper& r) const
111 {
112 return str != r.str;
113 }
operator <sdbusplus::message::details::string_path_wrapper114 bool operator<(const string_path_wrapper& r) const
115 {
116 return str < r.str;
117 }
operator ==sdbusplus::message::details::string_path_wrapper118 bool operator==(const std::string& r) const
119 {
120 return str == r;
121 }
operator !=sdbusplus::message::details::string_path_wrapper122 bool operator!=(const std::string& r) const
123 {
124 return str != r;
125 }
operator <sdbusplus::message::details::string_path_wrapper126 bool operator<(const std::string& r) const
127 {
128 return str < r;
129 }
130
operator ==(const std::string & l,const string_path_wrapper & r)131 friend bool operator==(const std::string& l, const string_path_wrapper& r)
132 {
133 return l == r.str;
134 }
operator !=(const std::string & l,const string_path_wrapper & r)135 friend bool operator!=(const std::string& l, const string_path_wrapper& r)
136 {
137 return l != r.str;
138 }
operator <(const std::string & l,const string_path_wrapper & r)139 friend bool operator<(const std::string& l, const string_path_wrapper& r)
140 {
141 return l < r.str;
142 }
143
144 std::string filename() const;
145 string_path_wrapper parent_path() const;
146 string_path_wrapper operator/(std::string_view) const;
147 string_path_wrapper& operator/=(std::string_view);
148 };
149
150 /** Typename for sdbus SIGNATURE types. */
151 struct signature_type
152 {};
153 /** Typename for sdbus UNIX_FD types. */
154 struct unix_fd_type
155 {
156 int fd;
157
158 unix_fd_type() = default;
unix_fd_typesdbusplus::message::details::unix_fd_type159 unix_fd_type(int f) : fd(f) {}
160
operator intsdbusplus::message::details::unix_fd_type161 operator int() const
162 {
163 return fd;
164 }
165 };
166
167 } // namespace details
168
169 /** std::string wrapper for OBJECT_PATH. */
170 using object_path = details::string_path_wrapper;
171 /** std::string wrapper for SIGNATURE. */
172 using signature = details::string_wrapper;
173 using unix_fd = details::unix_fd_type;
174
175 namespace details
176 {
177
178 template <typename T>
179 struct convert_from_string
180 {
181 static auto op(const std::string&) noexcept = delete;
182 };
183
184 template <typename T>
185 struct convert_to_string
186 {
187 static std::string op(T) = delete;
188 };
189
190 } // namespace details
191
192 /** @brief Convert from a string to a native type.
193 *
194 * Some C++ types cannot be represented directly on dbus, so we encode
195 * them as strings. Enums are the primary example of this. This is a
196 * template function prototype for the conversion from string functions.
197 *
198 * @return A std::optional<T> containing the value if conversion is possible.
199 */
200 template <typename T>
convert_from_string(const std::string & str)201 auto convert_from_string(const std::string& str) noexcept
202 {
203 return details::convert_from_string<T>::op(str);
204 }
205
206 /** @brief Convert from a native type to a string.
207 *
208 * Some C++ types cannot be represented directly on dbus, so we encode
209 * them as strings. Enums are the primary example of this. This is a
210 * template function prototype for the conversion to string functions.
211 *
212 * @return A std::string containing an encoding of the value, if conversion is
213 * possible.
214 */
215 template <typename T>
convert_to_string(T t)216 std::string convert_to_string(T t)
217 {
218 return details::convert_to_string<T>::op(t);
219 }
220
221 namespace details
222 {
223 // SFINAE templates to determine if convert_from_string exists for a type.
224 template <typename T>
225 auto has_convert_from_string_helper(T)
226 -> decltype(convert_from_string<T>::op(std::declval<std::string>()),
227 std::true_type());
228 auto has_convert_from_string_helper(...) -> std::false_type;
229
230 template <typename T>
231 struct has_convert_from_string :
232 decltype(has_convert_from_string_helper(std::declval<T>())){};
233
234 template <typename T>
235 inline constexpr bool has_convert_from_string_v =
236 has_convert_from_string<T>::value;
237
238 // Specialization of 'convert_from_string' for variant.
239 template <typename... Types>
240 struct convert_from_string<std::variant<Types...>>
241 {
opsdbusplus::message::details::convert_from_string242 static auto op(const std::string& str)
243 -> std::optional<std::variant<Types...>>
244 {
245 if constexpr (0 < sizeof...(Types))
246 {
247 return process<Types...>(str);
248 }
249 return {};
250 }
251
252 // We need to iterate through all the variant types and find
253 // the one which matches the contents of the string. Often,
254 // a variant can contain both a convertible-type (ie. enum) and
255 // a string, so we need to iterate through all the convertible-types
256 // first and convert to string as a last resort.
257 template <typename T, typename... Args>
processsdbusplus::message::details::convert_from_string258 static auto process(const std::string& str)
259 -> std::optional<std::variant<Types...>>
260 {
261 // If convert_from_string exists for the type, attempt it.
262 if constexpr (has_convert_from_string_v<T>)
263 {
264 auto r = convert_from_string<T>::op(str);
265 if (r)
266 {
267 return r;
268 }
269 }
270
271 // If there are any more types in the variant, try them.
272 if constexpr (0 < sizeof...(Args))
273 {
274 auto r = process<Args...>(str);
275 if (r)
276 {
277 return r;
278 }
279 }
280
281 // Otherwise, if this is a string, do last-resort conversion.
282 if constexpr (std::is_same_v<std::string, std::remove_cv_t<T>>)
283 {
284 return str;
285 }
286
287 return {};
288 }
289 };
290
291 } // namespace details
292
293 /** Export template helper to determine if a type has convert_from_string. */
294 template <typename T>
295 inline constexpr bool has_convert_from_string_v =
296 details::has_convert_from_string_v<T>;
297
298 } // namespace message
299 } // namespace sdbusplus
300
301 namespace std
302 {
303
304 /** Overload of std::hash for details::string_wrappers */
305 template <>
306 struct hash<sdbusplus::message::details::string_wrapper>
307 {
308 using argument_type = sdbusplus::message::details::string_wrapper;
309 using result_type = std::size_t;
310
operator ()std::hash311 result_type operator()(const argument_type& s) const
312 {
313 return hash<std::string>()(s.str);
314 }
315 };
316
317 /** Overload of std::hash for details::string_wrappers */
318 template <>
319 struct hash<sdbusplus::message::details::string_path_wrapper>
320 {
321 using argument_type = sdbusplus::message::details::string_path_wrapper;
322 using result_type = std::size_t;
323
operator ()std::hash324 result_type operator()(const argument_type& s) const
325 {
326 return hash<std::string>()(s.str);
327 }
328 };
329
330 } // namespace std
331