#ifndef QTMVVM_SERVICEREGISTRY_H #define QTMVVM_SERVICEREGISTRY_H #include #include #include #include #include "QtMvvmCore/qtmvvmcore_global.h" #include "QtMvvmCore/injection.h" namespace QtMvvm { class ServiceRegistryPrivate; //! A singleton to prepare services for dependency injection and to access them class Q_MVVMCORE_EXPORT ServiceRegistry { public: enum DestructionScope { DestroyOnAppQuit = 1, DestroyOnAppDestroy = 2, DestroyOnRegistryDestroy = 3, DestroyNever = 127 }; //! @private ServiceRegistry(ServiceRegistryPrivate *d_ptr); ~ServiceRegistry(); //! Returns the ServiceRegistry singleton instance static ServiceRegistry* instance(); //! Checks if a given interface or service is already registered template bool isRegistered() const; //! @copybrief ServiceRegistry::isRegistered() bool isRegistered(const QByteArray &iid) const; //! Register a service for its interface via the type template void registerInterface(bool weak = false, DestructionScope scope = DestroyOnAppDestroy); //! Register a service for its interface via a constructor function template void registerInterface(TFunc fn, bool weak = false, DestructionScope scope = DestroyOnAppDestroy); //! Register a service for its interface via an already existing instance template void registerInterface(TService *service, bool weak = false, DestructionScope scope = DestroyOnAppDestroy); //! Register a service via its type template void registerObject(bool weak = false, DestructionScope scope = DestroyOnAppDestroy); //! Register a service via a constructor function template void registerObject(TFunc fn, bool weak = false, DestructionScope scope = DestroyOnAppDestroy); //! Register a service via an already existing instance template void registerObject(TService *service, bool weak = false, DestructionScope scope = DestroyOnAppDestroy); //! Register a service by an iid via their metadata void registerService(const QByteArray &iid, const QMetaObject *metaObject, bool weak, DestructionScope scope); void registerService(const QByteArray &iid, const QMetaObject *metaObject, bool weak = false); //MAJOR merge methods //! Register a service by an iid via a generalized constructor function void registerService(const QByteArray &iid, const std::function &fn, QByteArrayList injectables, bool weak, DestructionScope scope); void registerService(const QByteArray &iid, const std::function &fn, QByteArrayList injectables, bool weak = false);//MAJOR merge methods //! Returns the service for the given interface template TInterface *service(); //! Returns the service for the given iid QObject *serviceObj(const QByteArray &iid); //! Inject services for all injectable properties on object void injectServices(QObject *object); //! Constructs a new instance of TClass with properties injected template TClass *constructInjected(QObject *parent = nullptr); //! Constructs a new instance of metaObject with properties injected QObject *constructInjected(const QMetaObject *metaObject, QObject *parent = nullptr); private: friend class QtMvvm::ServiceRegistryPrivate; QScopedPointer d; }; //! Is thrown if a service is beeing registered that is already registered class Q_MVVMCORE_EXPORT ServiceExistsException : public QException { public: //! @private ServiceExistsException(const QByteArray &iid); //! @inherit{QException::what} const char *what() const noexcept override; //! @inherit{QException::raise} void raise() const override; //! @inherit{QException::clone} QException *clone() const override; protected: //! @private ServiceExistsException(const ServiceExistsException * const other); //! @private const QByteArray _msg; }; //! Is thrown in case the construction of a service has failed class Q_MVVMCORE_EXPORT ServiceConstructionException : public QException { public: //! @private ServiceConstructionException(const QByteArray &message); //! @inherit{QException::what} const char *what() const noexcept override; //! @inherit{QException::raise} void raise() const override; //! @inherit{QException::clone} QException *clone() const override; protected: //! @private ServiceConstructionException(const ServiceConstructionException * const other); //! @private const QByteArray _msg; }; //! Is thrown if a service could not be created because of a missing dependency to be injected class Q_MVVMCORE_EXPORT ServiceDependencyException : public ServiceConstructionException { public: //! @private ServiceDependencyException(const QByteArray &iid); void raise() const override; QException *clone() const override; protected: //! @private ServiceDependencyException(const ServiceDependencyException * const other); }; // ------------- Generic Implementation ------------- template bool ServiceRegistry::isRegistered() const { return isRegistered(__helpertypes::inject_iid()); } #define QTMVVM_SERVICE_ASSERT(tint, tsvc) \ static_assert(__helpertypes::is_valid_interface::value, "TService must implement the given TInterface interface and be a qobject class"); \ Q_ASSERT_X(qobject_interface_iid(), Q_FUNC_INFO, "TInterface must be registered with Q_DECLARE_INTERFACE"); template void ServiceRegistry::registerInterface(bool weak, DestructionScope scope) { QTMVVM_SERVICE_ASSERT(TInterface, TService) registerService(qobject_interface_iid(), &TService::staticMetaObject, weak, scope); } template void ServiceRegistry::registerInterface(TFunc fn, bool weak, DestructionScope scope) { QTMVVM_SERVICE_ASSERT(TInterface, TService) QByteArrayList injectables; auto packed_fn = __helpertypes::pack_function(std::move(fn), injectables); registerService(qobject_interface_iid(), packed_fn, injectables, weak, scope); } template void ServiceRegistry::registerInterface(TService *service, bool weak, DestructionScope scope) { QTMVVM_SERVICE_ASSERT(TInterface, TService) registerService(qobject_interface_iid(), [service](const QObjectList ¶ms) -> QObject* { Q_UNUSED(params); return service; }, QByteArrayList(), weak, scope); } #undef QTMVVM_SERVICE_ASSERT #define QTMVVM_SERVICE_ASSERT(tsvc) \ static_assert(__helpertypes::is_qobj::value, "TService must be a qobject class"); template void ServiceRegistry::registerObject(bool weak, DestructionScope scope) { QTMVVM_SERVICE_ASSERT(TService) registerService(__helpertypes::qobject_iid(), &TService::staticMetaObject, weak, scope); } template void ServiceRegistry::registerObject(TFunc fn, bool weak, DestructionScope scope) { QTMVVM_SERVICE_ASSERT(TService) QByteArrayList injectables; auto packed_fn = __helpertypes::pack_function(std::move(fn), injectables); registerService(__helpertypes::qobject_iid(), packed_fn, injectables, weak, scope); } template void ServiceRegistry::registerObject(TService *service, bool weak, DestructionScope scope) { QTMVVM_SERVICE_ASSERT(TService) registerService(__helpertypes::qobject_iid(), [service](const QObjectList ¶ms) -> QObject* { Q_UNUSED(params); return service; }, QByteArrayList(), weak, scope); } #undef QTMVVM_SERVICE_ASSERT template TInterface *ServiceRegistry::service() { return qobject_cast(serviceObj(__helpertypes::inject_iid())); } template TClass *ServiceRegistry::constructInjected(QObject *parent) { static_assert(__helpertypes::is_qobj::value, "TClass must be a qobject class"); return qobject_cast(constructInjected(&TClass::staticMetaObject, parent)); } } #endif // QTMVVM_SERVICEREGISTRY_H