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  uint64_t serial();
326 
327  uint64_t replySerial();
328 
329  /// Check the next type of data in the message
330  std::pair<char, std::string> peekType();
331 
332  Message &operator<<(uint8_t v);
333  Message &operator<<(bool b);
334  Message &operator<<(int16_t v);
335  Message &operator<<(uint16_t v);
336  Message &operator<<(int32_t v);
337  Message &operator<<(uint32_t v);
338  Message &operator<<(int64_t v);
339  Message &operator<<(uint64_t v);
340  Message &operator<<(double v);
341  Message &operator<<(const std::string &s);
342  Message &operator<<(const char *s);
343 
344  Message &operator<<(const ObjectPath &o);
345  Message &operator<<(const Signature &s);
346  Message &operator<<(const UnixFD &fd);
347  Message &operator<<(const Container &c);
348  Message &operator<<(const ContainerEnd &c);
349  Message &operator<<(const Variant &v);
350 
351  template <typename K, typename V>
352  Message &operator<<(const std::pair<K, V> &t) {
353  if (!(*this)) {
354  return *this;
355  }
356  *this << std::get<0>(t);
357  if (!(*this)) {
358  return *this;
359  }
360  *this << std::get<1>(t);
361  return *this;
362  }
363 
364  template <typename... Args>
365  Message &operator<<(const std::tuple<Args...> &t) {
366  TupleMarshaller<decltype(t), sizeof...(Args)>::marshall(*this, t);
367  return *this;
368  }
369 
370  template <typename... Args>
371  Message &operator<<(const DBusStruct<Args...> &t) {
372  using value_type = DBusStruct<Args...>;
373  using signature =
375  if (*this << Container(Container::Type::Struct,
376  Signature(signature::data()))) {
377  TupleMarshaller<typename value_type::tuple_type,
378  sizeof...(Args)>::marshall(*this, t.data());
379  if (*this) {
380  *this << ContainerEnd();
381  }
382  }
383  return *this;
384  }
385 
386  template <typename Key, typename Value>
387  Message &operator<<(const DictEntry<Key, Value> &t) {
388  using value_type = DictEntry<Key, Value>;
389  using signature =
391  if (*this << Container(Container::Type::DictEntry,
392  Signature(signature::data()))) {
393  *this << t.key();
394  if (!(*this)) {
395  return *this;
396  }
397  *this << t.value();
398  if (!(*this)) {
399  return *this;
400  }
401  if (*this) {
402  *this << ContainerEnd();
403  }
404  }
405  return *this;
406  }
407 
408  template <typename T>
409  Message &operator<<(const std::vector<T> &t) {
410  using value_type = std::vector<T>;
411  using signature =
413  if (*this << Container(Container::Type::Array,
414  Signature(signature::data()))) {
415  for (auto &v : t) {
416  *this << v;
417  }
418  *this << ContainerEnd();
419  }
420  return *this;
421  }
422 
423  Message &operator>>(uint8_t &v);
424  Message &operator>>(bool &b);
425  Message &operator>>(int16_t &v);
426  Message &operator>>(uint16_t &v);
427  Message &operator>>(int32_t &v);
428  Message &operator>>(uint32_t &v);
429  Message &operator>>(int64_t &v);
430  Message &operator>>(uint64_t &v);
431  Message &operator>>(double &v);
432  Message &operator>>(std::string &s);
433  Message &operator>>(ObjectPath &o);
434  Message &operator>>(Signature &s);
435  Message &operator>>(UnixFD &fd);
436  Message &operator>>(const Container &c);
437  Message &operator>>(const ContainerEnd &c);
438  Message &operator>>(Variant &variant);
439 
440  template <typename K, typename V>
441  Message &operator>>(std::pair<K, V> &t) {
442  if (!(*this)) {
443  return *this;
444  }
445  *this >> std::get<0>(t);
446  if (!(*this)) {
447  return *this;
448  }
449  *this >> std::get<1>(t);
450  return *this;
451  }
452 
453  template <typename... Args>
454  Message &operator>>(std::tuple<Args...> &t) {
455  TupleMarshaller<decltype(t), sizeof...(Args)>::unmarshall(*this, t);
456  return *this;
457  }
458 
459  template <typename... Args>
460  Message &operator>>(DBusStruct<Args...> &t) {
461  using value_type = DBusStruct<Args...>;
462  using tuple_type = typename value_type::tuple_type;
463  using signature =
465  if (*this >>
466  Container(Container::Type::Struct, Signature(signature::data()))) {
467  TupleMarshaller<tuple_type, sizeof...(Args)>::unmarshall(*this,
468  t.data());
469  if (*this) {
470  *this >> ContainerEnd();
471  }
472  }
473  return *this;
474  }
475 
476  template <typename Key, typename Value>
477  Message &operator>>(DictEntry<Key, Value> &t) {
478  using value_type = DictEntry<Key, Value>;
479  using signature =
481  if (*this >> Container(Container::Type::DictEntry,
482  Signature(signature::data()))) {
483  *this >> t.key();
484  if (!(*this)) {
485  return *this;
486  }
487  *this >> t.value();
488  if (!(*this)) {
489  return *this;
490  }
491  if (*this) {
492  *this >> ContainerEnd();
493  }
494  }
495  return *this;
496  }
497 
498  template <typename T>
499  Message &operator>>(std::vector<T> &t) {
500  using value_type = std::vector<T>;
501  using signature =
503  if (*this >>
504  Container(Container::Type::Array, Signature(signature::data()))) {
505  t.clear();
506  while (!end()) {
507  T temp;
508  if (*this >> temp) {
509  t.push_back(temp);
510  } else {
511  break;
512  }
513  }
514  *this >> ContainerEnd();
515  }
516  return *this;
517  }
518 
519 private:
520  std::unique_ptr<MessagePrivate> d_ptr;
521  FCITX_DECLARE_PRIVATE(Message);
522 };
523 
524 template <typename K, typename V>
525 inline LogMessageBuilder &operator<<(LogMessageBuilder &builder,
526  const DictEntry<K, V> &entry) {
527  builder << "(" << entry.key() << ", " << entry.value() << ")";
528  return builder;
529 }
530 
531 template <typename... Args>
532 inline LogMessageBuilder &operator<<(LogMessageBuilder &builder,
533  const DBusStruct<Args...> &st) {
534  builder << st.data();
535  return builder;
536 }
537 
538 static inline LogMessageBuilder &operator<<(LogMessageBuilder &builder,
539  const Signature &sig) {
540  builder << "Signature(" << sig.sig() << ")";
541  return builder;
542 }
543 
544 static inline LogMessageBuilder &operator<<(LogMessageBuilder &builder,
545  const ObjectPath &path) {
546  builder << "ObjectPath(" << path.path() << ")";
547  return builder;
548 }
549 
550 } // namespace fcitx::dbus
551 
552 namespace std {
553 
554 template <std::size_t i, typename... _Elements>
555 constexpr auto &get(fcitx::dbus::DBusStruct<_Elements...> &t) noexcept {
556  return std::get<i>(t.data());
557 }
558 
559 template <std::size_t i, typename... _Elements>
560 constexpr auto &get(const fcitx::dbus::DBusStruct<_Elements...> &t) noexcept {
561  return std::get<i>(t.data());
562 }
563 
564 template <typename T, typename... _Elements>
565 constexpr auto &get(fcitx::dbus::DBusStruct<_Elements...> &t) noexcept {
566  return std::get<T>(t.data());
567 }
568 
569 template <typename T, typename... _Elements>
570 constexpr auto &get(const fcitx::dbus::DBusStruct<_Elements...> &t) noexcept {
571  return std::get<T>(t.data());
572 }
573 } // namespace std
574 
575 #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:42
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 descriptor.
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