Files
speckle-cpp-connectors/SpeckleLib/Speckle/Interface/Browser/JSFunction.h
T
Ralph Wessel 4ff7d68516 ElementHighlighter ensures layers are visible (on request) before selecting target elements
Updates to allow attribute changes to be written
Workaround to force VS to recognise template specialisations
2024-11-20 21:49:47 +00:00

113 lines
4.1 KiB
C++

#ifndef SPECKLE_INTERFACE_JS_FUNCTION
#define SPECKLE_INTERFACE_JS_FUNCTION
#include "Active/Serialise/Inventory/Identity.h"
#include "Active/Serialise/Item/Wrapper/ItemWrap.h"
#include "Active/Serialise/Package/NullPackage.h"
#include "Active/Serialise/Package/Wrapper/PackageWrap.h"
#include "Speckle/Interface/Browser/JSBinding.h"
#include "Speckle/Interface/Browser/NamedFunction.h"
#include "Speckle/Utility/String.h"
#include <functional>
#include <type_traits>
#include <utility>
namespace speckle::interfac::browser {
/*!
Interface for a C++ function binding to a JavaScript function
@tparam Argument The function parameter type
@tparam Return The function return type
@tparam Binding The platform JS binding (defines argument/result serialisation and transport mechanism to (de)serialise)
*/
template<typename Argument, typename Return, typename Binding>
class JSFunction : public NamedFunction<Argument, Return>, public Binding {
public:
// MARK: - Types
using base = NamedFunction<Argument, Return>;
//A bridged C++ function
using Function = base::Function;
// MARK: - Constructors
/*!
Constructor
@param jsName The function name (as called from JavaScript)
@param function The C++ function bound to the name
*/
JSFunction(const speckle::utility::String& jsName, Function function) : base{jsName, function} {}
/*!
Copy constructor
@param source The object to copy
*/
JSFunction(const JSFunction& source) = default;
// MARK: - Functions (const)
/*!
Get the bound function name
@return The bound function name
*/
speckle::utility::String getName() const override { return base::getName(); }
/*!
Execute the function
@param param The input parameter
@return The function result
*/
typename Binding::ValueType execute(const typename Binding::ValueType& param) const override;
};
/*--------------------------------------------------------------------
Execute the function
param: The input parameter
return: The function result
--------------------------------------------------------------------*/
template<typename Argument, typename Return, typename Binding>
Binding::ValueType JSFunction<Argument, Return, Binding>::execute(const typename Binding::ValueType& bindingParameters) const {
typename Binding::Transport transport;
//Process any returned result into the binding value type
auto processResult = [&, transport](Return* outgoing) -> typename Binding::ValueType {
if constexpr(!std::is_same<Return, void>::value) {
if (outgoing == nullptr)
throw; //NB: Throw a system exception here in future with a defined error
typename Binding::ValueType result;
transport.send(std::move(*outgoing), active::serialise::Identity{}, result);
return result;
}
return typename Binding::ValueType{};
};
//Ensure void parameters and/or return values are handled correctly
if constexpr(std::is_same<Argument, void>::value) {
active::serialise::NullPackage null;
if constexpr(std::is_same<Return, void>::value)
base::execute(null); //No parameters and no return value
else {
auto result = base::execute(null); //No parameters with return value
return processResult(dynamic_cast<Return*>(result.get()));
}
} else {
Argument argument;
if constexpr (std::is_base_of<active::serialise::Package, Argument>::value)
transport.receive(active::serialise::PackageWrap{argument}, active::serialise::Identity{}, bindingParameters);
else
transport.receive(active::serialise::ItemWrap{argument}, active::serialise::Identity{}, bindingParameters);
if constexpr(std::is_same<Return, void>::value)
base::execute(argument); //Parameters and no return value
else {
auto result = base::execute(argument); //Parameters with return value
return processResult(dynamic_cast<Return*>(result.get()));
}
}
return typename Binding::ValueType{};
} //JSFunction<Argument, Return, Binding>::execute
}
#endif //SPECKLE_INTERFACE_JS_FUNCTION