diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp index 9f9580d..086aa4c 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.cpp @@ -1,7 +1,6 @@ #include "Connector/Interface/Browser/Bridge/Base/GetDocumentInfo.h" #include "Active/Serialise/CargoHold.h" -#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" #include "Connector/Interface/Browser/Bridge/Base/Arg/DocumentInfo.h" using namespace active::container; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp index dac0fc5..b630a40 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Base/GetDocumentState.cpp @@ -1,7 +1,6 @@ #include "Connector/Interface/Browser/Bridge/Base/GetDocumentState.h" #include "Active/Serialise/CargoHold.h" -#include "Active/Serialise/Package/Wrapper/ContainerWrap.h" #include "Connector/Database/Model/Card/ModelCardDatabase.h" using namespace active::container; diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.cpp index 8483d99..5b69438 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.cpp @@ -1,6 +1,7 @@ #include "Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.h" #include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/PackageWrap.h" #include @@ -11,11 +12,13 @@ namespace { ///Serialisation fields enum FieldIndex { + arg0, darkTheme, }; ///Serialisation field IDs static std::array fieldID = { + Identity{"0"}, Identity{"DarkTheme"}, }; @@ -30,6 +33,9 @@ namespace { --------------------------------------------------------------------*/ bool ConnectorConfig::fillInventory(Inventory& inventory) const { using enum Entry::Type; + //When used as an argument template, this wrapper is expected to be first in the list + if (isArgumentTemplate()) + inventory.merge({ fieldID[arg0], arg0, element }); inventory.merge(Inventory{ { { fieldID[darkTheme], darkTheme, element }, @@ -51,6 +57,9 @@ Cargo::Unique ConnectorConfig::getCargo(const Inventory::Item& item) const { return nullptr; using namespace active::serialise; switch (item.index) { + case arg0: + //This structure is the first argument + return std::make_unique(*this); case darkTheme: return std::make_unique>(isDarkTheme); default: diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.h index 3350839..178ef28 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Config/Arg/ConnectorConfig.h @@ -2,13 +2,14 @@ #define CONNECTOR_INTERFACE_BRIDGE_CONNECTOR_CONFIG #include "Active/Serialise/Package/Package.h" +#include "Speckle/Interface/Browser/Bridge/JSArgumentBase.h" namespace connector::interfac::browser::bridge { /*! Configuration settings class */ - class ConnectorConfig : public active::serialise::Package { + class ConnectorConfig : public active::serialise::Package, virtual public speckle::interfac::browser::bridge::JSArgumentBase { public: // MARK: - Types diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/Arg/ComplexType.h b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/Arg/ComplexType.h index ebfbe88..6049277 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/Arg/ComplexType.h +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/Arg/ComplexType.h @@ -29,11 +29,7 @@ namespace connector::interfac::browser::bridge { speckle::utility::String ID; int32_t count = 0; bool testBool = false; - -/* Id = GetHashCode() + " - I am a string", - count = GetHashCode(), - thisIsABoolean = false -*/ + // MARK: - Serialisation /*! diff --git a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/Arg/SayHiArg.cpp b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/Arg/SayHiArg.cpp index 4aa1266..bd4ef07 100644 --- a/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/Arg/SayHiArg.cpp +++ b/SpeckleConnector/Connector/Interface/Browser/Bridge/Test/Arg/SayHiArg.cpp @@ -17,11 +17,11 @@ namespace { isHelloID, }; - ///Serialisation field IDs + ///Serialisation field IDs. NB: This structure is never exported, so we only define the incoming argument indices static std::array fieldID = { - Identity{"name"}, - Identity{"count"}, - Identity{"sayHelloNotHi"}, + Identity{"0"}, + Identity{"1"}, + Identity{"2"}, }; } diff --git a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSArgumentBase.h b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSArgumentBase.h new file mode 100644 index 0000000..6275a5d --- /dev/null +++ b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSArgumentBase.h @@ -0,0 +1,44 @@ +#ifndef SPECKLE_INTERFACE_JS_BRIDGE_ARGUMENT_BASE +#define SPECKLE_INTERFACE_JS_BRIDGE_ARGUMENT_BASE + +#include "Active/Serialise/Package/Package.h" +#include "Speckle/Utility/String.h" + +namespace speckle::interfac::browser::bridge { + + /*! + Interface for objects used as arguments for JS bridge arguments + + Enables deserialisation to recognise individual parameters in the serialised JS method aergument, e.g. "0", "1", etc + */ + class JSArgumentBase { + public: + /*! + Destructor + */ + virtual ~JSArgumentBase() {} + + // MARK: - Functions (const) + + /*! + Determine if the object is used as an argument template + @return True if the object is used as an argument template + */ + bool isArgumentTemplate() const { return m_isArgumentTemplate; } + + // MARK: - Functions (mutating) + + /*! + Set whether the object is used as an argument template + @param state True if the object is used as an argument template + */ + void setArgumentTemplate(bool state) { m_isArgumentTemplate = state; } + + private: + ///True if the object is used as an argument template + bool m_isArgumentTemplate = false; + }; + +} + +#endif //SPECKLE_INTERFACE_JS_BRIDGE_ARGUMENT_BASE diff --git a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgument.h b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgument.h index b2cfadd..1d4021e 100644 --- a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgument.h +++ b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgument.h @@ -2,6 +2,7 @@ #define SPECKLE_INTERFACE_JS_BRIDGE_ARGUMENT #include "Active/Serialise/Package/Package.h" +#include "Speckle/Interface/Browser/Bridge/JSArgumentBase.h" #include "Speckle/Utility/String.h" namespace speckle::interfac::browser::bridge { @@ -95,13 +96,18 @@ namespace speckle::interfac::browser::bridge { class JSArgType : public JSBridgeArgument { public: using JSBridgeArgument::JSBridgeArgument; - + + JSArgType() { + //Tag the argument object as a template where possible + if (auto arg = dynamic_cast(&value); arg != nullptr) + arg->setArgumentTemplate(true); + } /*! Copy constructor @param source The object to copy */ - JSArgType(const JSArgType& source) : JSBridgeArgument{ source }, value{ source.value } {} - + JSArgType(const JSArgType& source) : JSBridgeArgument{source}, value{source.value} {} + T value; }; diff --git a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.cpp b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.cpp index f17bf44..835a7f8 100644 --- a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.cpp +++ b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.cpp @@ -2,11 +2,13 @@ #include "Active/Serialise/Inventory/Inventory.h" #include "Active/Serialise/Item/Wrapper/ValueWrap.h" +#include "Active/Serialise/Package/Wrapper/ValueSettingWrap.h" #include "Active/Serialise/JSON/JSONTransport.h" #include "Active/Utility/BufferIn.h" using namespace active::serialise; using namespace active::serialise::json; +using namespace active::setting; using namespace speckle::interfac::browser::bridge; using namespace speckle::utility; @@ -41,7 +43,7 @@ namespace { { {"arg"}, args, 0, std::nullopt, true }, //The JS arguments are expressed as a flat array - use the array indices to map to expected vars }, }.withType(&typeid(JSBridgeArgumentWrap));; - + } /*-------------------------------------------------------------------- @@ -131,7 +133,24 @@ std::unique_ptr JSBridgeArgumentWrap::makeArgument(const Strin if (auto maker = m_argumentFactory.find(methodID); (maker != m_argumentFactory.end())) { if (auto result = reinterpret_cast(maker->second(methodID, requestID)); result != nullptr) { try { - JSONTransport().receive(std::forward(*result), Identity{}, argument); + //The argument is passed as an array of stringified JSON - first unpack the array + JSONTransport transport; + ValueSetting args; + transport.receive(ValueSettingWrap{args}, Identity{}, argument); + //Then unify the argument strings into a single JSON argument + String unifiedArgument{"{"}; + int32_t argIndex = 0; + bool isFirst = false; + for (auto& arg : args.operator std::vector()) { + if (isFirst) + isFirst = false; + else + unifiedArgument += ","; + unifiedArgument += "\"" + String{argIndex++} + "\":" + JSONTransport::convertFromJSONString(arg); + } + unifiedArgument += "}"; + //And receive the unified argument into the methiod argument + transport.receive(std::forward(*result), Identity{}, unifiedArgument); return std::unique_ptr{result}; } catch(std::runtime_error e) { //Populating the error cancels the method diff --git a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.h b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.h index 0cf838b..c126929 100644 --- a/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.h +++ b/SpeckleLib/Speckle/Interface/Browser/Bridge/JSBridgeArgumentWrap.h @@ -19,7 +19,11 @@ namespace speckle::interfac::browser::bridge { template void* constructArgument(const speckle::utility::String& method, const speckle::utility::String& request) { try { - return new T(method, request); + auto result = new T(method, request); + //Tag the argument object as a template where possible + if (auto arg = dynamic_cast(result); arg != nullptr) + arg->setArgumentTemplate(true); + return result; } catch(...) { return nullptr; //Object constructors should throw an exception if incoming data isn't viable (NB: only use for unrecoverable problems) } diff --git a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj index 5bc5faa..d36c107 100644 --- a/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj +++ b/SpeckleLib/SpeckleLib.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 210CC86F2C7E879700610F58 /* JSArgumentBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 210CC86D2C7E879700610F58 /* JSArgumentBase.h */; }; 212A88132AE48821001EAFE7 /* libArchicad27.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 21379E082AE47A6400A1584C /* libArchicad27.a */; platformFilters = (macos, ); }; 2193517B2C624FC100E5A69C /* MenuSubscriber.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 219351782C624FC100E5A69C /* MenuSubscriber.cpp */; }; 2193518C2C62655700E5A69C /* MenuEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 219351892C62655700E5A69C /* MenuEvent.h */; }; @@ -69,6 +70,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 210CC86D2C7E879700610F58 /* JSArgumentBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSArgumentBase.h; sourceTree = ""; }; 212A87EF2AE4868C001EAFE7 /* SpeckleLib-test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "SpeckleLib-test.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 21329F472BFA611C00B5C7AF /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 21329F632BFD452C00B5C7AF /* Environment.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Environment.md; sourceTree = ""; }; @@ -312,6 +314,7 @@ 21F69F4A2C6CCC25008B6A06 /* BrowserBridge.cpp */, 21F69F4B2C6CCC25008B6A06 /* BrowserBridge.h */, 21F69F582C6CDAEE008B6A06 /* Functions */, + 210CC86D2C7E879700610F58 /* JSArgumentBase.h */, 21F69FA52C733EDA008B6A06 /* JSBridgeArgument.cpp */, 21F69F4D2C6CCC25008B6A06 /* JSBridgeArgument.h */, 21F69F802C6FF3B0008B6A06 /* JSBridgeArgumentWrap.cpp */, @@ -385,6 +388,7 @@ buildActionMask = 2147483647; files = ( 21F69F5A2C6CDB67008B6A06 /* FunctionBinding.h in Headers */, + 210CC86F2C7E879700610F58 /* JSArgumentBase.h in Headers */, 21B67D0D2C7E0E8D00FD64FC /* ErrorReport.h in Headers */, 21B67D002C7CE15100FD64FC /* Exception.h in Headers */, 2193518C2C62655700E5A69C /* MenuEvent.h in Headers */,