From b3b99ab4b4944c7d33d5e5ff19bd2f2aa1e0b513 Mon Sep 17 00:00:00 2001 From: Ralph Wessel Date: Tue, 20 Aug 2024 08:45:16 +0100 Subject: [PATCH] Updated JSBridgeArgument to receive args as a JS array rather than an object --- .../Browser/Bridge/JSBridgeArgumentWrap.cpp | 61 +++++++++++-------- .../Browser/Bridge/JSBridgeArgumentWrap.h | 25 ++++---- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.cpp b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.cpp index 1271b06..cb4586b 100644 --- a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.cpp +++ b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.cpp @@ -20,17 +20,22 @@ namespace { ///The indices of the package items enum FieldIndex { + args, + }; + + + ///The indices of the arguments array rows + enum RowIndex { objectName, methodName, requestID, }; + ///The package inventory auto myInventory = Inventory { { - { {"binding_name"}, objectName, attribute }, - { {"name"}, methodName, attribute }, - { {"request_id"}, requestID, attribute }, + { {"arg"}, args, array }, //The JS arguments are expressed as a flat array - use the array indices to map to expected vars }, }.withType(&typeid(JSBridgeArgumentWrap));; @@ -50,11 +55,8 @@ JSBridgeArgumentWrap::~JSBridgeArgumentWrap() { return: True if items have been added to the inventory --------------------------------------------------------------------*/ -bool JSBridgeArgumentWrap::fillInventory(active::serialise::Inventory& inventory) const { - if (!m_isReadingAttributes.has_value() || *m_isReadingAttributes) - inventory.merge(myInventory); - if (m_argument) - m_argument->fillInventory(inventory); +bool JSBridgeArgumentWrap::fillInventory(Inventory& inventory) const { + inventory.merge(myInventory); return true; } //JSBridgeArgumentWrap::fillInventory @@ -66,16 +68,28 @@ bool JSBridgeArgumentWrap::fillInventory(active::serialise::Inventory& inventory return: The requested cargo (nullptr on failure) --------------------------------------------------------------------*/ -Cargo::Unique JSBridgeArgumentWrap::getCargo(const active::serialise::Inventory::Item& item) const { +Cargo::Unique JSBridgeArgumentWrap::getCargo(const Inventory::Item& item) const { if (item.ownerType != &typeid(JSBridgeArgumentWrap)) return nullptr; switch (item.index) { - case FieldIndex::objectName: - return std::make_unique>(m_objectName); - case FieldIndex::methodName: - return std::make_unique>(m_methodName); - case FieldIndex::requestID: - return std::make_unique>(m_requestID); + case FieldIndex::args: { + switch (item.available) { //NB: Args are not labelled - in this instance we use the array row index to couple to an argument var + case RowIndex::objectName: + return std::make_unique>(m_objectName); + case RowIndex::methodName: + return std::make_unique>(m_methodName); + case RowIndex::requestID: + return std::make_unique>(m_requestID); + default: + //Once the argument attributes have been obtained (object, method etc) we need to ensure the argument object exists + if (!m_argument) + finaliseArgument(); + Inventory::Item childItem{item}; + //The index of the child item starts at zero, so deduct the indices already received by the wrapper + childItem.available -= (RowIndex::requestID + 1); + return m_argument->getCargo(childItem); + } + } default: return nullptr; //Requested an unknown index } @@ -99,23 +113,18 @@ void JSBridgeArgumentWrap::setDefault() { return: True if the data has been validated --------------------------------------------------------------------*/ bool JSBridgeArgumentWrap::validate() { - return !m_objectName.empty() && !m_methodName.empty() && !m_requestID.empty() && (!m_argument | m_argument->validate()); + //Only successful if we built an argument object and its content is valid + return !m_argument && m_argument->validate(); } //JSBridgeArgumentWrap::validate /*-------------------------------------------------------------------- - Finalise the package attributes (called when isAttributeFirst = true and attributes have been imported) - - return: True if the attributes have been successfully finalised (returning false will cause an exception to be thrown) + Finalise the output argument object based on the current object, method etc --------------------------------------------------------------------*/ -bool JSBridgeArgumentWrap::finaliseAttributes() { - if (!m_isReadingAttributes.has_value() || !*m_isReadingAttributes ||m_objectName.empty() || m_methodName.empty()) - return false; - m_isReadingAttributes = false; +void JSBridgeArgumentWrap::finaliseArgument() const { //Use the deserialised target bridge and method to establish the required arguments (if any) - m_argument.reset(JSBridgeArgumentWrap::makeArgument(m_objectName, m_methodName)); + m_argument.reset(JSBridgeArgumentWrap::makeArgument(m_objectName, m_methodName, m_requestID)); //If the function doesn't take an argument, we still need to pass along the base class with object name, method etc if (!m_argument) m_argument = std::make_unique(m_objectName, m_methodName, m_requestID); - return true; -} //JSBridgeArgumentWrap::finaliseAttributes +} //JSBridgeArgumentWrap::finaliseArgument diff --git a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.h b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.h index 60849e1..8f08266 100644 --- a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.h +++ b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.h @@ -12,12 +12,15 @@ namespace speckle::interfac::browser::bridge { /*! Factory function to make an argument object + @param bridge The target bridge name + @param method The target method to receive the argument + @param request The request ID for the result @return A new argument object */ template - void* constructArgument() { + void* constructArgument(const speckle::utility::String& bridge, const speckle::utility::String& method, const speckle::utility::String& request) { try { - return new T(); + return new T(bridge, method, request); } catch(...) { return nullptr; //Object constructors should throw an exception if incoming data isn't viable (NB: only use for unrecoverable problems) } @@ -103,11 +106,6 @@ namespace speckle::interfac::browser::bridge { @return True if the data has been validated */ bool validate() override; - /*! - Finalise the package attributes (called when isAttributeFirst = true and attributes have been imported) - @return True if the attributes have been successfully finalised (returning false will cause an exception to be thrown) - */ - bool finaliseAttributes() override; /*! Make an argument object for a specified bridge method @@ -115,9 +113,10 @@ namespace speckle::interfac::browser::bridge { @param method The name of the target method @return An argument object (nullptr on failure) */ - static JSBridgeArgument* makeArgument(const speckle::utility::String& bridge, const speckle::utility::String& method) { + static JSBridgeArgument* makeArgument(const speckle::utility::String& bridge, const speckle::utility::String& method, + const speckle::utility::String& request) { if (auto maker = m_argumentFactory.find(JSBridgeArgumentWrap::encode(bridge, method)); (maker != m_argumentFactory.end())) - return reinterpret_cast(maker->second()); + return reinterpret_cast(maker->second(bridge, method, request)); return nullptr; } @@ -141,9 +140,13 @@ namespace speckle::interfac::browser::bridge { static speckle::utility::String encode(const speckle::utility::String& bridge, const speckle::utility::String& method) { return bridge + ":" + method; } + /*! + Finalise the output argument object based on the current object, method etc + */ + void finaliseArgument() const; //Factory function for producing instances from a serialised document object - using Production = std::function; + using Production = std::function; ///Factory functions to construct arguments from linked bridge/method names static std::unordered_map m_argumentFactory; @@ -154,7 +157,7 @@ namespace speckle::interfac::browser::bridge { ///An ID to be paired with the method return value speckle::utility::String m_requestID; ///The function arguments - std::shared_ptr m_argument; + mutable std::shared_ptr m_argument; ///True while the attribute are being deserialised std::optional m_isReadingAttributes = true; };