Fcitx
message.h
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2016-2016 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #ifndef _FCITX_UTILS_DBUS_MESSAGE_H_
8 #define _FCITX_UTILS_DBUS_MESSAGE_H_
9 
10 #include <cassert>
11 #include <cstddef>
12 #include <cstdint>
13 #include <functional>
14 #include <memory>
15 #include <string>
16 #include <tuple>
17 #include <type_traits>
18 #include <utility>
19 #include <vector>
20 #include <fcitx-utils/dbus/message_details.h> // IWYU pragma: export
21 #include <fcitx-utils/fcitxutils_export.h>
22 #include <fcitx-utils/log.h>
23 #include <fcitx-utils/macros.h>
24 #include <fcitx-utils/metastring.h>
25 #include <fcitx-utils/tuplehelpers.h>
26 #include <fcitx-utils/unixfd.h>
27 
28 /// \addtogroup FcitxUtils
29 /// \{
30 /// \file
31 /// \brief API for DBus message.
32 
33 namespace fcitx::dbus {
34 
35 class Message;
36 class Variant;
37 
38 /**
39  * A type to represent DBus struct.
40  *
41  * It is used for message serialization.
42  */
43 template <typename... Args>
44 struct DBusStruct {
45  using tuple_type = std::tuple<Args...>;
46 
47  DBusStruct() = default;
48 
49  template <typename Element, typename... Elements>
50  DBusStruct(Element &&ele, Elements &&...elements)
51  requires(sizeof...(Elements) != 0 ||
52  !std::is_same_v<typename std::decay_t<Element>, DBusStruct>)
53  : data_(std::forward<Element>(ele),
54  std::forward<Elements>(elements)...) {}
55 
56  DBusStruct(const DBusStruct &) = default;
57  DBusStruct(DBusStruct &&) noexcept(
58  std::is_nothrow_move_constructible<tuple_type>::value) = default;
59  DBusStruct &operator=(const DBusStruct &other) = default;
60  DBusStruct &operator=(DBusStruct &&other) noexcept(
61  std::is_nothrow_move_assignable<tuple_type>::value) = default;
62 
63  explicit DBusStruct(const tuple_type &other) : data_(std::forward(other)) {}
64  explicit DBusStruct(tuple_type &&other)
65  : data_(std::forward<tuple_type>(other)) {}
66 
67  constexpr tuple_type &data() { return data_; }
68  constexpr const tuple_type &data() const { return data_; }
69 
70 private:
71  tuple_type data_;
72 };
73 
74 struct FCITXUTILS_EXPORT VariantHelperBase {
75 public:
76  virtual ~VariantHelperBase() = default;
77  virtual std::shared_ptr<void> copy(const void *) const = 0;
78  virtual void serialize(dbus::Message &msg, const void *data) const = 0;
79  virtual void print(LogMessageBuilder &builder, const void *data) const = 0;
80  virtual void deserialize(dbus::Message &msg, void *data) const = 0;
81  virtual std::string signature() const = 0;
82 };
83 
84 template <typename Value>
85 class FCITXUTILS_EXPORT VariantHelper : public VariantHelperBase {
86  std::shared_ptr<void> copy(const void *src) const override {
87  if (src) {
88  auto *s = static_cast<const Value *>(src);
89  return std::make_shared<Value>(*s);
90  }
91  return std::make_shared<Value>();
92  }
93  void serialize(dbus::Message &msg, const void *data) const override {
94  auto *s = static_cast<const Value *>(data);
95  msg << *s;
96  }
97  void deserialize(dbus::Message &msg, void *data) const override {
98  auto *s = static_cast<Value *>(data);
99  msg >> *s;
100  }
101  void print(LogMessageBuilder &builder, const void *data) const override {
102  auto *s = static_cast<const Value *>(data);
103  builder << *s;
104  }
105  std::string signature() const override {
107  }
108 };
109 
110 /**
111  * A type to represent DBus dict entry.
112  *
113  * It is used for message serialization for type like a{sv}.
114  */
115 template <typename Key, typename Value>
116 class DictEntry {
117 public:
118  DictEntry() = default;
119  DictEntry(const DictEntry &) = default;
120  DictEntry(DictEntry &&) noexcept = default;
121  DictEntry &operator=(const DictEntry &other) = default;
122  DictEntry &operator=(DictEntry &&other) noexcept = default;
123 
124  DictEntry(const Key &key, const Value &value) : key_(key), value_(value) {}
125 
126  constexpr Key &key() { return key_; }
127  constexpr const Key &key() const { return key_; }
128  constexpr Value &value() { return value_; }
129  constexpr const Value &value() const { return value_; }
130 
131 private:
132  Key key_;
133  Value value_;
134 };
135 
136 class Message;
137 using MessageCallback = std::function<bool(Message &)>;
138 class Slot;
139 
140 enum class MessageType {
141  Invalid,
142  Signal,
143  MethodCall,
144  Reply,
145  Error,
146 };
147 
148 /**
149  * String like type object path 'o'
150  */
151 class FCITXUTILS_EXPORT ObjectPath {
152 public:
153  ObjectPath(const std::string &path = {}) : path_(path) {}
154 
155  const std::string &path() const { return path_; }
156 
157 private:
158  std::string path_;
159 };
160 
161 /**
162  * String like type object signature 'g'
163  */
164 class FCITXUTILS_EXPORT Signature {
165 public:
166  Signature(const std::string &sig = {}) : sig_(sig) {}
167 
168  const std::string &sig() const { return sig_; }
169 
170 private:
171  std::string sig_;
172 };
173 
174 /// Helper type for serialization, should not be used directly.
175 class FCITXUTILS_EXPORT Container {
176 public:
177  enum class Type { Array, DictEntry, Struct, Variant };
178 
179  Container(Type t = Type::Array, const Signature &content = Signature())
180  : type_(t), content_(content) {}
181 
182  Type type() const { return type_; }
183  const Signature &content() const { return content_; }
184 
185 private:
186  Type type_;
187  Signature content_;
188 };
189 
190 /// Helper type for serialization, should not be used directly.
191 class FCITXUTILS_EXPORT ContainerEnd {};
192 
193 class MessagePrivate;
194 
195 template <typename Tuple, std::size_t N>
197  static void marshall(Message &msg, const Tuple &t) {
199  msg << std::get<N - 1>(t);
200  }
201  static void unmarshall(Message &msg, Tuple &t) {
203  msg >> std::get<N - 1>(t);
204  }
205 };
206 
207 template <typename Tuple>
208 struct TupleMarshaller<Tuple, 1> {
209  static void marshall(Message &msg, const Tuple &t) {
210  msg << std::get<0>(t);
211  }
212  static void unmarshall(Message &msg, Tuple &t) { msg >> std::get<0>(t); }
213 };
214 
215 template <typename Tuple>
216 struct TupleMarshaller<Tuple, 0> {
217  static void marshall(Message & /*unused*/, const Tuple & /*unused*/) {}
218  static void unmarshall(Message & /*unused*/, Tuple & /*unused*/) {}
219 };
220 
221 /**
222  * Basic DBus type of a DBus message.
223  */
224 class FCITXUTILS_EXPORT Message {
225  friend class Bus;
226 
227 public:
228  Message();
229 
230  FCITX_DECLARE_VIRTUAL_DTOR_MOVE(Message);
231  /// Create a reply to this message.
232  Message createReply() const;
233  /// Create a error reply to this message.
234  Message createError(const char *name, const char *message) const;
235 
236  /// Return the message type.
237  MessageType type() const;
238 
239  /// Check if the message is error.
240  bool isError() const { return type() == MessageType::Error; }
241 
242  /// Return the destination of the message.
243  std::string destination() const;
244 
245  /**
246  * Set the destination of the message.
247  *
248  * Should only be used on message to send.
249  *
250  * @param dest destination
251  */
252  void setDestination(const std::string &dest);
253 
254  /// Return the sender of the message.
255  std::string sender() const;
256 
257  /// Return the member of the message.
258  std::string member() const;
259 
260  /// Return the interface of the message.
261  std::string interface() const;
262 
263  /// Return the signature of the message
264  std::string signature() const;
265 
266  /**
267  * Return the error name of the message.
268  *
269  * Should only be used when message is a received error.
270  *
271  * @return DBus Error type
272  */
273  std::string errorName() const;
274 
275  /**
276  * Return the error message of the message.
277  *
278  * Should only be used when message is a received error.
279  *
280  * @return DBus Error type
281  */
282  std::string errorMessage() const;
283 
284  /// Return the path of the message.
285  std::string path() const;
286 
287  /**
288  * Return the low level internal pointer of the message.
289  *
290  * @see dbus::Bus::impl
291  *
292  * @return internal pointer
293  */
294  void *nativeHandle() const;
295 
296  /// Synchronously call a dbus method with a timeout in microseconds.
297  Message call(uint64_t usec);
298 
299  /**
300  * Asynchronously call a dbus method with a timeout in microseconds.
301  *
302  * @param usec timeout
303  * @param callback Callback function if anything happens.
304  */
305  std::unique_ptr<Slot> callAsync(uint64_t usec, MessageCallback callback);
306 
307  /// Send this message.
308  bool send();
309 
310  /// Check if message is not empty and has no serialization error.
311  operator bool() const;
312 
313  /// Check if message reaches end.
314  bool end() const;
315 
316  /// Clear serialization error.
317  void resetError();
318 
319  /// Rewind the message to the beginning.
320  void rewind();
321 
322  /// Skip the next data.
323  void skip();
324 
325  /// Check the next type of data in the message
326  std::pair<char, std::string> peekType();
327 
328  Message &operator<<(uint8_t v);
329  Message &operator<<(bool b);
330  Message &operator<<(int16_t v);
331  Message &operator<<(uint16_t v);
332  Message &operator<<(int32_t v);
333  Message &operator<<(uint32_t v);
334  Message &operator<<(int64_t v);
335  Message &operator<<(uint64_t v);
336  Message &operator<<(double v);
337  Message &operator<<(const std::string &s);
338  Message &operator<<(const char *s);
339 
340  Message &operator<<(const ObjectPath &o);
341  Message &operator<<(const Signature &s);
342  Message &operator<<(const UnixFD &fd);
343  Message &operator<<(const Container &c);
344  Message &operator<<(const ContainerEnd &c);
345  Message &operator<<(const Variant &v);
346 
347  template <typename K, typename V>
348  Message &operator<<(const std::pair<K, V> &t) {
349  if (!(*this)) {
350  return *this;
351  }
352  *this << std::get<0>(t);
353  if (!(*this)) {
354  return *this;
355  }
356  *this << std::get<1>(t);
357  return *this;
358  }
359 
360  template <typename... Args>
361  Message &operator<<(const std::tuple<Args...> &t) {
362  TupleMarshaller<decltype(t), sizeof...(Args)>::marshall(*this, t);
363  return *this;
364  }
365 
366  template <typename... Args>
367  Message &operator<<(const DBusStruct<Args...> &t) {
368  using value_type = DBusStruct<Args...>;
369  using signature =
371  if (*this << Container(Container::Type::Struct,
372  Signature(signature::data()))) {
373  TupleMarshaller<typename value_type::tuple_type,
374  sizeof...(Args)>::marshall(*this, t.data());
375  if (*this) {
376  *this << ContainerEnd();
377  }
378  }
379  return *this;
380  }
381 
382  template <typename Key, typename Value>
383  Message &operator<<(const DictEntry<Key, Value> &t) {
384  using value_type = DictEntry<Key, Value>;
385  using signature =
387  if (*this << Container(Container::Type::DictEntry,
388  Signature(signature::data()))) {
389  *this << t.key();
390  if (!(*this)) {
391  return *this;
392  }
393  *this << t.value();
394  if (!(*this)) {
395  return *this;
396  }
397  if (*this) {
398  *this << ContainerEnd();
399  }
400  }
401  return *this;
402  }
403 
404  template <typename T>
405  Message &operator<<(const std::vector<T> &t) {
406  using value_type = std::vector<T>;
407  using signature =
409  if (*this << Container(Container::Type::Array,
410  Signature(signature::data()))) {
411  for (auto &v : t) {
412  *this << v;
413  }
414  *this << ContainerEnd();
415  }
416  return *this;
417  }
418 
419  Message &operator>>(uint8_t &v);
420  Message &operator>>(bool &b);
421  Message &operator>>(int16_t &v);
422  Message &operator>>(uint16_t &v);
423  Message &operator>>(int32_t &v);
424  Message &operator>>(uint32_t &v);
425  Message &operator>>(int64_t &v);
426  Message &operator>>(uint64_t &v);
427  Message &operator>>(double &v);
428  Message &operator>>(std::string &s);
429  Message &operator>>(ObjectPath &o);
430  Message &operator>>(Signature &s);
431  Message &operator>>(UnixFD &fd);
432  Message &operator>>(const Container &c);
433  Message &operator>>(const ContainerEnd &c);
434  Message &operator>>(Variant &variant);
435 
436  template <typename K, typename V>
437  Message &operator>>(std::pair<K, V> &t) {
438  if (!(*this)) {
439  return *this;
440  }
441  *this >> std::get<0>(t);
442  if (!(*this)) {
443  return *this;
444  }
445  *this >> std::get<1>(t);
446  return *this;
447  }
448 
449  template <typename... Args>
450  Message &operator>>(std::tuple<Args...> &t) {
451  TupleMarshaller<decltype(t), sizeof...(Args)>::unmarshall(*this, t);
452  return *this;
453  }
454 
455  template <typename... Args>
456  Message &operator>>(DBusStruct<Args...> &t) {
457  using value_type = DBusStruct<Args...>;
458  using tuple_type = typename value_type::tuple_type;
459  using signature =
461  if (*this >>
462  Container(Container::Type::Struct, Signature(signature::data()))) {
463  TupleMarshaller<tuple_type, sizeof...(Args)>::unmarshall(*this,
464  t.data());
465  if (*this) {
466  *this >> ContainerEnd();
467  }
468  }
469  return *this;
470  }
471 
472  template <typename Key, typename Value>
473  Message &operator>>(DictEntry<Key, Value> &t) {
474  using value_type = DictEntry<Key, Value>;
475  using signature =
477  if (*this >> Container(Container::Type::DictEntry,
478  Signature(signature::data()))) {
479  *this >> t.key();
480  if (!(*this)) {
481  return *this;
482  }
483  *this >> t.value();
484  if (!(*this)) {
485  return *this;
486  }
487  if (*this) {
488  *this >> ContainerEnd();
489  }
490  }
491  return *this;
492  }
493 
494  template <typename T>
495  Message &operator>>(std::vector<T> &t) {
496  using value_type = std::vector<T>;
497  using signature =
499  if (*this >>
500  Container(Container::Type::Array, Signature(signature::data()))) {
501  t.clear();
502  while (!end()) {
503  T temp;
504  if (*this >> temp) {
505  t.push_back(temp);
506  } else {
507  break;
508  }
509  }
510  *this >> ContainerEnd();
511  }
512  return *this;
513  }
514 
515 private:
516  std::unique_ptr<MessagePrivate> d_ptr;
517  FCITX_DECLARE_PRIVATE(Message);
518 };
519 
520 template <typename K, typename V>
521 inline LogMessageBuilder &operator<<(LogMessageBuilder &builder,
522  const DictEntry<K, V> &entry) {
523  builder << "(" << entry.key() << ", " << entry.value() << ")";
524  return builder;
525 }
526 
527 template <typename... Args>
528 inline LogMessageBuilder &operator<<(LogMessageBuilder &builder,
529  const DBusStruct<Args...> &st) {
530  builder << st.data();
531  return builder;
532 }
533 
534 static inline LogMessageBuilder &operator<<(LogMessageBuilder &builder,
535  const Signature &sig) {
536  builder << "Signature(" << sig.sig() << ")";
537  return builder;
538 }
539 
540 static inline LogMessageBuilder &operator<<(LogMessageBuilder &builder,
541  const ObjectPath &path) {
542  builder << "ObjectPath(" << path.path() << ")";
543  return builder;
544 }
545 
546 } // namespace fcitx::dbus
547 
548 namespace std {
549 
550 template <std::size_t i, typename... _Elements>
551 constexpr auto &get(fcitx::dbus::DBusStruct<_Elements...> &t) noexcept {
552  return std::get<i>(t.data());
553 }
554 
555 template <std::size_t i, typename... _Elements>
556 constexpr auto &get(const fcitx::dbus::DBusStruct<_Elements...> &t) noexcept {
557  return std::get<i>(t.data());
558 }
559 
560 template <typename T, typename... _Elements>
561 constexpr auto &get(fcitx::dbus::DBusStruct<_Elements...> &t) noexcept {
562  return std::get<T>(t.data());
563 }
564 
565 template <typename T, typename... _Elements>
566 constexpr auto &get(const fcitx::dbus::DBusStruct<_Elements...> &t) noexcept {
567  return std::get<T>(t.data());
568 }
569 } // namespace std
570 
571 #endif // _FCITX_UTILS_DBUS_MESSAGE_H_
Helper type for serialization, should not be used directly.
Definition: message.h:191
Class wrap around the unix fd.
Definition: unixfd.h:22
Basic DBus type of a DBus message.
Definition: message.h:224
Describe a Key in fcitx.
Definition: key.h:41
String like type object signature &#39;g&#39;.
Definition: message.h:164
Virtual base class represent some internal registration of the bus.
Definition: bus.h:33
Definition: matchrule.h:78
A class that represents a connection to the Bus.
Definition: bus.h:51
Helper type for serialization, should not be used directly.
Definition: message.h:175
Utility class to handle unix file decriptor.
Class to represent a signal. May be used like a functor.
Definition: signals.h:126
A type to represent DBus dict entry.
Definition: message.h:116
Variant type to be used to box or unbox the dbus variant type.
Definition: variant.h:65
String like type object path &#39;o&#39;.
Definition: message.h:151
bool isError() const
Check if the message is error.
Definition: message.h:240
A type to represent DBus struct.
Definition: message.h:44
Log utilities.
Static string based on template argument.
Base class that can be used for UI composition or graph.
Definition: element.h:26