33#include < functional>
44#include < utility>
55
6+ #include < bit>
67#include < qcontainerfwd.h>
78#include < qdbusabstractinterface.h>
89#include < qdbuserror.h>
1415#include < qlogging.h>
1516#include < qloggingcategory.h>
1617#include < qobject.h>
18+ #include < qoverload.h>
19+ #include < qstringview.h>
1720#include < qtclasshelpermacros.h>
1821#include < qtmetamacros.h>
1922#include < qvariant.h>
2023
24+ #include " ../core/util.hpp"
25+
2126class DBusPropertiesInterface ;
2227
2328Q_DECLARE_LOGGING_CATEGORY (logDbusProperties);
@@ -132,21 +137,94 @@ public slots:
132137 friend class DBusPropertyGroup ;
133138};
134139
140+ namespace bindable_p {
141+
142+ template <typename T>
143+ struct BindableParams ;
144+
145+ template <template <typename , typename , auto , auto > class B , typename C, typename T, auto O, auto S>
146+ struct BindableParams <B<C, T, O, S>> {
147+ using Class = C;
148+ using Type = T;
149+ static constexpr size_t OFFSET = O;
150+ };
151+
152+ } // namespace bindable_p
153+
154+ template <
155+ auto offset,
156+ auto bindablePtr,
157+ auto updatedPtr,
158+ auto groupPtr,
159+ StringLiteral16 Name,
160+ bool required>
161+ class DBusBindableProperty : public DBusPropertyCore {
162+ using PtrMeta = MemberPointerTraits<decltype (bindablePtr)>;
163+ using Bindable = PtrMeta::Type;
164+ using Owner = PtrMeta::Class;
165+ using BindableMeta = bindable_p::BindableParams<Bindable>;
166+ using DataType = BindableMeta::Type;
167+
168+ public:
169+ explicit DBusBindableProperty () { this ->group ()->attachProperty (this ); }
170+
171+ [[nodiscard]] QString name () const override { return Name; };
172+ [[nodiscard]] QStringView nameRef () const override { return Name; };
173+ [[nodiscard]] bool isRequired () const override { return required; };
174+
175+ [[nodiscard]] QString valueString () override {
176+ QString str;
177+ QDebug (&str) << this ->bindable ()->value ();
178+ return str;
179+ }
180+
181+ void write () { this ->group ()->pushPropertyUpdate (this ); }
182+ void requestUpdate () { this ->group ()->requestPropertyUpdate (this ); }
183+
184+ protected:
185+ QDBusError store (const QVariant& variant) override {
186+ auto result = demarshallVariant<DataType>(variant);
187+
188+ if (result.isValid ()) {
189+ this ->bindable ()->setValue (std::move (result.value ));
190+
191+ if constexpr (updatedPtr != nullptr ) {
192+ (this ->owner ()->*updatedPtr)();
193+ }
194+ }
195+
196+ return result.error ;
197+ }
198+
199+ QVariant serialize () override { return QVariant::fromValue (this ->bindable ()->value ()); }
200+
201+ private:
202+ [[nodiscard]] constexpr Owner* owner () const {
203+ auto * self = std::bit_cast<char *>(this );
204+ return std::bit_cast<Owner*>(self - offset ()); // NOLINT
205+ }
206+
207+ [[nodiscard]] constexpr DBusPropertyGroup* group () const { return &(this ->owner ()->*groupPtr); }
208+ [[nodiscard]] constexpr Bindable* bindable () const { return &(this ->owner ()->*bindablePtr); }
209+ };
210+
135211class DBusPropertyGroup : public QObject {
136212 Q_OBJECT;
137213
138214public:
139- explicit DBusPropertyGroup (
140- QVector<DBusPropertyCore*> properties = QVector<DBusPropertyCore*>(),
141- QObject* parent = nullptr
142- );
215+ explicit DBusPropertyGroup (QVector<DBusPropertyCore*> properties = {}, QObject* parent = nullptr );
216+ explicit DBusPropertyGroup (QObject* parent): DBusPropertyGroup({}, parent) {}
143217
144218 void setInterface (QDBusAbstractInterface* interface);
145219 void attachProperty (AbstractDBusProperty* property);
220+ void attachProperty (DBusPropertyCore* property);
146221 void updateAllDirect ();
147222 void updateAllViaGetAll ();
148223 [[nodiscard]] QString toString () const ;
149224
225+ void pushPropertyUpdate (DBusPropertyCore* property);
226+ void requestPropertyUpdate (DBusPropertyCore* property);
227+
150228signals:
151229 void getAllFinished ();
152230 void getAllFailed (QDBusError error);
@@ -160,8 +238,6 @@ private slots:
160238
161239private:
162240 void updatePropertySet (const QVariantMap& properties, bool complainMissing);
163- void requestPropertyUpdate (DBusPropertyCore* property);
164- void pushPropertyUpdate (DBusPropertyCore* property);
165241 void tryUpdateProperty (DBusPropertyCore* property, const QVariant& variant) const ;
166242 [[nodiscard]] QString propertyString (const DBusPropertyCore* property) const ;
167243
@@ -224,7 +300,41 @@ class DBusProperty: public AbstractDBusProperty {
224300private:
225301 T value;
226302
227- friend class DBusPropertyGroup ;
303+ friend class DBusPropertyCore ;
228304};
229305
230306} // namespace qs::dbus
307+
308+ // NOLINTBEGIN
309+ #define QS_DBUS_BINDABLE_PROPERTY_GROUP (Class, name ) qs::dbus::DBusPropertyGroup name {this };
310+
311+ #define QS_DBUS_PROPERTY_BINDING_P (Class, property, bindable, updated, group, name, required ) \
312+ static constexpr size_t _qs_property_##property##_offset() { return offsetof (Class, property); } \
313+ \
314+ qs::dbus::DBusBindableProperty< \
315+ &Class::_qs_property_##property##_offset, \
316+ &Class::bindable, \
317+ updated, \
318+ &Class::group, \
319+ u##name, \
320+ required> \
321+ property;
322+
323+ #define QS_DBUS_PROPERTY_BINDING_7 (Class, property, bindable, updated, group, name, required ) \
324+ QS_DBUS_PROPERTY_BINDING_P (Class, property, bindable, &Class::updated, group, name, required)
325+
326+ #define QS_DBUS_PROPERTY_BINDING_6 (Class, property, bindable, group, name, required ) \
327+ QS_DBUS_PROPERTY_BINDING_P (Class, property, bindable, nullptr , group, name, required)
328+
329+ #define QS_DBUS_PROPERTY_BINDING_5 (Class, property, bindable, group, name ) \
330+ QS_DBUS_PROPERTY_BINDING_6 (Class, property, bindable, group, name, true )
331+
332+ // Q_OBJECT_BINDABLE_PROPERTY elides the warning for the exact same reason,
333+ // so we consider it safe to disable the warning.
334+ // clang-format off
335+ #define QS_DBUS_PROPERTY_BINDING (...) \
336+ QT_WARNING_PUSH QT_WARNING_DISABLE_INVALID_OFFSETOF \
337+ QT_OVERLOADED_MACRO (QS_DBUS_PROPERTY_BINDING, __VA_ARGS__) \
338+ QT_WARNING_POP
339+ // clang-format on
340+ // NOLINTEND
0 commit comments