xref: /openbmc/sdbusplus/include/sdbusplus/message/native_types.hpp (revision 36137e09614746b13603b5fbae79e6f70819c46b)
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