File indexing completed on 2024-05-12 05:26:02

0001 /*
0002  * Copyright (C) 2014 Christian Mollekopf <chrigi_1@fastmail.fm>
0003  *
0004  *   This program is free software; you can redistribute it and/or modify
0005  *   it under the terms of the GNU General Public License as published by
0006  *   the Free Software Foundation; either version 2 of the License, or
0007  *   (at your option) any later version.
0008  *
0009  *   This program is distributed in the hope that it will be useful,
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *   GNU General Public License for more details.
0013  *
0014  *   You should have received a copy of the GNU General Public License
0015  *   along with this program; if not, write to the
0016  *   Free Software Foundation, Inc.,
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
0018  */
0019 
0020 #pragma once
0021 
0022 #include "sink_export.h"
0023 #include <QVariant>
0024 #include <QByteArray>
0025 #include <functional>
0026 #include <flatbuffers/flatbuffers.h>
0027 
0028 namespace Sink {
0029 namespace ApplicationDomain {
0030 namespace Buffer {
0031     struct MailContact;
0032     struct ContactEmail;
0033 }
0034 }
0035 }
0036 
0037 /**
0038  * Defines how to convert qt primitives to flatbuffer ones
0039  */
0040 template <class T>
0041 flatbuffers::uoffset_t SINK_EXPORT variantToProperty(const QVariant &, flatbuffers::FlatBufferBuilder &fbb);
0042 
0043 /**
0044  * Defines how to convert flatbuffer primitives to qt ones
0045  */
0046 template <typename T>
0047 QVariant SINK_EXPORT propertyToVariant(const flatbuffers::String *);
0048 template <typename T>
0049 QVariant SINK_EXPORT propertyToVariant(uint8_t);
0050 template <typename T>
0051 QVariant SINK_EXPORT propertyToVariant(int);
0052 template <typename T>
0053 QVariant SINK_EXPORT propertyToVariant(const flatbuffers::Vector<uint8_t> *);
0054 template <typename T>
0055 QVariant SINK_EXPORT propertyToVariant(const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *);
0056 template <typename T>
0057 QVariant SINK_EXPORT propertyToVariant(const Sink::ApplicationDomain::Buffer::MailContact *);
0058 template <typename T>
0059 QVariant SINK_EXPORT propertyToVariant(const flatbuffers::Vector<flatbuffers::Offset<Sink::ApplicationDomain::Buffer::MailContact>> *);
0060 template <typename T>
0061 QVariant SINK_EXPORT propertyToVariant(const flatbuffers::Vector<flatbuffers::Offset<Sink::ApplicationDomain::Buffer::ContactEmail>> *);
0062 
0063 /**
0064  * The property mapper is a non-typesafe virtual dispatch.
0065  *
0066  * Instead of using an interface and requring each implementation to override
0067  * a virtual method per property, the property mapper can be filled with accessors
0068  * that extract the properties from resource types.
0069  */
0070 class PropertyMapper
0071 {
0072 public:
0073     virtual ~PropertyMapper(){};
0074 
0075     template <typename T, typename Buffer, typename BufferBuilder, typename FunctionReturnValue, typename Arg>
0076     void addMapping(FunctionReturnValue (Buffer::*f)() const, void (BufferBuilder::*f2)(Arg))
0077     {
0078         addReadMapping<T, Buffer, FunctionReturnValue>(f);
0079         addWriteMapping<T, BufferBuilder>(f2);
0080     }
0081 
0082     virtual QVariant getProperty(const QByteArray &key, void const *buffer) const
0083     {
0084         const auto it = mReadAccessors.constFind(key);
0085         if (it != mReadAccessors.end()) {
0086             const auto accessor = it.value();
0087             return accessor(buffer);
0088         }
0089         Q_ASSERT_X(false, key, "No read accessor for the property");
0090         return {};
0091     }
0092 
0093     virtual void setProperty(const QByteArray &key, const QVariant &value, QList<std::function<void(void *builder)>> &builderCalls, flatbuffers::FlatBufferBuilder &fbb) const
0094     {
0095         const auto it = mWriteAccessors.constFind(key);
0096         if (it != mWriteAccessors.end()) {
0097             const auto accessor = it.value();
0098             builderCalls << accessor(value, fbb);
0099         } else {
0100             Q_ASSERT_X(false, key, "No write accessor for the property");
0101         }
0102     }
0103 
0104     bool hasMapping(const QByteArray &key) const
0105     {
0106         return mReadAccessors.contains(key);
0107     }
0108 
0109     QList<QByteArray> availableProperties() const
0110     {
0111         return mReadAccessors.keys();
0112     }
0113 
0114 private:
0115     void addReadMapping(const QByteArray &property, const std::function<QVariant(void const *)> &mapping)
0116     {
0117         mReadAccessors.insert(property, mapping);
0118     }
0119 
0120     template <typename T, typename Buffer, typename FunctionReturnValue>
0121     void addReadMapping(FunctionReturnValue (Buffer::*f)() const)
0122     {
0123         addReadMapping(T::name, [f](void const *buffer) -> QVariant { return propertyToVariant<typename T::Type>((static_cast<const Buffer*>(buffer)->*f)()); });
0124     }
0125 
0126 
0127     void addWriteMapping(const QByteArray &property, const std::function<std::function<void(void *builder)>(const QVariant &, flatbuffers::FlatBufferBuilder &)> &mapping)
0128     {
0129         mWriteAccessors.insert(property, mapping);
0130     }
0131 
0132     template <typename T, typename BufferBuilder>
0133     void addWriteMapping(void (BufferBuilder::*f)(uint8_t))
0134     {
0135         addWriteMapping(T::name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(void *builder)> {
0136             return [value, f](void *builder) { (static_cast<BufferBuilder*>(builder)->*f)(value.value<typename T::Type>()); };
0137         });
0138     }
0139 
0140     template <typename T, typename BufferBuilder>
0141     void addWriteMapping(void (BufferBuilder::*f)(int))
0142     {
0143         addWriteMapping(T::name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(void *builder)> {
0144             return [value, f](void *builder) { (static_cast<BufferBuilder*>(builder)->*f)(value.value<typename T::Type>()); };
0145         });
0146     }
0147 
0148     template <typename T, typename BufferBuilder>
0149     void addWriteMapping(void (BufferBuilder::*f)(bool))
0150     {
0151         addWriteMapping(T::name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(void *builder)> {
0152             return [value, f](void *builder) { (static_cast<BufferBuilder*>(builder)->*f)(value.value<typename T::Type>()); };
0153         });
0154     }
0155 
0156     template <typename T, typename BufferBuilder, typename Arg>
0157     void addWriteMapping(void (BufferBuilder::*f)(flatbuffers::Offset<Arg>))
0158     {
0159         addWriteMapping(T::name, [f](const QVariant &value, flatbuffers::FlatBufferBuilder &fbb) -> std::function<void(void *builder)> {
0160             auto offset = variantToProperty<typename T::Type>(value, fbb);
0161             return [offset, f](void *builder) { (static_cast<BufferBuilder*>(builder)->*f)(offset); };
0162         });
0163     }
0164 
0165     QHash<QByteArray, std::function<QVariant(void const *)>> mReadAccessors;
0166     QHash<QByteArray, std::function<std::function<void(void *builder)>(const QVariant &, flatbuffers::FlatBufferBuilder &)>> mWriteAccessors;
0167 };
0168