Updated JSBridgeArgument to receive args as a JS array rather than an object

This commit is contained in:
Ralph Wessel
2024-08-20 08:45:16 +01:00
parent a2000eb8a8
commit b3b99ab4b4
2 changed files with 49 additions and 37 deletions
@@ -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<ValueWrap<String>>(m_objectName);
case FieldIndex::methodName:
return std::make_unique<ValueWrap<String>>(m_methodName);
case FieldIndex::requestID:
return std::make_unique<ValueWrap<String>>(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<ValueWrap<String>>(m_objectName);
case RowIndex::methodName:
return std::make_unique<ValueWrap<String>>(m_methodName);
case RowIndex::requestID:
return std::make_unique<ValueWrap<String>>(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<JSBridgeArgument>(m_objectName, m_methodName, m_requestID);
return true;
} //JSBridgeArgumentWrap::finaliseAttributes
} //JSBridgeArgumentWrap::finaliseArgument
@@ -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<typename T>
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<JSBridgeArgument*>(maker->second());
return reinterpret_cast<JSBridgeArgument*>(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<void*()>;
using Production = std::function<void*(const speckle::utility::String&, const speckle::utility::String&, const speckle::utility::String&)>;
///Factory functions to construct arguments from linked bridge/method names
static std::unordered_map<speckle::utility::String, Production> 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<JSBridgeArgument> m_argument;
mutable std::shared_ptr<JSBridgeArgument> m_argument;
///True while the attribute are being deserialised
std::optional<bool> m_isReadingAttributes = true;
};