Skip to content

Commit 1955dee

Browse files
committed
dbus/properties: add QObjectBindableProperty based dbus property
Many times more lightweight than the original QObject-based one.
1 parent 4163713 commit 1955dee

File tree

3 files changed

+151
-15
lines changed

3 files changed

+151
-15
lines changed

src/core/util.hpp

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,45 @@
22
#include <algorithm>
33
#include <type_traits>
44

5+
#include <bit>
56
#include <qlatin1stringview.h>
67
#include <qobject.h>
78
#include <qproperty.h>
9+
#include <qstringview.h>
810
#include <qtclasshelpermacros.h>
911
#include <qtmetamacros.h>
1012

11-
template <size_t Length>
13+
template <size_t length>
1214
struct StringLiteral {
13-
constexpr StringLiteral(const char (&str)[Length]) { // NOLINT
14-
std::copy_n(str, Length, this->value);
15+
constexpr StringLiteral(const char (&str)[length]) { // NOLINT
16+
std::copy_n(str, length, this->value);
1517
}
1618

1719
constexpr operator const char*() const noexcept { return this->value; }
18-
operator QLatin1StringView() const { return QLatin1String(this->value, Length); }
20+
operator QLatin1StringView() const { return QLatin1String(this->value, length); }
1921

20-
char value[Length]; // NOLINT
22+
char value[length]; // NOLINT
23+
};
24+
25+
template <size_t length>
26+
struct StringLiteral16 {
27+
constexpr StringLiteral16(const char16_t (&str)[length]) { // NOLINT
28+
std::copy_n(str, length, this->value);
29+
}
30+
31+
[[nodiscard]] constexpr const QChar* qCharPtr() const noexcept {
32+
return std::bit_cast<const QChar*>(&this->value);
33+
}
34+
35+
[[nodiscard]] Q_ALWAYS_INLINE operator QString() const noexcept {
36+
return QString::fromRawData(this->qCharPtr(), static_cast<qsizetype>(length - 1));
37+
}
38+
39+
[[nodiscard]] Q_ALWAYS_INLINE operator QStringView() const noexcept {
40+
return QStringView(this->qCharPtr(), static_cast<qsizetype>(length - 1));
41+
}
42+
43+
char16_t value[length]; // NOLINT
2144
};
2245

2346
// NOLINTBEGIN
@@ -149,11 +172,10 @@ public:
149172
// NOLINTEND
150173

151174
template <typename T>
152-
class MemberPointerTraits;
175+
struct MemberPointerTraits;
153176

154177
template <typename T, typename C>
155-
class MemberPointerTraits<T C::*> {
156-
public:
178+
struct MemberPointerTraits<T C::*> {
157179
using Class = C;
158180
using Type = T;
159181
};

src/dbus/properties.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ void DBusPropertyGroup::attachProperty(AbstractDBusProperty* property) {
162162
property->group = this;
163163
}
164164

165+
void DBusPropertyGroup::attachProperty(DBusPropertyCore* property) {
166+
this->properties.append(property);
167+
}
168+
165169
void DBusPropertyGroup::updateAllDirect() {
166170
qCDebug(logDbusProperties).noquote()
167171
<< "Updating all properties of" << this->toString() << "via individual queries";

src/dbus/properties.hpp

Lines changed: 117 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <functional>
44
#include <utility>
55

6+
#include <bit>
67
#include <qcontainerfwd.h>
78
#include <qdbusabstractinterface.h>
89
#include <qdbuserror.h>
@@ -14,10 +15,14 @@
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+
2126
class DBusPropertiesInterface;
2227

2328
Q_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+
135211
class DBusPropertyGroup: public QObject {
136212
Q_OBJECT;
137213

138214
public:
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+
150228
signals:
151229
void getAllFinished();
152230
void getAllFailed(QDBusError error);
@@ -160,8 +238,6 @@ private slots:
160238

161239
private:
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 {
224300
private:
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

Comments
 (0)