/* Copyright (C) 2014 * swift project Community / Contributors * * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level * directory of this distribution. No part of swift project, including this file, may be copied, modified, propagated, * or distributed except according to the terms contained in the LICENSE file. */ //! \file #ifndef BLACKMISC_VARIANT_PRIVATE_H #define BLACKMISC_VARIANT_PRIVATE_H #include "blackmisc/blackmiscexport.h" #include "blackmisc/inheritancetraits.h" #include #include #include #include #include #include namespace BlackMisc { class CEmpty; class CVariant; class CPropertyIndex; class CIcon; template void registerMetaValueType(); namespace Private { //! \private Needed so we can copy forward-declared CVariant. void assign(CVariant &, const CVariant &); //! \private Needed so we can copy forward-declared CIcon. void assign(CIcon &, const CIcon &); //! \private Abstract base class representing the set of operations supported by a particular value type. struct BLACKMISC_EXPORT IValueObjectMetaInfo { virtual ~IValueObjectMetaInfo() = default; virtual QString toQString(const void *object, bool i18n) const = 0; virtual QJsonObject toJson(const void *object) const = 0; virtual void convertFromJson(const QJsonObject &json, void *object) const = 0; virtual QJsonObject toMemoizedJson(const void *object) const = 0; virtual void convertFromMemoizedJson(const QJsonObject &json, void *object, bool allowFallbackToJson) const = 0; virtual void unmarshall(const QDBusArgument &arg, void *object) const = 0; virtual uint getValueHash(const void *object) const = 0; virtual int getMetaTypeId() const = 0; virtual const void *upCastTo(const void *object, int metaTypeId) const = 0; virtual int compareImpl(const void *lhs, const void *rhs) const = 0; virtual void setPropertyByIndex(void *object, const CVariant &variant, const CPropertyIndex &index) const = 0; virtual void propertyByIndex(const void *object, CVariant &o_variant, const BlackMisc::CPropertyIndex &index) const = 0; virtual QString propertyByIndexAsString(const void *object, const CPropertyIndex &index, bool i18n) const = 0; virtual bool equalsPropertyByIndex(const void *object, const CVariant &compareValue, const CPropertyIndex &index) const = 0; virtual void toIcon(const void *object, CIcon &o_icon) const = 0; }; //! \private Exception to signal that an unsupported operation was requested. class CVariantException : public std::invalid_argument { public: template CVariantException(const T &, const QString &opName) : CVariantException(qMetaTypeId(), opName) {} CVariantException(int typeId, const QString &opName) : std::invalid_argument((blurb(typeId, opName)).toStdString()), m_operationName(opName) {} const QString &operationName() const { return m_operationName; } ~CVariantException() {} private: QString m_operationName; static QString blurb(int typeId, const QString &operationName) { return QString("CVariant requested unsupported operation of contained ") + QMetaType::typeName(typeId) + " object: " + operationName; } }; //! \private Helper using expression SFINAE to select the correct method implementations. struct CValueObjectMetaInfoHelper { template static QJsonObject toJson(const T &object, decltype(static_cast(object.toJson()), 0)) { return object.toJson(); } template static QJsonObject toJson(const T &object, ...) { throw CVariantException(object, "toJson"); } template static void convertFromJson(const QJsonObject &json, T &object, decltype(static_cast(object.convertFromJson(json)), 0)) { object.convertFromJson(json); } template static void convertFromJson(const QJsonObject &, T &object, ...) { throw CVariantException(object, "convertFromJson"); } template static QJsonObject toMemoizedJson(const T &object, decltype(static_cast(object.toMemoizedJson()), 0)) { return object.toMemoizedJson(); } template static QJsonObject toMemoizedJson(const T &object, ...) { return toJson(object, 0); } template static void convertFromMemoizedJson(const QJsonObject &json, T &object, bool allowFallbackToJson, decltype(static_cast(object.convertFromMemoizedJson(json, allowFallbackToJson)), 0)) { object.convertFromMemoizedJson(json, allowFallbackToJson); } template static void convertFromMemoizedJson(const QJsonObject &json, T &object, bool allowFallbackToJson, ...) { convertFromJson(json, object, 0); Q_UNUSED(allowFallbackToJson) } template static uint getValueHash(const T &object, decltype(static_cast(qHash(object)), 0)) { return qHash(object); } template static uint getValueHash(const T &object, ...) { throw CVariantException(object, "getValueHash"); } template static int compareImpl(const T &lhs, const T &rhs, decltype(static_cast(compare(lhs, rhs)), 0)) { return compare(lhs, rhs); } template static int compareImpl(const T &lhs, const T &, ...) { throw CVariantException(lhs, "compare"); } template static void setPropertyByIndex(T &object, const CVariant &variant, const CPropertyIndex &index, decltype(static_cast(object.setPropertyByIndex(index, variant)), 0)) { object.setPropertyByIndex(index, variant); } template static void setPropertyByIndex(T &object, const CVariant &, const CPropertyIndex &, ...) { throw CVariantException(object, "setPropertyByIndex"); } template static void propertyByIndex(CVariant &o_variant, const T &object, const CPropertyIndex &index, decltype(static_cast(object.propertyByIndex(index)), 0)) { assign(o_variant, object.propertyByIndex(index)); } template static void propertyByIndex(CVariant &, const T &object, const CPropertyIndex &, ...) { throw CVariantException(object, "propertyByIndex"); } template static QString propertyByIndexAsString(const T &object, const CPropertyIndex &index, bool i18n, decltype(static_cast(object.propertyByIndexAsString(index, i18n)), 0)) { return object.propertyByIndexAsString(index, i18n); } template static QString propertyByIndexAsString(const T &object, const CPropertyIndex &, bool, ...) { throw CVariantException(object, "propertyByIndexAsString"); } template static bool equalsPropertyByIndex(const T &object, const CVariant &variant, const CPropertyIndex &index, decltype(static_cast(object.equalsPropertyByIndex(variant, index)), 0)) { return object.equalsPropertyByIndex(variant, index); } template static bool equalsPropertyByIndex(const T &object, const CVariant &, const CPropertyIndex &, ...) { throw CVariantException(object, "equalsPropertyByIndex"); } template static void toIcon(const T &object, CIcon &o_icon, std::enable_if_t < ! std::is_same::value, decltype(static_cast(object.toIcon()), 0) >) { assign(o_icon, object.toIcon()); } template static void toIcon(const T &object, CIcon &, ...) { throw CVariantException(object, "toIcon"); } }; //! \private Implementation of IValueObjectMetaInfo representing the set of operations supported by T. template struct CValueObjectMetaInfo : public IValueObjectMetaInfo { virtual QString toQString(const void *object, bool i18n) const override { return cast(object).toQString(i18n); } virtual QJsonObject toJson(const void *object) const override { return CValueObjectMetaInfoHelper::toJson(cast(object), 0); } virtual void convertFromJson(const QJsonObject &json, void *object) const override { CValueObjectMetaInfoHelper::convertFromJson(json, cast(object), 0); } virtual QJsonObject toMemoizedJson(const void *object) const override { return CValueObjectMetaInfoHelper::toMemoizedJson(cast(object), 0); } virtual void convertFromMemoizedJson(const QJsonObject &json, void *object, bool allowFallbackToJson) const override { CValueObjectMetaInfoHelper::convertFromMemoizedJson(json, cast(object), allowFallbackToJson, 0); } virtual void unmarshall(const QDBusArgument &arg, void *object) const override { arg >> cast(object); } virtual uint getValueHash(const void *object) const override { return CValueObjectMetaInfoHelper::getValueHash(cast(object), 0); } virtual int getMetaTypeId() const override { return maybeGetMetaTypeId(std::integral_constant::Defined> {}); } virtual const void *upCastTo(const void *object, int metaTypeId) const override { const auto base = static_cast(static_cast *>(&cast(object))); return metaTypeId == getMetaTypeId() ? object : CValueObjectMetaInfo> {} .upCastTo(base, metaTypeId); } virtual int compareImpl(const void *lhs, const void *rhs) const override { return CValueObjectMetaInfoHelper::compareImpl(cast(lhs), cast(rhs), 0); } virtual void setPropertyByIndex(void *object, const CVariant &variant, const CPropertyIndex &index) const override { CValueObjectMetaInfoHelper::setPropertyByIndex(cast(object), variant, index, 0); } virtual void propertyByIndex(const void *object, CVariant &o_variant, const BlackMisc::CPropertyIndex &index) const override { CValueObjectMetaInfoHelper::propertyByIndex(o_variant, cast(object), index, 0); } virtual QString propertyByIndexAsString(const void *object, const CPropertyIndex &index, bool i18n) const override { return CValueObjectMetaInfoHelper::propertyByIndexAsString(cast(object), index, i18n, 0); } virtual bool equalsPropertyByIndex(const void *object, const CVariant &compareValue, const CPropertyIndex &index) const override { return CValueObjectMetaInfoHelper::equalsPropertyByIndex(cast(object), compareValue, index, 0); } virtual void toIcon(const void *object, CIcon &o_icon) const override { CValueObjectMetaInfoHelper::toIcon(cast(object), o_icon, 0); } static const T &cast(const void *object) { return *static_cast(object); } static T &cast(void *object) { return *static_cast(object); } static int maybeGetMetaTypeId(std::true_type) { return qMetaTypeId(); } static int maybeGetMetaTypeId(std::false_type) { return QMetaType::UnknownType; } }; //! \private Explicit specialization for the terminating case of the recursive CValueObjectMetaInfo::upCastTo. template <> struct CValueObjectMetaInfo { const void *upCastTo(const void *, int) const { return nullptr; } }; //! \private Getter to obtain the IValueObjectMetaInfo which was stored by BlackMisc::registerMetaValueType. IValueObjectMetaInfo *getValueObjectMetaInfo(int typeId); //! \private Getter to obtain the IValueObjectMetaInfo which was stored by BlackMisc::registerMetaValueType. IValueObjectMetaInfo *getValueObjectMetaInfo(const QVariant &); //! \private Getter to obtain the IValueObjectMetaInfo which was stored by BlackMisc::registerMetaValueType. template IValueObjectMetaInfo *getValueObjectMetaInfo() { return getValueObjectMetaInfo(qMetaTypeId()); } //! \cond PRIVATE template struct MetaTypeHelperImpl { static constexpr int maybeGetMetaTypeId() { return qMetaTypeId(); } static void maybeRegisterMetaType() { qRegisterMetaType(); qDBusRegisterMetaType(); registerMetaValueType(); } }; template struct MetaTypeHelperImpl { static constexpr int maybeGetMetaTypeId() { return QMetaType::UnknownType; } static void maybeRegisterMetaType() {} }; template using MetaTypeHelper = MetaTypeHelperImpl::Defined>; //! \endcond } } Q_DECLARE_METATYPE(BlackMisc::Private::IValueObjectMetaInfo *) #endif