Fcitx
variant.h
Go to the documentation of this file.
1 /*
2  * SPDX-FileCopyrightText: 2017-2017 CSSlayer <wengxt@gmail.com>
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  */
7 #ifndef _FCITX_UTILS_DBUS_VARIANT_H_
8 #define _FCITX_UTILS_DBUS_VARIANT_H_
9 
10 #include <cassert>
11 #include <memory>
12 #include <string>
13 #include <type_traits>
14 #include <utility>
16 #include <fcitx-utils/fcitxutils_export.h>
17 #include <fcitx-utils/log.h>
18 #include <fcitx-utils/macros.h>
19 
20 /// \addtogroup FcitxUtils
21 /// \{
22 /// \file
23 /// \brief API for dbus variant type.
24 
25 namespace fcitx::dbus {
26 
27 class VariantTypeRegistryPrivate;
28 
29 /// We need to "predefine some of the variant type that we want to handle".
30 class FCITXUTILS_EXPORT VariantTypeRegistry {
31 public:
32  static VariantTypeRegistry &defaultRegistry();
33 
34  template <typename TypeName>
35  void registerType() {
36  using SignatureType = typename DBusSignatureTraits<TypeName>::signature;
37  using PureType = FCITX_STRING_TO_DBUS_TYPE(SignatureType::str());
38  static_assert(
39  std::is_same<TypeName, PureType>::value,
40  "Type is not pure enough, remove the redundant tuple from it");
42  std::make_shared<VariantHelper<TypeName>>());
43  }
44 
45  std::shared_ptr<VariantHelperBase>
46  lookupType(const std::string &signature) const;
47 
48 private:
49  void registerTypeImpl(const std::string &signature,
50  std::shared_ptr<VariantHelperBase>);
52  std::unique_ptr<VariantTypeRegistryPrivate> d_ptr;
53  FCITX_DECLARE_PRIVATE(VariantTypeRegistry);
54 };
55 
56 std::shared_ptr<VariantHelperBase> FCITXUTILS_EXPORT
57 lookupVariantType(const std::string &signature);
58 
59 template <typename TypeName>
60 inline void registerVariantType() {
61  VariantTypeRegistry::defaultRegistry().registerType<TypeName>();
62 }
63 
64 /// Variant type to be used to box or unbox the dbus variant type.
65 class FCITXUTILS_EXPORT Variant {
66 public:
67  /// Construct an empty variant.
68  Variant() = default;
69 
70  /// Construct a variant from some existing data.
71  template <
72  typename Value,
73  typename Dummy = std::enable_if_t<
74  !std::is_same_v<std::remove_cv_t<std::remove_reference_t<Value>>,
75  Variant>,
76  void>>
77  explicit Variant(Value &&value) {
78  setData(std::forward<Value>(value));
79  }
80 
81  /// Copy Construct a variant from another variant.
82  Variant(const Variant &v) : signature_(v.signature_), helper_(v.helper_) {
83  if (helper_) {
84  data_ = helper_->copy(v.data_.get());
85  }
86  }
87 
88  /// Copy another variant data to current.
89  Variant(Variant &&v) = default;
90  Variant &operator=(const Variant &v) {
91  if (&v == this) {
92  return *this;
93  }
94  signature_ = v.signature_;
95  helper_ = v.helper_;
96  if (helper_) {
97  data_ = helper_->copy(v.data_.get());
98  }
99  return *this;
100  }
101  Variant &operator=(Variant &&v) = default;
102 
103  /// Set variant data from some existing data.
104  template <typename Value,
105  typename = std::enable_if_t<!std::is_same<
106  std::remove_cv_t<std::remove_reference_t<Value>>,
107  dbus::Variant>::value>>
108  void setData(Value &&value);
109 
110  /// Copy variant data from another variant.
111  void setData(const Variant &v) { *this = v; }
112 
113  /// Set variant data from anthoer variant.
114  void setData(Variant &&v) { *this = std::move(v); }
115 
116  /// Set variant data with a C-string.
117  void setData(const char *str) { setData(std::string(str)); }
118 
119  void setRawData(std::shared_ptr<void> data,
120  std::shared_ptr<VariantHelperBase> helper) {
121  data_ = std::move(data);
122  helper_ = std::move(helper);
123  if (helper_) {
124  signature_ = helper_->signature();
125  }
126  }
127 
128  /// Return data as given type. You need to make sure that signature matches
129  /// before using it.
130  template <typename Value>
131  const Value &dataAs() const {
132  assert(signature() == DBusSignatureTraits<Value>::signature::data());
133  return *static_cast<Value *>(data_.get());
134  }
135 
136  void writeToMessage(dbus::Message &msg) const;
137 
138  /// Return the signature of the data.
139  const std::string &signature() const { return signature_; }
140 
141  /// Print the variant data to log.
142  void printData(LogMessageBuilder &builder) const {
143  if (helper_) {
144  helper_->print(builder, data_.get());
145  }
146  }
147 
148 private:
149  std::string signature_;
150  std::shared_ptr<void> data_;
151  std::shared_ptr<const VariantHelperBase> helper_;
152 };
153 
154 template <typename Value, typename>
155 void Variant::setData(Value &&value) {
156  using value_type = std::remove_cv_t<std::remove_reference_t<Value>>;
158  data_ = std::make_shared<value_type>(std::forward<Value>(value));
159  helper_ = std::make_shared<VariantHelper<value_type>>();
160 }
161 
162 static inline LogMessageBuilder &operator<<(LogMessageBuilder &builder,
163  const Variant &var) {
164  builder << "Variant(sig=" << var.signature() << ", content=";
165  var.printData(builder);
166  builder << ")";
167  return builder;
168 }
169 
170 } // namespace fcitx::dbus
171 
172 #endif // _FCITX_UTILS_DBUS_VARIANT_H_
Basic DBus type of a DBus message.
Definition: message.h:224
Variant(const Variant &v)
Copy Construct a variant from another variant.
Definition: variant.h:82
API for DBus message.
Variant(Value &&value)
Construct a variant from some existing data.
Definition: variant.h:77
void setData(Variant &&v)
Set variant data from anthoer variant.
Definition: variant.h:114
We need to "predefine some of the variant type that we want to handle".
Definition: variant.h:30
const std::string & signature() const
Return the signature of the data.
Definition: variant.h:139
void setData(const char *str)
Set variant data with a C-string.
Definition: variant.h:117
void printData(LogMessageBuilder &builder) const
Print the variant data to log.
Definition: variant.h:142
void setData(Value &&value)
Set variant data from some existing data.
Definition: variant.h:155
const Value & dataAs() const
Return data as given type.
Definition: variant.h:131
Variant type to be used to box or unbox the dbus variant type.
Definition: variant.h:65
void setData(const Variant &v)
Copy variant data from another variant.
Definition: variant.h:111
Log utilities.