Issue #77 Move mixin classes to separate files

By separating them from unrelated code, their dependents
can use them without depending on unrelated code, which
in turn helps to reduce cyclic dependencies.
This commit is contained in:
Mat Sutcliffe
2020-08-25 23:31:23 +01:00
parent 4a6d94b6d4
commit b80114213d
129 changed files with 1207 additions and 969 deletions

View File

@@ -11,132 +11,13 @@
#ifndef BLACKMISC_DBUS_H
#define BLACKMISC_DBUS_H
#include "blackmisc/metaclass.h"
#include "blackmisc/inheritancetraits.h"
#include "blackmisc/typetraits.h"
#include "blackmisc/blackmiscexport.h"
#include <QFlags>
#include <QDBusArgument>
#include <type_traits>
namespace BlackMisc
{
class CEmpty;
/*!
* Tag type signifying overloaded marshalling methods that preserve data at the expense of size.
*/
class LosslessTag {};
// *INDENT-OFF*
namespace Private
{
//! \cond PRIVATE
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
void marshallMember(QDBusArgument &arg, const T &value, std::false_type) { value.marshallToDbus(arg); }
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
void marshallMember(QDBusArgument &arg, const T &value, std::true_type) { value.marshallToDbus(arg, LosslessTag()); }
template <class T, std::enable_if_t<!THasMarshallMethods<T>::value, int> = 0>
void marshallMember(QDBusArgument &arg, const T &value, std::false_type) { arg << value; }
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
void unmarshallMember(const QDBusArgument &arg, T &value, std::false_type) { value.unmarshallFromDbus(arg); }
template <class T, std::enable_if_t<THasMarshallMethods<T>::value, int> = 0>
void unmarshallMember(const QDBusArgument &arg, T &value, std::true_type) { value.unmarshallFromDbus(arg, LosslessTag()); }
template <class T, std::enable_if_t<!THasMarshallMethods<T>::value, int> = 0>
void unmarshallMember(const QDBusArgument &arg, T &value, std::false_type) { arg >> value; }
//! \endcond
}
// *INDENT-ON*
namespace Mixin
{
/*!
* CRTP class template which will generate marshalling operators for a derived class with its own marshalling implementation.
*
* \tparam Derived Must implement public methods void marshallToDbus(QDBusArgument &arg) const and void unmarshallFromDbus(const QDBusArgument &arg).
*/
template <class Derived, class...>
class DBusOperators
{
public:
//! Unmarshalling operator >>, DBus to object
friend const QDBusArgument &operator>>(const QDBusArgument &arg, Derived &obj)
{
arg.beginStructure();
obj.unmarshallFromDbus(arg);
arg.endStructure();
return arg;
}
//! Marshalling operator <<, object to DBus
friend QDBusArgument &operator<<(QDBusArgument &arg, const Derived &obj)
{
arg.beginStructure();
obj.marshallToDbus(arg);
arg.endStructure();
return arg;
}
};
template <class Derived>
class DBusOperators<Derived, LosslessTag> {};
/*!
* CRTP class template from which a derived class can inherit common methods dealing with marshalling instances by metaclass.
*
* \see BLACKMISC_DECLARE_USING_MIXIN_DBUS
*/
template <class Derived, class... Tags>
class DBusByMetaClass : public DBusOperators<Derived, Tags...>
{
public:
//! Marshall without begin/endStructure, for when composed within another object
void marshallToDbus(QDBusArgument &arg, Tags...) const
{
baseMarshall(static_cast<const TBaseOfT<Derived> *>(derived()), arg);
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForMarshalling>());
meta.forEachMember([ &, this ](auto member)
{
using lossless = std::integral_constant<bool, member.has(MetaFlags<LosslessMarshalling>())>;
Private::marshallMember(arg, member.in(*this->derived()), lossless());
});
}
//! Unmarshall without begin/endStructure, for when composed within another object
void unmarshallFromDbus(const QDBusArgument &arg, Tags...)
{
baseUnmarshall(static_cast<TBaseOfT<Derived> *>(derived()), arg);
constexpr auto meta = introspect<Derived>().without(MetaFlags<DisabledForMarshalling>());
meta.forEachMember([ &, this ](auto member)
{
using lossless = std::integral_constant<bool, member.has(MetaFlags<LosslessMarshalling>())>;
Private::unmarshallMember(arg, member.in(*this->derived()), lossless());
});
}
private:
const Derived *derived() const { return static_cast<const Derived *>(this); }
Derived *derived() { return static_cast<Derived *>(this); }
template <typename T> static void baseMarshall(const T *base, QDBusArgument &arg) { base->marshallToDbus(arg, Tags()...); }
template <typename T> static void baseUnmarshall(T *base, const QDBusArgument &arg) { base->unmarshallFromDbus(arg, Tags()...); }
static void baseMarshall(const void *, QDBusArgument &) {}
static void baseUnmarshall(void *, const QDBusArgument &) {}
static void baseMarshall(const CEmpty *, QDBusArgument &) {}
static void baseUnmarshall(CEmpty *, const QDBusArgument &) {}
};
// *INDENT-OFF*
/*!
* When a derived class and a base class both inherit from Mixin::DBusByTuple,
* the derived class uses this macro to disambiguate the inherited members.
*/
# define BLACKMISC_DECLARE_USING_MIXIN_DBUS(DERIVED, ...) \
using ::BlackMisc::Mixin::DBusByMetaClass<DERIVED BLACK_TRAILING_VA_ARGS(__VA_ARGS__)>::marshallToDbus; \
using ::BlackMisc::Mixin::DBusByMetaClass<DERIVED BLACK_TRAILING_VA_ARGS(__VA_ARGS__)>::unmarshallFromDbus;
// *INDENT-ON*
} // Mixin
} // BlackMisc
#include <utility>
#include <string>
/*!
* Non member non-friend streaming for std::string