dbus/properties: support data transformation/validation before store

This commit is contained in:
outfoxxed 2024-11-21 03:27:52 -08:00
parent a13c9d91b5
commit d4deb11216
Signed by: outfoxxed
GPG key ID: 4C88A185FB89301E
2 changed files with 83 additions and 18 deletions

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <type_traits>
#include <utility> #include <utility>
#include <bit> #include <bit>
@ -43,7 +44,7 @@ public:
bool isValid() { return !this->error.isValid(); } bool isValid() { return !this->error.isValid(); }
T value; T value {};
QDBusError error; QDBusError error;
}; };
@ -137,6 +138,16 @@ private:
friend class DBusPropertyGroup; friend class DBusPropertyGroup;
}; };
// Default implementation with no transformation
template <typename T>
struct DBusDataTransform {
using Wire = T;
using Data = T;
static DBusResult<Data> fromWire(Wire&& wire) { return DBusResult<T>(std::move(wire)); }
static Wire toWire(const Data& value) { return value; }
};
namespace bindable_p { namespace bindable_p {
template <typename T> template <typename T>
@ -149,9 +160,16 @@ struct BindableParams<B<C, T, O, S>> {
static constexpr size_t OFFSET = O; static constexpr size_t OFFSET = O;
}; };
template <typename Bindable>
struct BindableType {
using Meta = BindableParams<Bindable>;
using Type = Meta::Type;
};
} // namespace bindable_p } // namespace bindable_p
template < template <
typename T,
auto offset, auto offset,
auto bindablePtr, auto bindablePtr,
auto updatedPtr, auto updatedPtr,
@ -160,10 +178,13 @@ template <
bool required> bool required>
class DBusBindableProperty: public DBusPropertyCore { class DBusBindableProperty: public DBusPropertyCore {
using PtrMeta = MemberPointerTraits<decltype(bindablePtr)>; using PtrMeta = MemberPointerTraits<decltype(bindablePtr)>;
using Bindable = PtrMeta::Type;
using Owner = PtrMeta::Class; using Owner = PtrMeta::Class;
using BindableMeta = bindable_p::BindableParams<Bindable>; using Bindable = PtrMeta::Type;
using DataType = BindableMeta::Type; using BindableType = bindable_p::BindableType<Bindable>::Type;
using BaseType = std::conditional_t<std::is_void_v<T>, BindableType, T>;
using Transform = DBusDataTransform<BaseType>;
using DataType = Transform::Data;
using WireType = Transform::Wire;
public: public:
explicit DBusBindableProperty() { this->group()->attachProperty(this); } explicit DBusBindableProperty() { this->group()->attachProperty(this); }
@ -183,20 +204,33 @@ public:
protected: protected:
QDBusError store(const QVariant& variant) override { QDBusError store(const QVariant& variant) override {
auto result = demarshallVariant<DataType>(variant); DBusResult<DataType> result;
if (result.isValid()) { if constexpr (std::is_same_v<WireType, BaseType>) {
this->bindable()->setValue(std::move(result.value)); result = demarshallVariant<DataType>(variant);
} else {
if constexpr (updatedPtr != nullptr) { auto wireResult = demarshallVariant<WireType>(variant);
(this->owner()->*updatedPtr)(); if (!wireResult.isValid()) return wireResult.error;
} result = Transform::fromWire(std::move(wireResult.value));
} }
return result.error; if (!result.isValid()) return result.error;
this->bindable()->setValue(std::move(result.value));
if constexpr (updatedPtr != nullptr) {
(this->owner()->*updatedPtr)();
}
return QDBusError();
} }
QVariant serialize() override { return QVariant::fromValue(this->bindable()->value()); } QVariant serialize() override {
if constexpr (std::is_same_v<WireType, BaseType>) {
return QVariant::fromValue(this->bindable()->value());
} else {
return QVariant::fromValue(Transform::toWire(this->bindable()->value()));
}
}
private: private:
[[nodiscard]] constexpr Owner* owner() const { [[nodiscard]] constexpr Owner* owner() const {
@ -308,10 +342,20 @@ private:
// NOLINTBEGIN // NOLINTBEGIN
#define QS_DBUS_BINDABLE_PROPERTY_GROUP(Class, name) qs::dbus::DBusPropertyGroup name {this}; #define QS_DBUS_BINDABLE_PROPERTY_GROUP(Class, name) qs::dbus::DBusPropertyGroup name {this};
#define QS_DBUS_PROPERTY_BINDING_P(Class, property, bindable, updated, group, name, required) \ #define QS_DBUS_PROPERTY_BINDING_P( \
Class, \
Type, \
property, \
bindable, \
updated, \
group, \
name, \
required \
) \
static constexpr size_t _qs_property_##property##_offset() { return offsetof(Class, property); } \ static constexpr size_t _qs_property_##property##_offset() { return offsetof(Class, property); } \
\ \
qs::dbus::DBusBindableProperty< \ qs::dbus::DBusBindableProperty< \
Type, \
&Class::_qs_property_##property##_offset, \ &Class::_qs_property_##property##_offset, \
&Class::bindable, \ &Class::bindable, \
updated, \ updated, \
@ -320,11 +364,32 @@ private:
required> \ required> \
property; property;
#define QS_DBUS_PROPERTY_BINDING_7(Class, property, bindable, updated, group, name, required) \ #define QS_DBUS_PROPERTY_BINDING_8( \
QS_DBUS_PROPERTY_BINDING_P(Class, property, bindable, &Class::updated, group, name, required) Class, \
Type, \
property, \
bindable, \
updated, \
group, \
name, \
required \
) \
QS_DBUS_PROPERTY_BINDING_P( \
Class, \
Type, \
property, \
bindable, \
&Class::updated, \
group, \
name, \
required \
)
#define QS_DBUS_PROPERTY_BINDING_7(Class, Type, property, bindable, group, name, required) \
QS_DBUS_PROPERTY_BINDING_P(Class, Type, property, bindable, nullptr, group, name, required)
#define QS_DBUS_PROPERTY_BINDING_6(Class, property, bindable, group, name, required) \ #define QS_DBUS_PROPERTY_BINDING_6(Class, property, bindable, group, name, required) \
QS_DBUS_PROPERTY_BINDING_P(Class, property, bindable, nullptr, group, name, required) QS_DBUS_PROPERTY_BINDING_7(Class, void, property, bindable, group, name, required)
#define QS_DBUS_PROPERTY_BINDING_5(Class, property, bindable, group, name) \ #define QS_DBUS_PROPERTY_BINDING_5(Class, property, bindable, group, name) \
QS_DBUS_PROPERTY_BINDING_6(Class, property, bindable, group, name, true) QS_DBUS_PROPERTY_BINDING_6(Class, property, bindable, group, name, true)

View file

@ -457,7 +457,7 @@ private:
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanSeek, bpCanSeek, playerProperties, "CanSeek"); QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanSeek, bpCanSeek, playerProperties, "CanSeek");
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanGoNext, bpCanGoNext, playerProperties, "CanGoNext"); QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanGoNext, bpCanGoNext, playerProperties, "CanGoNext");
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanGoPrevious, bpCanGoPrevious, playerProperties, "CanGoPrevious"); QS_DBUS_PROPERTY_BINDING(MprisPlayer, pCanGoPrevious, bpCanGoPrevious, playerProperties, "CanGoPrevious");
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pPosition, bpPosition, onPositionUpdated, playerProperties, "Position", false); QS_DBUS_PROPERTY_BINDING(MprisPlayer, qlonglong, pPosition, bpPosition, onPositionUpdated, playerProperties, "Position", false);
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pVolume, bVolume, playerProperties, "Volume", false); QS_DBUS_PROPERTY_BINDING(MprisPlayer, pVolume, bVolume, playerProperties, "Volume", false);
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pMetadata, bpMetadata, playerProperties, "Metadata"); QS_DBUS_PROPERTY_BINDING(MprisPlayer, pMetadata, bpMetadata, playerProperties, "Metadata");
QS_DBUS_PROPERTY_BINDING(MprisPlayer, pPlaybackStatus, bpPlaybackStatus, playerProperties, "PlaybackStatus"); QS_DBUS_PROPERTY_BINDING(MprisPlayer, pPlaybackStatus, bpPlaybackStatus, playerProperties, "PlaybackStatus");