From deee1e80c5afd49cb65bdebb5d2a88fc5d8c255b Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Mon, 30 Sep 2024 10:50:24 +0100 Subject: [PATCH] Added classes for managing detached objects: - DetachmentManager: Manages detached objects during (de)serialisation - DetachedWrap: Wrapper for detached objects, generating references on demand from serialised data - DetachedReference: Wrapper for representation of wrapped objects with a reference - DetachedObjectStore: Interface for filing/retrieving detached objects in storage --- .../Serialise/Detached/DetachedReference.cpp | 90 ++++++++++++++++++ .../Serialise/Detached/DetachedReference.h | 77 +++++++++++++++ .../Serialise/Detached/DetachedWrap.cpp | 93 +++++++++++++++++++ .../Speckle/Serialise/Detached/DetachedWrap.h | 89 ++++++++++++++++++ .../Serialise/Detached/DetachmentManager.cpp | 89 ++++++++++++++++++ .../Serialise/Detached/DetachmentManager.h | 82 ++++++++++++++++ .../Detached/Storage/DetachedObjectStore.h | 46 +++++++++ .../SpeckleLib.xcodeproj/project.pbxproj | 38 ++++++++ 8 files changed, 604 insertions(+) create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachedReference.h create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.h create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.cpp create mode 100644 SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h create mode 100644 SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp new file mode 100644 index 0000000..140c476 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.cpp @@ -0,0 +1,90 @@ +#include "Speckle/Serialise/Detached/DetachedReference.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Speckle/Serialise/Detached/DetachmentManager.h" +#include "Speckle/Utility/String.h" + +using namespace active::serialise; +using namespace speckle::serialise; +using namespace speckle::utility; + +#include + +namespace { + + ///Serialisation fields + enum FieldIndex { + refdID, + speckTypeID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"referencedId"}, + Identity{"speckle_type"}, + }; + + ///Type signature for a reference to a detached object + String referenceType{"reference"}; + +} + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool DetachedReference::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + inventory.merge(Inventory{ + { + { fieldID[refdID], refdID, element }, + { fieldID[speckTypeID], speckTypeID, element }, + }, + }.withType(&typeid(DetachedReference))); + return true; +} //DetachedReference::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique DetachedReference::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(DetachedReference)) + return base::get().getCargo(item); + using namespace active::serialise; + switch (item.index) { + case refdID: { + //If we don't have an allocated string for receiving a reference (from 'setDefault') then we need to create one + if (!m_reference) { + //Ask a manager to send the detached data and provide a reference + auto detachmentManager = getManager(); + if (detachmentManager == nullptr) + return nullptr; //TODO: Discuss if this is a serious error - possibly throwing an exception is warranted + m_reference = detachmentManager->send(std::forward(base::get()), item.identity()); + if (!m_reference) + throw; //TODO: Throw a more descriptive exception + } + std::make_unique(*m_reference); + } + case speckTypeID: + return std::make_unique(m_type); + default: + return nullptr; //Requested an unknown index + } +} //DetachedReference::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void DetachedReference::setDefault() { + m_type.clear(); + m_reference = String{}; +} //DetachedReference::setDefault diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.h b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.h new file mode 100644 index 0000000..6993f39 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedReference.h @@ -0,0 +1,77 @@ +#ifndef SPECKLE_SERIALISE_DETACHED_REFERENCE +#define SPECKLE_SERIALISE_DETACHED_REFERENCE + +#include "Active/Serialise/Package/Package.h" +#include "Speckle/Serialise/Detached/DetachedWrap.h" +#include "Speckle/Utility/String.h" + +namespace speckle::serialise { + + /*! + Wrapper for references to a detached (serialised) object + + An object holding a child object that should be serialised as a detached object should wrap the child in this package for (de)serialisation + */ + class DetachedReference : public active::serialise::Package, std::reference_wrapper { + public: + + // MARK: - Types + + ///Item reference base + using base = std::reference_wrapper; + + // MARK: - Constructors + + /*! + Constructor + @param source The source package to wrap + */ + DetachedReference(Package& source) : base{source} {} + /*! + Constructor + @param source The source package to wrap + */ + DetachedReference(const active::serialise::Package& source) : base(const_cast(source)) {} + DetachedReference(const DetachedReference& source) = delete; + /*! + Destructor + */ + ~DetachedReference() override = default; + + // MARK: - Functions (const) + + /*! + Fill an inventory with the cargo items + @param inventory The inventory to receive the cargo items + @return True if items have been added to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + // MARK: - Functions (mutating) + + /*! + Set to the default package content + */ + void setDefault() override; + /*! + Validate the cargo data + @return True if the data has been validated + */ + bool validate() override; + + private: + ///The reference value, i.e. a hash of the object content + mutable std::optional m_reference; + ///The reference type + utility::String m_type; + }; + +} + +#endif //SPECKLE_SERIALISE_DETACHED_REFERENCE diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp b/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp new file mode 100644 index 0000000..141b4b9 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.cpp @@ -0,0 +1,93 @@ +#include "Speckle/Serialise/Detached/DetachedWrap.h" + +#include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Utility/BufferOut.h" +#include "Active/Utility/SHA256.h" +#include "Speckle/Serialise/Detached/DetachmentManager.h" +#include "Speckle/Utility/String.h" + +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::serialise; +using namespace speckle::utility; + +#include + +namespace { + + ///Serialisation fields + enum FieldIndex { + refdID, + }; + + ///Serialisation field IDs + static std::array fieldID = { + Identity{"id"}, + }; + +} + +/*-------------------------------------------------------------------- + Fill an inventory with the package items + + inventory: The inventory to receive the package items + + return: True if the package has added items to the inventory + --------------------------------------------------------------------*/ +bool DetachedWrap::fillInventory(Inventory& inventory) const { + using enum Entry::Type; + if (!base::get().fillInventory(inventory)) + return false; + inventory.merge(Inventory{ + { + { fieldID[refdID], refdID, element }, + }, + }.withType(&typeid(DetachedWrap))); + return true; +} //DetachedWrap::fillInventory + + +/*-------------------------------------------------------------------- + Get the specified cargo + + item: The inventory item to retrieve + + return: The requested cargo (nullptr on failure) + --------------------------------------------------------------------*/ +Cargo::Unique DetachedWrap::getCargo(const Inventory::Item& item) const { + if (item.ownerType != &typeid(DetachedWrap)) + return base::get().getCargo(item); + using namespace active::serialise; + switch (item.index) { + case refdID: { + if (!m_reference) { + if (m_bufferOut == nullptr) + return nullptr; //TODO: Consider throwing an exception here + auto serialisedData = m_bufferOut->getOutput(); + //Produce a hash from the serialised object. NB: We are currently using only the first 32 chars of the SHA256 hash + m_reference = (active::utility::SHA256() << serialisedData << String{"}"}).base64Hash().substr(0, 32); + } + return std::make_unique>(*m_reference); + } + default: + return nullptr; //Requested an unknown index + } +} //DetachedWrap::getCargo + + +/*-------------------------------------------------------------------- + Set to the default package content + --------------------------------------------------------------------*/ +void DetachedWrap::setDefault() { + m_reference = String{}; +} //DetachedWrap::setDefault + + +/*-------------------------------------------------------------------- + Validate the cargo data + + return: True if the data has been validated + --------------------------------------------------------------------*/ +bool DetachedWrap::validate() { + return m_reference && base::get().validate(); +} //DetachedWrap::validate diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.h b/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.h new file mode 100644 index 0000000..29532b1 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachedWrap.h @@ -0,0 +1,89 @@ +#ifndef SPECKLE_SERIALISE_DETACHED_WRAP +#define SPECKLE_SERIALISE_DETACHED_WRAP + +#include "Active/Serialise/Package/Package.h" + +#include "Speckle/Database/Identity/RecordID.h" + +namespace active::utility { + class BufferOut; +} + +namespace speckle::serialise { + + /*! + Lightweight interface wrapper for a detached object + + The wrapper generates a new reference ID for the object during serialisation, embedding it in the output + */ + class DetachedWrap : public active::serialise::Package, public std::reference_wrapper { + public: + + // MARK: - Types + + ///Item reference base + using base = std::reference_wrapper; + + // MARK: - Constructors + + /*! + Constructor + @param source The source package to wrap + @param bufferOut The serialisation output buffer + */ + DetachedWrap(active::serialise::Package& source, active::utility::BufferOut& bufferOut) : base(source), m_bufferOut{&bufferOut} {} + /*! + Constructor + @param source The source package to wrap + @param bufferOut The serialisation output buffer + */ + DetachedWrap(const active::serialise::Package& source, active::utility::BufferOut& bufferOut) : + DetachedWrap{const_cast(source), bufferOut} {} + /*! + Copy constructor + @param source The object to copy + */ + DetachedWrap(const DetachedWrap& source) : base(source), m_reference{source.m_reference} {} + + // MARK: - Functions (const) + + /*! + Get the detached object reference + @return The detached object reference (nullopt if the reference has not been determined yet - call after (de)serialisation) + */ + std::optional getReference() const { return m_reference; } + /*! + Fill an inventory with the cargo items + @param inventory The inventory to receive the cargo items + @return True if items have been added to the inventory + */ + bool fillInventory(active::serialise::Inventory& inventory) const override; + /*! + Get the specified cargo + @param item The inventory item to retrieve + @return The requested cargo (nullptr on failure) + */ + Cargo::Unique getCargo(const active::serialise::Inventory::Item& item) const override; + + // MARK: - Functions (mutating) + + /*! + Set to the default package content + */ + void setDefault() override; + /*! + Validate the cargo data + @return True if the data has been validated + */ + bool validate() override; + + private: + ///The detached record reference + mutable std::optional m_reference; + ///The serialisation output buffer + active::utility::BufferOut* m_bufferOut; + }; + +} + +#endif //SPECKLE_SERIALISE_DETACHED_WRAP diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.cpp b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.cpp new file mode 100644 index 0000000..b5e98f0 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.cpp @@ -0,0 +1,89 @@ +#include "Speckle/Serialise/Detached/DetachmentManager.h" + +#include "Active/Utility/BufferOut.h" +#include "Speckle/Serialise/Detached/DetachedWrap.h" +#include "Speckle/Serialise/Detached/Storage/DetachedObjectStore.h" + +using namespace active::serialise; +using namespace speckle::database; +using namespace speckle::serialise; +using namespace speckle::utility; + + +/*-------------------------------------------------------------------- + Default constructor + --------------------------------------------------------------------*/ +DetachmentManager::DetachmentManager() { + +} //DetachmentManager::DetachmentManager + + +/*-------------------------------------------------------------------- + Destructor + --------------------------------------------------------------------*/ +DetachmentManager::~DetachmentManager() { + +} //DetachmentManager::~DetachmentManager + + +/*-------------------------------------------------------------------- + Send cargo as a detached object + + package: The package to become a detached object + identity: The package identity (name, optional namespace) + + return: The ID of the sent detached object + --------------------------------------------------------------------*/ +std::optional DetachmentManager::send(Package&& package, const Identity& identity) const { + auto transport = m_transport.lock(); + if (!transport) + throw; //TODO: Throw meaningful exception type + //Prepare the detached object data + String serialisedData; + active::utility::BufferOut buffer{serialisedData}; + //The wrapper will manage the object serialisation and generate a unique reference based on the output + DetachedWrap wrapper{package, buffer}; + transport->send(std::forward(wrapper), identity, serialisedData); + auto detachedReference = wrapper.getReference(); + //If a reference is obtained, file/cache the object as required + if (detachedReference) { + m_store->file(*detachedReference, serialisedData); + if (m_cache) + m_cache->file(*detachedReference, serialisedData); + } + return detachedReference; +} //DetachmentManager::send + + +/*-------------------------------------------------------------------- + Receive cargo from a detached object + + id: The ID of the detached object to receive + package: The package to receive the detached object data + identity: The package identity (name, optional namespace) + + return: True if the detached object was found and received + --------------------------------------------------------------------*/ +bool DetachmentManager::receive(const database::RecordID& id, Package&& package, const Identity& identity) const { + return false; //TODO: Implement when we start receiving in Archicad +} //DetachmentManager::receive + + +/*-------------------------------------------------------------------- + Set the manager primary storage + + store: the primary storage (this is the long-term storage, e.g. a remote/cloud database) + --------------------------------------------------------------------*/ +void DetachmentManager::setStore(std::unique_ptr store) { + m_store = std::move(store); +} //DetachmentManager::setStore + + +/*-------------------------------------------------------------------- + Set the manager storage cache + + cache: the storage cache (this is intended to provide faster access than the primary storage for repeated detached objects) + --------------------------------------------------------------------*/ +void DetachmentManager::setCache(std::unique_ptr cache) { + m_cache = std::move(cache); +} //DetachmentManager::setCache diff --git a/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h new file mode 100644 index 0000000..094eda2 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/DetachmentManager.h @@ -0,0 +1,82 @@ +#ifndef SPECKLE_SERIALISE_DETACHMENT_MANAGER +#define SPECKLE_SERIALISE_DETACHMENT_MANAGER + +#include "Active/Serialise/Manager.h" +#include "Active/Serialise/Transport.h" +#include "Speckle/Database/Identity/RecordID.h" + +namespace active::serialise { + class Package; +} + +namespace speckle::serialise { + + class DetachedObjectStore; + + /*! + Manager for detached (serialised) objects + + Pass this manager to the target transport for (de)serialisation supporting detached objects. Note that the manager is expected to know how + to send/receive detached objects, e.g. to a JS portal, remote server or local database (or some combo) + */ + class DetachmentManager : public virtual active::serialise::Manager { + public: + + // MARK: - Types + + ///Base class + using base = active::serialise::Manager; + + /*! + Default constructor + */ + DetachmentManager(); + DetachmentManager(const DetachmentManager&) = delete; + /*! + Destructor + */ + ~DetachmentManager(); + + // MARK: - Functions (const) + + /*! + Send cargo as a detached object + @param package The package to become a detached object + @param identity The package identity (name, optional namespace) + @return The ID of the sent detached object + */ + std::optional send(active::serialise::Package&& package, const active::serialise::Identity& identity) const; + /*! + Receive cargo from a detached object + @param id The ID of the detached object to receive + @param package The package to receive the detached object data + @param identity The package identity (name, optional namespace) + @return True if the detached object was found and received + */ + bool receive(const database::RecordID& id, active::serialise::Package&& package, const active::serialise::Identity& identity) const; + + // MARK: - Functions (mutating) + + /*! + Set the manager primary storage + @param store the primary storage (this is the long-term storage, e.g. a remote/cloud database) + */ + void setStore(std::unique_ptr store); + /*! + Set the manager storage cache + @param cache the storage cache (this is intended to provide faster access than the primary storage for repeated detached objects) + */ + void setCache(std::unique_ptr cache); + + private: + ///The manager serialisation transport (NB - this is expected to be a shared resource, so the manager does not own it) + std::weak_ptr m_transport; + ///The primary store for sending/retrieving detached objects + std::unique_ptr m_store; + ///A cache for detached objects - can be used as a local store to save + std::unique_ptr m_cache; + }; + +} + +#endif //SPECKLE_SERIALISE_DETACHMENT_MANAGER diff --git a/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h b/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h new file mode 100644 index 0000000..546d572 --- /dev/null +++ b/SpeckleLib/Speckle/Serialise/Detached/Storage/DetachedObjectStore.h @@ -0,0 +1,46 @@ +#ifndef SPECKLE_SERIALISE_DETACHED_OBJECT_STORE +#define SPECKLE_SERIALISE_DETACHED_OBJECT_STORE + +#include "Speckle/Database/Identity/RecordID.h" +#include "Speckle/Utility/String.h" + +namespace speckle::serialise { + + /*! + Interface for objects that store/cache/send/receive detached objects + + It is currently assumed that objects will be serialised and can be held in a string. This can be revisited in future if binary data is required. + */ + class DetachedObjectStore { + public: + + // MARK: Constructors + + /*! + Destructor + */ + virtual ~DetachedObjectStore() {} + + // MARK: - Functions (const) + + /*! + Retrieve a detached object from storage + @param reference The required object reference + @return The object data (nullopt if the object cannot be found in storage) + */ + virtual utility::String::Option retrieve(const database::RecordID& reference) = 0; + + // MARK: - Functions (mutating) + + /*! + File a detached object in storage + @param reference The object reference (typically a hash generated from the object data) + @param data The object data (currently expected to be serialised as JSON) + @return True if the object was filed (typically rejected if it duplicates an object already in the store) + */ + virtual bool file(const database::RecordID& reference, const utility::String& data) const = 0; + }; + +} + +#endif //SPECKLE_SERIALISE_DETACHED_OBJECT_STORE diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index 9c1676a..82a12ac 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -37,6 +37,10 @@ 219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AC2C62CC1A00E5A69C /* Guid.cpp */; }; 219351B32C62CC1A00E5A69C /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351AE2C62CC1A00E5A69C /* String.cpp */; }; 2199881E2BD833830035E5EA /* libArchicad27.a in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; }; + 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */; }; + 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */; }; + 21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */; }; + 21AEF9DD2CAAA4EA000B8681 /* DetachedObjectStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 21AEF9DB2CAAA4EA000B8681 /* DetachedObjectStore.h */; }; 21B67D002C7CE15100FD64FC /* Exception.h in Headers */ = {isa = PBXBuildFile; fileRef = 21B67CFE2C7CE15100FD64FC /* Exception.h */; }; 21B67D0D2C7E0E8D00FD64FC /* ErrorReport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21B67D092C7E0E8D00FD64FC /* ErrorReport.h */; }; 21B67D0E2C7E0E8D00FD64FC /* ErrorReport.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 21B67D0C2C7E0E8D00FD64FC /* ErrorReport.cpp */; }; @@ -159,6 +163,13 @@ 219351AE2C62CC1A00E5A69C /* String.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = String.cpp; sourceTree = ""; }; 219351AF2C62CC1A00E5A69C /* String.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = String.h; sourceTree = ""; }; 219712682BE7E2D500D9EF7E /* Serialisation.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Serialisation.md; sourceTree = ""; }; + 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedWrap.h; sourceTree = ""; }; + 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedReference.h; sourceTree = ""; }; + 21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachmentManager.h; sourceTree = ""; }; + 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DetachedReference.cpp; sourceTree = ""; }; + 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DetachmentManager.cpp; sourceTree = ""; }; + 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DetachedWrap.cpp; sourceTree = ""; }; + 21AEF9DB2CAAA4EA000B8681 /* DetachedObjectStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetachedObjectStore.h; sourceTree = ""; }; 21B67CFE2C7CE15100FD64FC /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = ""; }; 21B67D092C7E0E8D00FD64FC /* ErrorReport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ErrorReport.h; sourceTree = ""; }; 21B67D0C2C7E0E8D00FD64FC /* ErrorReport.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorReport.cpp; sourceTree = ""; }; @@ -255,6 +266,7 @@ isa = PBXGroup; children = ( 2167E27C2C49121F000827D3 /* CMakeLists.txt */, + 21AEF9C72CA818EA000B8681 /* Detached */, 21F69F3A2C6B880B008B6A06 /* JSBase */, 219712682BE7E2D500D9EF7E /* Serialisation.md */, ); @@ -403,6 +415,28 @@ path = SpeckleLibDoctest; sourceTree = ""; }; + 21AEF9C72CA818EA000B8681 /* Detached */ = { + isa = PBXGroup; + children = ( + 21AEF9B92CA606B4000B8681 /* DetachedReference.cpp */, + 21AEF9B52CA5FA02000B8681 /* DetachedReference.h */, + 21AEF9BD2CA6FDA4000B8681 /* DetachedWrap.cpp */, + 21AEF9B32CA5F7CF000B8681 /* DetachedWrap.h */, + 21AEF9BB2CA6DF84000B8681 /* DetachmentManager.cpp */, + 21AEF9B72CA5FCB6000B8681 /* DetachmentManager.h */, + 21AEF9DE2CAAA78A000B8681 /* Storage */, + ); + path = Detached; + sourceTree = ""; + }; + 21AEF9DE2CAAA78A000B8681 /* Storage */ = { + isa = PBXGroup; + children = ( + 21AEF9DB2CAAA4EA000B8681 /* DetachedObjectStore.h */, + ); + path = Storage; + sourceTree = ""; + }; 21D0BD1F2C86F0280077E104 /* Database */ = { isa = PBXGroup; children = ( @@ -596,6 +630,7 @@ 21D0BD5A2C8910400077E104 /* UserInfo.h in Headers */, 21D0BD562C890B1C0077E104 /* ServerMigration.h in Headers */, 210CC88F2C81A98500610F58 /* Guid64.h in Headers */, + 21AEF9DD2CAAA4EA000B8681 /* DetachedObjectStore.h in Headers */, 215F088D2CA195EC00CD343B /* ArchicadElementDBaseEngine.h in Headers */, 21B67D002C7CE15100FD64FC /* Exception.h in Headers */, 21D0BD2C2C86FC350077E104 /* Record.h in Headers */, @@ -749,6 +784,7 @@ 21B67D0E2C7E0E8D00FD64FC /* ErrorReport.cpp in Sources */, 21F69F7E2C6FD9FC008B6A06 /* GetCallResult.cpp in Sources */, 219245FE2CA2CC4300CF5703 /* BIMRecord.cpp in Sources */, + 21AEF9BE2CA6FDA4000B8681 /* DetachedWrap.cpp in Sources */, 2193519B2C6278D900E5A69C /* SelectionSubscriber.cpp in Sources */, 21D0BD2B2C86FC350077E104 /* Record.cpp in Sources */, 219246042CA2CE2700CF5703 /* BIMLink.cpp in Sources */, @@ -760,11 +796,13 @@ 219351B32C62CC1A00E5A69C /* String.cpp in Sources */, 219351B12C62CC1A00E5A69C /* Guid.cpp in Sources */, 21F69F512C6CCC25008B6A06 /* BrowserBridge.cpp in Sources */, + 21AEF9BC2CA6DF84000B8681 /* DetachmentManager.cpp in Sources */, 215F08552C99DA8D00CD343B /* Project.cpp in Sources */, 21F69F3B2C6B880C008B6A06 /* JSBaseTransport.cpp in Sources */, 210CC89F2C81E34400610F58 /* Platform.cpp in Sources */, 21D0BD202C86F0280077E104 /* AccountDatabase.cpp in Sources */, 21F69F962C71087A008B6A06 /* Account.cpp in Sources */, + 21AEF9BA2CA606B5000B8681 /* DetachedReference.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };