From e75ef3133d553937885d76c656a744c20ea38cf5 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Sat, 14 Sep 2024 02:06:02 +0100 Subject: [PATCH] Clarified concepts for Storage and Engine types Added FilterMover and CardMover to deal with polymorphic ModelCard and Sendfilter types Implemented more of SenderModelCard (more needed) --- .../Connector.xcodeproj/project.pbxproj | 12 ++++ .../Connector/Database/ModelCardDatabase.cpp | 5 +- .../Connector/Record/Model/CardMover.cpp | 56 ++++++++++++++++ .../Connector/Record/Model/CardMover.h | 41 ++++++++++++ .../Record/Model/Filter/FilterMover.cpp | 64 +++++++++++++++++++ .../Record/Model/Filter/FilterMover.h | 51 +++++++++++++++ .../Record/Model/SenderModelCard.cpp | 37 ++++------- .../DocumentStore/DocumentStoreEngine.h | 30 +++++---- .../Speckle/Record/Credentials/ServerInfo.cpp | 5 +- 9 files changed, 258 insertions(+), 43 deletions(-) create mode 100644 SpeckleConnector/Connector/Record/Model/CardMover.cpp create mode 100644 SpeckleConnector/Connector/Record/Model/CardMover.h create mode 100644 SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp create mode 100644 SpeckleConnector/Connector/Record/Model/Filter/FilterMover.h diff --git a/SpeckleConnector/Connector.xcodeproj/project.pbxproj b/SpeckleConnector/Connector.xcodeproj/project.pbxproj index 3f5962f..273a6d9 100644 --- a/SpeckleConnector/Connector.xcodeproj/project.pbxproj +++ b/SpeckleConnector/Connector.xcodeproj/project.pbxproj @@ -25,6 +25,8 @@ 210CC8832C80E6A300610F58 /* TriggerEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 210CC8812C80E6A300610F58 /* TriggerEvent.cpp */; }; 213CC39C2B1101F500088049 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2151077C2AEDB9070022CD24 /* Cocoa.framework */; }; 214B7A372C764BCD00D586C1 /* UpdateConfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21F69FBD2C7630B3008B6A06 /* UpdateConfig.cpp */; }; + 215F082A2C947F4400CD343B /* CardMover.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F08262C947F4400CD343B /* CardMover.cpp */; }; + 215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 215F082C2C94C5C000CD343B /* FilterMover.cpp */; }; 219F30422C769283009834E9 /* ConfigTests.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219F30402C769282009834E9 /* ConfigTests.cpp */; }; 21B67CA32C769CB400FD64FC /* libActiveLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69EF52C64FE91008B6A06 /* libActiveLib.a */; }; 21B67CA42C769CB400FD64FC /* libArchicad27.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21F69ECD2C64C035008B6A06 /* libArchicad27.a */; }; @@ -282,6 +284,10 @@ 210CC8822C80E6A300610F58 /* TriggerEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TriggerEvent.h; sourceTree = ""; }; 213CC3A52B1101F500088049 /* Speckle Connector.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Speckle Connector.bundle"; sourceTree = BUILT_PRODUCTS_DIR; }; 2151077C2AEDB9070022CD24 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; + 215F08262C947F4400CD343B /* CardMover.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CardMover.cpp; sourceTree = ""; }; + 215F08292C947F4400CD343B /* CardMover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CardMover.h; sourceTree = ""; }; + 215F082C2C94C5C000CD343B /* FilterMover.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FilterMover.cpp; sourceTree = ""; }; + 215F082D2C94C5C000CD343B /* FilterMover.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FilterMover.h; sourceTree = ""; }; 2161FD902BF2600C006D9527 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 219388682C4E5DE2002A0180 /* CMakeLists.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = ""; }; 219F30352C768F0A009834E9 /* Connector-AC27-Test.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Connector-AC27-Test.bundle"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1020,6 +1026,8 @@ 21D0BDD92C9387F70077E104 /* Model */ = { isa = PBXGroup; children = ( + 215F08262C947F4400CD343B /* CardMover.cpp */, + 215F08292C947F4400CD343B /* CardMover.h */, 21D0BDAA2C8F363E0077E104 /* CardSetting.cpp */, 21D0BDA92C8F363E0077E104 /* CardSetting.h */, 21D0BDDF2C9393980077E104 /* Filter */, @@ -1036,6 +1044,8 @@ children = ( 21D0BDE12C943C630077E104 /* DirectSelectionSendFilter.cpp */, 21D0BDE22C943C630077E104 /* DirectSelectionSendFilter.h */, + 215F082C2C94C5C000CD343B /* FilterMover.cpp */, + 215F082D2C94C5C000CD343B /* FilterMover.h */, 21D0BDDD2C9393980077E104 /* SendFilter.cpp */, 21D0BDDE2C9393980077E104 /* SendFilter.h */, ); @@ -1384,8 +1394,10 @@ 21B67CAD2C77329800FD64FC /* GetSourceApplicationName.cpp in Sources */, 21D0BDE02C9393980077E104 /* SendFilter.cpp in Sources */, 21D0BDA82C8F33AC0077E104 /* ModelCard.cpp in Sources */, + 215F082A2C947F4400CD343B /* CardMover.cpp in Sources */, 21D0BDD72C935DAE0077E104 /* RemoveModel.cpp in Sources */, 21B67CDC2C78C88000FD64FC /* SayHi.cpp in Sources */, + 215F082E2C94C5C000CD343B /* FilterMover.cpp in Sources */, 21F69F122C677BC0008B6A06 /* ConnectorMenu.cpp in Sources */, 21F69F8D2C70D7EE008B6A06 /* GetAccounts.cpp in Sources */, 21B67CCC2C77670400FD64FC /* ModelCardDatabase.cpp in Sources */, diff --git a/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp index 0ad0d9e..d53c689 100644 --- a/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp +++ b/SpeckleConnector/Connector/Database/ModelCardDatabase.cpp @@ -2,6 +2,7 @@ #include "Active/Database/Storage/Storage.h" #include "Active/Serialise/JSON/JSONTransport.h" +#include "Connector/Record/Model/CardMover.h" #include "Speckle/Database/Identity/RecordID.h" #include "Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h" @@ -20,8 +21,8 @@ using namespace speckle::utility; namespace connector::database { ///ModelCard database engine declaration - class ModelCardDatabase::Engine : public DocumentStoreEngine { - using base = DocumentStoreEngine; + class ModelCardDatabase::Engine : public DocumentStoreEngine { + using base = DocumentStoreEngine; using base::base; }; diff --git a/SpeckleConnector/Connector/Record/Model/CardMover.cpp b/SpeckleConnector/Connector/Record/Model/CardMover.cpp new file mode 100644 index 0000000..841e05b --- /dev/null +++ b/SpeckleConnector/Connector/Record/Model/CardMover.cpp @@ -0,0 +1,56 @@ +/*! +Copyright 2024 Ralph Wessel and Hugh Wessel +Distributed under the MIT License (See accompanying file LICENSE.txt or copy at https://opensource.org/license/mit/) +*/ + +#include "Connector/Record/Model/CardMover.h" + +#include "Connector/Record/Model/SenderModelCard.h" + +using namespace active::serialise; +using namespace active::utility; +using namespace connector::record; + +namespace { + + ///The tag used to identify a Speckle type name value + const char* attributeTag = "typeDiscriminator"; + ///Identity for a SenderModelCard + const char* senderCardTypeName = "SenderModelCard"; + ///Identity for a ReceiverModelCard + const char* receiverCardTypeName = "ReceiverModelCard"; + +} + + ///The handler for model card packages +std::shared_ptr CardMover::m_handler = std::make_shared(attributeTag); + + +/*-------------------------------------------------------------------- + Constructor (for deserialisation) + + handler: A package handler to reconstruct incoming packages + --------------------------------------------------------------------*/ +CardMover::CardMover() : Mover{m_handler} { + validateHandler(); +} //CardMover::CardMover + + +/*-------------------------------------------------------------------- + Constructor (for serialisation) + + outgoing: An outgoing package + --------------------------------------------------------------------*/ +CardMover::CardMover(const active::serialise::Package& outgoing) : Mover{outgoing, m_handler} { + validateHandler(); +} //CardMover::CardMover + + +/*-------------------------------------------------------------------- + Ensure the handler is populated + --------------------------------------------------------------------*/ +void CardMover::validateHandler() { + if (!m_handler->empty()) + return; + m_handler->add(senderCardTypeName); +} //CardMover::validateHandler diff --git a/SpeckleConnector/Connector/Record/Model/CardMover.h b/SpeckleConnector/Connector/Record/Model/CardMover.h new file mode 100644 index 0000000..09ec860 --- /dev/null +++ b/SpeckleConnector/Connector/Record/Model/CardMover.h @@ -0,0 +1,41 @@ +#ifndef CONNECTOR_MODEL_CARD_MOVER +#define CONNECTOR_MODEL_CARD_MOVER + +#include "Active/Serialise/Package/Wrapper/Mover.h" + +namespace connector::record { + + /*! + Wrapper to box/unbox objects during (de)serialisation, reading/writing a specified attribute to determine object type + + Note that a derived class could also define the package handler, allowing the wrapper to be created via a default constructor that is + automatically bound to a set of internally defined object types + */ + class CardMover : public active::serialise::Mover { + public: + + // MARK: - Constructors + + /*! + Default constructor + */ + CardMover(); + /*! + Constructor (for serialisation) + @param outgoing An outgoing package + */ + CardMover(const active::serialise::Package& outgoing); + + private: + /*! + Ensure the handler is populated + */ + static void validateHandler(); + + ///The handler for model card packages + static std::shared_ptr m_handler; + }; + +} + +#endif //CONNECTOR_MODEL_CARD_MOVER diff --git a/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp b/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp new file mode 100644 index 0000000..5712d2d --- /dev/null +++ b/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.cpp @@ -0,0 +1,64 @@ +/*! +Copyright 2024 Ralph Wessel and Hugh Wessel +Distributed under the MIT License (See accompanying file LICENSE.txt or copy at https://opensource.org/license/mit/) +*/ + +#include "Connector/Record/Model/Filter/FilterMover.h" + +#include "Connector/Record/Model/Filter/DirectSelectionSendFilter.h" + +using namespace active::serialise; +using namespace active::utility; +using namespace connector::record; + +namespace { + + ///The tag used to identify a Speckle type name value + const char* attributeTag = "typeDiscriminator"; + ///Identity for a SenderModelCard + const char* DirectSelectionTypeName = "DirectSelectionSendFilter"; + +} + + ///The handler for model card packages +std::shared_ptr FilterMover::m_handler = std::make_shared(attributeTag); + + +/*-------------------------------------------------------------------- + Constructor (for deserialisation) + + handler: A package handler to reconstruct incoming packages + --------------------------------------------------------------------*/ +FilterMover::FilterMover() : Mover{m_handler} { + validateHandler(); +} //FilterMover::FilterMover + + +/*-------------------------------------------------------------------- + Constructor (for serialisation) + + outgoing: An outgoing package + --------------------------------------------------------------------*/ +FilterMover::FilterMover(const active::serialise::Package& outgoing) : Mover{outgoing, m_handler} { + validateHandler(); +} //FilterMover::FilterMover + + +/*-------------------------------------------------------------------- + Constructor (when it will be used for serialisation only on an existing object) + + package: A reference to the member variable + --------------------------------------------------------------------*/ +FilterMover::FilterMover(active::serialise::PackageUniqueWrap&& package) : Mover{std::move(package), m_handler} { + +} //FilterMover::FilterMover + + +/*-------------------------------------------------------------------- + Ensure the handler is populated + --------------------------------------------------------------------*/ +void FilterMover::validateHandler() { + if (!m_handler->empty()) + return; + m_handler->add(DirectSelectionTypeName); +} //FilterMover::validateHandler diff --git a/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.h b/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.h new file mode 100644 index 0000000..48e13a1 --- /dev/null +++ b/SpeckleConnector/Connector/Record/Model/Filter/FilterMover.h @@ -0,0 +1,51 @@ +#ifndef CONNECTOR_MODEL_SEND_FILTER_MOVER +#define CONNECTOR_MODEL_SEND_FILTER_MOVER + +#include "Active/Serialise/Package/Wrapper/Mover.h" + +namespace connector::record { + + /*! + Wrapper to box/unbox objects during (de)serialisation, reading/writing a specified attribute to determine object type + + Note that a derived class could also define the package handler, allowing the wrapper to be created via a default constructor that is + automatically bound to a set of internally defined object types + */ + class FilterMover : public active::serialise::Mover { + public: + + // MARK: - Constructors + + /*! + Default constructor (primarily for a list of polymorphic objects) + */ + FilterMover(); + /*! + Constructor (when it will be used for serialisation only on an existing object) + @param package A reference to the member variable + */ + FilterMover(const Package& package); + /*! + Constructor (for serialisation or deserialisation of a polymorphic member variable held in a unique pointer) + @param package A reference to the member variable + */ + FilterMover(const Package::Unique& package); + /*! + Constructor (when it will be used for serialisation only on an existing object) + @param package A reference to the member variable + */ + FilterMover(active::serialise::PackageUniqueWrap&& package); + + private: + /*! + Ensure the handler is populated + */ + static void validateHandler(); + + ///The handler for model card packages + static std::shared_ptr m_handler; + }; + +} + +#endif //CONNECTOR_MODEL_SEND_FILTER_MOVER diff --git a/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp b/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp index 4db1090..08e1d8b 100644 --- a/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp +++ b/SpeckleConnector/Connector/Record/Model/SenderModelCard.cpp @@ -1,5 +1,8 @@ #include "Connector/Record/Model/SenderModelCard.h" +#include "Active/Serialise/Package/Wrapper/PackageWrap.h" +#include "Active/Serialise/Package/Wrapper/PackageUniqueWrap.h" +#include "Connector/Record/Model/Filter/FilterMover.h" #include "Connector/Record/Model/Filter/SendFilter.h" #include @@ -67,16 +70,12 @@ SenderModelCard::~SenderModelCard() { --------------------------------------------------------------------*/ bool SenderModelCard::fillInventory(Inventory& inventory) const { using enum Entry::Type; -/* inventory.merge(Inventory{ + inventory.merge(Inventory{ { - { fieldID[modelID], modelID, element }, - { fieldID[projectID], projectID, element }, - { fieldID[accountID], accountID, element }, - { fieldID[serverURLID], serverURLID, element }, - { fieldID[settingsID], settingsID, element }, + { fieldID[sendFilterID], sendFilterID, element }, }, }.withType(&typeid(SenderModelCard))); - return base::fillInventory(inventory);*/ + return base::fillInventory(inventory); } //SenderModelCard::fillInventory @@ -88,23 +87,15 @@ bool SenderModelCard::fillInventory(Inventory& inventory) const { return: The requested cargo (nullptr on failure) --------------------------------------------------------------------*/ Cargo::Unique SenderModelCard::getCargo(const Inventory::Item& item) const { -/* if (item.ownerType != &typeid(SenderModelCard)) + if (item.ownerType != &typeid(SenderModelCard)) return base::getCargo(item); using namespace active::serialise; switch (item.index) { - case modelID: - return std::make_unique>(m_modelID); - case projectID: - return std::make_unique>(m_projectID); - case accountID: - return std::make_unique>(m_accountID); - case serverURLID: - return std::make_unique>(m_serverURL); - case settingsID: - return std::make_unique>(m_settings); + case sendFilterID: + return std::make_unique(PackageUniqueWrap{m_filter}); default: return nullptr; //Requested an unknown index - }*/ + } } //SenderModelCard::getCargo @@ -112,10 +103,6 @@ Cargo::Unique SenderModelCard::getCargo(const Inventory::Item& item) const { Set to the default package content --------------------------------------------------------------------*/ void SenderModelCard::setDefault() { -/* base::setDefault(); - m_modelID.clear(); - m_projectID.clear(); - m_accountID.clear(); - m_serverURL.clear(); - m_settings.clear();*/ + base::setDefault(); + m_filter->setDefault(); } //SenderModelCard::setDefault diff --git a/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h b/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h index fc42f83..9ec72f7 100644 --- a/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h +++ b/SpeckleLib/Speckle/Database/Storage/DocumentStore/DocumentStoreEngine.h @@ -1,6 +1,7 @@ #ifndef SPECKLE_DATABASE_DOCUMENT_STORE_ENGINE #define SPECKLE_DATABASE_DOCUMENT_STORE_ENGINE +#include "Active/Database/Concepts.h" #include "Active/Database/Storage/DBaseEngine.h" #include "Active/Database/Storage/RecordCache.h" #include "Active/File/Path.h" @@ -21,8 +22,9 @@ namespace speckle::database { ///Concept for the ability to store objects in a document - template - concept DocumentStorable = std::is_base_of_v && + template + concept DocumentStorable = (active::database::CanWrap || active::database::FlatType) && + std::is_base_of_v && std::is_base_of_v; /*! @@ -36,7 +38,7 @@ namespace speckle::database { @tparam ObjID The object identifier type, e.g. Guid */ template - requires DocumentStorable + requires DocumentStorable class DocumentStoreEngine : public DocumentStoreCore, public active::database::DBaseEngine { public: @@ -45,7 +47,7 @@ namespace speckle::database { using base = active::database::DBaseEngine; using Filter = base::Filter; using Outline = base::Outline; - using Cache = active::database::RecordCache; + using Cache = active::database::RecordCache; // MARK: - Constructors @@ -147,7 +149,7 @@ namespace speckle::database { return: The cached records (nullptr on failure) --------------------------------------------------------------------*/ template - requires DocumentStorable + requires DocumentStorable typename DocumentStoreEngine::Cache* DocumentStoreEngine::getCache() const { if (m_cache) return m_cache.get(); @@ -175,7 +177,7 @@ namespace speckle::database { return: The requested object (nullptr on failure) --------------------------------------------------------------------*/ template - requires DocumentStorable + requires DocumentStorable std::unique_ptr DocumentStoreEngine::getObject(const ObjID& ID, std::optional tableID, std::optional documentID) const { return getCache()->read(ID); @@ -191,7 +193,7 @@ namespace speckle::database { return: The requested objects (nullptr on failure) --------------------------------------------------------------------*/ template - requires DocumentStorable + requires DocumentStorable active::container::Vector DocumentStoreEngine::getObjects(std::optional tableID, std::optional documentID) const { return getCache()->read(); @@ -208,7 +210,7 @@ namespace speckle::database { return: The requested objects (nullptr on failure) --------------------------------------------------------------------*/ template - requires DocumentStorable + requires DocumentStorable active::container::Vector DocumentStoreEngine::getObjects(const Filter& filter, std::optional tableID, std::optional documentID) const { return getCache()->read(filter); @@ -225,7 +227,7 @@ namespace speckle::database { documentID: Optional document ID (when the object is bound to a specific document) --------------------------------------------------------------------*/ template - requires DocumentStorable + requires DocumentStorable void DocumentStoreEngine::write(const Obj& object, const ObjID& objID, std::optional objDocID, std::optional tableID, std::optional documentID) const { getCache()->write(object); //NB: In future we might support duplicating records if objID != obj.id @@ -242,7 +244,7 @@ namespace speckle::database { return: True if the object was successfully erased --------------------------------------------------------------------*/ template - requires DocumentStorable + requires DocumentStorable void DocumentStoreEngine::erase(const ObjID& ID, std::optional tableID, std::optional documentID) const { getCache()->erase(ID); @@ -256,7 +258,7 @@ namespace speckle::database { documentID: Optional document ID (filter for this document only - nullopt = all objects) --------------------------------------------------------------------*/ template - requires DocumentStorable + requires DocumentStorable void DocumentStoreEngine::erase(std::optional tableID, std::optional documentID) const { getCache()->erase(); } //DocumentStoreEngine::erase @@ -268,7 +270,7 @@ namespace speckle::database { return: The database outline --------------------------------------------------------------------*/ template - requires DocumentStorable + requires DocumentStorable DocumentStoreEngine::Outline DocumentStoreEngine::getOutline() const { Outline result; if (getSchema().empty()) @@ -285,7 +287,7 @@ namespace speckle::database { return: Data to store from the latest records --------------------------------------------------------------------*/ template - requires DocumentStorable + requires DocumentStorable active::utility::Memory DocumentStoreEngine::buildStore() { active::utility::Memory result; Transport().send(std::forward(*getCache()), active::serialise::Identity{}, result); @@ -301,7 +303,7 @@ namespace speckle::database { return: The merged data to be stored --------------------------------------------------------------------*/ template - requires DocumentStorable + requires DocumentStorable void DocumentStoreEngine::mergeStore(const active::utility::Memory& toMerge) { //Import the incoming records from the data to merge Cache incoming; diff --git a/SpeckleLib/Speckle/Record/Credentials/ServerInfo.cpp b/SpeckleLib/Speckle/Record/Credentials/ServerInfo.cpp index db98ce8..9a237e5 100644 --- a/SpeckleLib/Speckle/Record/Credentials/ServerInfo.cpp +++ b/SpeckleLib/Speckle/Record/Credentials/ServerInfo.cpp @@ -1,7 +1,8 @@ #include "Speckle/Record/Credentials/ServerInfo.h" #include "Active/Serialise/Item/Wrapper/ValueOptionWrap.h" -#include "Active/Serialise/Package/Wrapper/PackageUnoWrap.h" +#include "Active/Serialise/Package/Wrapper/Mover.h" +#include "Active/Serialise/Package/Wrapper/PackageUniqueWrap.h" #include "Speckle/Utility/Guid.h" #include @@ -90,7 +91,7 @@ Cargo::Unique ServerInfo::getCargo(const Inventory::Item& item) const { case urlID: return std::make_unique(m_url); case migrationID: - return std::make_unique>(m_migration); + return std::make_unique(PackageUniqueWrap{m_migration}); default: return nullptr; //Requested an unknown index }