From 40c0c98a027b5d26f23ced7c954a6c4a506d019a Mon Sep 17 00:00:00 2001 From: Skycoder42 Date: Fri, 9 Feb 2018 22:19:50 +0100 Subject: [PATCH] . --- examples/mvvmwidgets/SampleWidgets/main.cpp | 27 +++---- src/mvvmcore/qtmvvmcore_helpertypes.h | 16 ++-- src/mvvmcore/serviceregistry.cpp | 81 ++++++++++++++++++++- src/mvvmcore/serviceregistry.h | 6 +- src/mvvmcore/serviceregistry_p.h | 42 +++++++++++ 5 files changed, 142 insertions(+), 30 deletions(-) diff --git a/examples/mvvmwidgets/SampleWidgets/main.cpp b/examples/mvvmwidgets/SampleWidgets/main.cpp index 8c47a49..7a244b1 100644 --- a/examples/mvvmwidgets/SampleWidgets/main.cpp +++ b/examples/mvvmwidgets/SampleWidgets/main.cpp @@ -5,35 +5,32 @@ #include "widgetseventservice.h" -struct test : public QObject { - IEventService *i; - EchoService *s; - - test(IEventService *i, EchoService *s) : - i(i), - s(s) - {} -}; +#define TEST_DIRECT 0 +#define TEST_FN 1 +#define TEST_INST 2 +#define TEST_CURRENT TEST_DIRECT int main(int argc, char *argv[]) { QApplication a(argc, argv); - QtMvvm::ServiceRegistry::instance()->registerObject(); - if (false) { + if(TEST_CURRENT == TEST_DIRECT) + QtMvvm::ServiceRegistry::instance()->registerObject(); + if(TEST_CURRENT == TEST_FN) QtMvvm::ServiceRegistry::instance()->registerObject([]() { return new EchoService(nullptr); }); + if(TEST_CURRENT == TEST_INST) QtMvvm::ServiceRegistry::instance()->registerObject(new EchoService()); - } - QtMvvm::ServiceRegistry::instance()->registerInterface(); - if (false) { + if(TEST_CURRENT == TEST_DIRECT) + QtMvvm::ServiceRegistry::instance()->registerInterface(); + if(TEST_CURRENT == TEST_FN) QtMvvm::ServiceRegistry::instance()->registerInterface([](EchoService *echo) { return new WidgetsEventService(echo, nullptr); }); + if(TEST_CURRENT == TEST_INST) QtMvvm::ServiceRegistry::instance()->registerInterface(new WidgetsEventService()); - } return a.exec(); } diff --git a/src/mvvmcore/qtmvvmcore_helpertypes.h b/src/mvvmcore/qtmvvmcore_helpertypes.h index 4abc41c..bf91257 100644 --- a/src/mvvmcore/qtmvvmcore_helpertypes.h +++ b/src/mvvmcore/qtmvvmcore_helpertypes.h @@ -52,19 +52,19 @@ inline QByteArray inject_iid() { } template -inline Q_CONSTEXPR std::function pack_function_imp(const TFunc &fn, QByteArrayList &injectables) { +inline Q_CONSTEXPR std::function pack_function_imp(const TFunc &fn, QByteArrayList &injectables) { injectables.append(inject_iid()); - auto subFn = [fn](const QVariantList ¶ms, int index, TArgs... tArgs) { + auto subFn = [fn](const QObjectList ¶ms, int index, TArgs... tArgs) { --index; - return fn(params, index, params[index].template value(), tArgs...); + return fn(params, index, qobject_cast(params[index]), tArgs...); }; return pack_function_imp(subFn, injectables); } template -inline Q_CONSTEXPR std::function pack_function_imp(const TFunc &fn, QByteArrayList &injectables) { +inline Q_CONSTEXPR std::function pack_function_imp(const TFunc &fn, QByteArrayList &injectables) { Q_UNUSED(injectables) - return [fn](const QVariantList ¶ms) { + return [fn](const QObjectList ¶ms) { return fn(params, params.size()); }; } @@ -76,8 +76,8 @@ template struct fn_info { template - static inline Q_CONSTEXPR std::function pack(const TFunctor &fn, QByteArrayList &injectables) { - auto subFn = [fn](const QVariantList ¶ms, int index, TArgs... args) -> QObject* { + static inline Q_CONSTEXPR std::function pack(const TFunctor &fn, QByteArrayList &injectables) { + auto subFn = [fn](const QObjectList ¶ms, int index, TArgs... args) -> QObject* { Q_UNUSED(params) Q_ASSERT_X(index == 0, Q_FUNC_INFO, "number of params does not equal recursion depth"); return fn(args...); @@ -87,7 +87,7 @@ struct fn_info }; template -inline Q_CONSTEXPR std::function pack_function(const TFunc &fn, QByteArrayList &injectables) { +inline Q_CONSTEXPR std::function pack_function(const TFunc &fn, QByteArrayList &injectables) { return fn_info::pack(fn, injectables); } diff --git a/src/mvvmcore/serviceregistry.cpp b/src/mvvmcore/serviceregistry.cpp index 8b5d11c..9b6c687 100644 --- a/src/mvvmcore/serviceregistry.cpp +++ b/src/mvvmcore/serviceregistry.cpp @@ -2,6 +2,8 @@ #include "serviceregistry_p.h" #include +#include +#include using namespace QtMvvm; @@ -19,17 +21,88 @@ ServiceRegistry *ServiceRegistry::instance() void ServiceRegistry::registerService(const QByteArray &iid, const QMetaObject *metaObject) { - //TODO create function with injectables and pass to other overload + QMutexLocker _(&d->serviceMutex); + Q_ASSERT(!d->services.contains(iid)); //TODO exception + d->services.insert(iid, QSharedPointer::create(metaObject)); } -void ServiceRegistry::registerService(const QByteArray &iid, const std::function &fn, QByteArrayList injectables) +void ServiceRegistry::registerService(const QByteArray &iid, const std::function &fn, QByteArrayList injectables) { - + QMutexLocker _(&d->serviceMutex); + Q_ASSERT(!d->services.contains(iid)); //TODO exception + d->services.insert(iid, QSharedPointer::create(fn, injectables)); } // ------------- Private Implementation ------------- -ServiceRegistryPrivate::ServiceRegistryPrivate() +ServiceRegistryPrivate::ServiceRegistryPrivate() : + serviceMutex(), + services() +{} + + + +ServiceRegistryPrivate::ServiceInfo::ServiceInfo() : + _instance(nullptr) +{} + +ServiceRegistryPrivate::ServiceInfo::~ServiceInfo() +{ + if(_instance) + QMetaObject::invokeMethod(_instance, "deleteLater"); +} + +QObject *ServiceRegistryPrivate::ServiceInfo::instance(ServiceRegistryPrivate *d) +{ + if(!_instance) + _instance = construct(d); + return _instance; +} + + + +ServiceRegistryPrivate::FnServiceInfo::FnServiceInfo(const std::function &creator, const QByteArrayList &injectables) : + creator(creator), + injectables(injectables) +{} + +QObject *ServiceRegistryPrivate::FnServiceInfo::construct(ServiceRegistryPrivate *d) const +{ + QObjectList params; + foreach(auto inj, injectables) + params.append(d->services.value(inj)->instance(d));//TODO exception + return creator(params); +} + + + +ServiceRegistryPrivate::MetaServiceInfo::MetaServiceInfo(const QMetaObject *metaObject) : + metaObject(metaObject) +{} + +QObject *ServiceRegistryPrivate::MetaServiceInfo::construct(ServiceRegistryPrivate *d) const { + auto instance = metaObject->newInstance(); + Q_ASSERT(instance); //TODO exception + + static QRegularExpression nameRegex(QStringLiteral(R"__(^__qtmvvm_inject_(.+)$)__"), + QRegularExpression::OptimizeOnFirstUsageOption); + + for(auto i = 0; i < metaObject->propertyCount(); i++) { + auto prop = metaObject->property(i); + auto match = nameRegex.match(QString::fromUtf8(prop.name())); + if(match.hasMatch()) { + auto tPropIndex = metaObject->indexOfProperty(qUtf8Printable(match.captured(1))); + if(tPropIndex == -1) + continue; //TODO warning + auto tProp = metaObject->property(tPropIndex); + + auto inject = prop.read(instance).toByteArray(); + auto injObj = d->services.value(inject)->instance(d); //TODO exception + tProp.write(instance, QVariant::fromValue(injObj)); //TODO check if casting works + } + } + //TODO call "init" method + return instance; } diff --git a/src/mvvmcore/serviceregistry.h b/src/mvvmcore/serviceregistry.h index e287e24..b254cef 100644 --- a/src/mvvmcore/serviceregistry.h +++ b/src/mvvmcore/serviceregistry.h @@ -34,7 +34,7 @@ public: void registerService(const QByteArray &iid, const QMetaObject *metaObject); void registerService(const QByteArray &iid, - const std::function &fn, + const std::function &fn, QByteArrayList injectables); private: @@ -65,7 +65,7 @@ template void ServiceRegistry::registerInterface(TService *service) { QTMVVM_SERVICE_ASSERT(TInterface, TService) - registerService(qobject_interface_iid(), [service](const QVariantList ¶ms) -> QObject* { + registerService(qobject_interface_iid(), [service](const QObjectList ¶ms) -> QObject* { Q_UNUSED(params); return service; }, QByteArrayList()); @@ -95,7 +95,7 @@ template void ServiceRegistry::registerObject(TService *service) { QTMVVM_SERVICE_ASSERT(TService) - registerService(__helpertypes::qobject_iid(), [service](const QVariantList ¶ms) -> QObject* { + registerService(__helpertypes::qobject_iid(), [service](const QObjectList ¶ms) -> QObject* { Q_UNUSED(params); return service; }, QByteArrayList()); diff --git a/src/mvvmcore/serviceregistry_p.h b/src/mvvmcore/serviceregistry_p.h index aaaebd4..7e5dde0 100644 --- a/src/mvvmcore/serviceregistry_p.h +++ b/src/mvvmcore/serviceregistry_p.h @@ -1,6 +1,8 @@ #ifndef QTMVVM_SERVICEREGISTRY_P_H #define QTMVVM_SERVICEREGISTRY_P_H +#include + #include "qtmvvmcore_global.h" #include "serviceregistry.h" @@ -9,6 +11,46 @@ namespace QtMvvm { class ServiceRegistryPrivate { public: + class ServiceInfo { + public: + ServiceInfo(); + virtual ~ServiceInfo(); + + QObject *instance(ServiceRegistryPrivate *d); + + protected: + virtual QObject *construct(ServiceRegistryPrivate *d) const = 0; + + private: + QObject *_instance; + }; + + class FnServiceInfo : public ServiceInfo { + public: + FnServiceInfo(const std::function &creator, const QByteArrayList &injectables); + + protected: + QObject *construct(ServiceRegistryPrivate *d) const final; + + private: + std::function creator; + QByteArrayList injectables; + }; + + class MetaServiceInfo : public ServiceInfo { + public: + MetaServiceInfo(const QMetaObject *metaObject); + + protected: + QObject *construct(ServiceRegistryPrivate *d) const final; + + private: + const QMetaObject *metaObject; + }; + + QMutex serviceMutex; + QHash> services; + ServiceRegistryPrivate(); };