include/static/unoembindhelpers/PrimaryBindings.hxx | 36 +++++++++++++++++ static/source/embindmaker/embindmaker.cxx | 42 ++++++++++++++++++++ 2 files changed, 78 insertions(+)
New commits: commit 8869994d5e62c422465f52b25dc3792be9add92d Author: Stephan Bergmann <stephan.bergm...@allotropia.de> AuthorDate: Wed Jan 31 17:31:49 2024 +0100 Commit: Stephan Bergmann <stephan.bergm...@allotropia.de> CommitDate: Thu Feb 1 08:46:47 2024 +0100 embindmaker: Add support for sequence types Ideally, JS code would have a way to create instances of arbitrary UNO sequence types (to e.g. put them into Anys), but that goes against the static nature of Embind. So at least register JS support for all those UNO sequence types that are actually used in the UNO API. (This would cause duplicate failures, though, if we generated multiple separate .cxx files from embindmaker invocations, with registration code for the same UNO sequence types.) (Even more ideally, UNO sequence types could map to JS arrays, and/oror be garbage-collected on the JS side rather than needing explicit delete(). The resize/size/get/set interface in unoembindhelpers::registerSequence is modelled after Embind's emscripten::register_vector.) Change-Id: Icd38b2e03db442dd613b9222b9bd092f947f7bec Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162849 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <stephan.bergm...@allotropia.de> diff --git a/include/static/unoembindhelpers/PrimaryBindings.hxx b/include/static/unoembindhelpers/PrimaryBindings.hxx index 5b677345b86b..6f8005b1656c 100644 --- a/include/static/unoembindhelpers/PrimaryBindings.hxx +++ b/include/static/unoembindhelpers/PrimaryBindings.hxx @@ -11,9 +11,12 @@ #include <sal/config.h> +#include <stdexcept> + #include <emscripten/bind.h> #include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/Sequence.hxx> #include <sal/types.h> template <typename T> struct emscripten::smart_ptr_trait<css::uno::Reference<T>> @@ -48,6 +51,39 @@ template <typename T> struct UnoInOutParam T value; }; + +template <typename T> +void checkSequenceAccess(css::uno::Sequence<T> const& sequence, sal_Int32 index) +{ + if (index < 0 || index >= sequence.getLength()) + { + throw std::out_of_range("index out of bounds"); + } +} + +template <typename T> void registerSequence(char const* name) +{ + emscripten::class_<css::uno::Sequence<T>>(name) + .template constructor<sal_Int32>() + .function("resize", + +[](css::uno::Sequence<T>& self, sal_Int32 size) { + if (size < 0) + { + throw std::invalid_argument("negative size"); + } + self.realloc(size); + }) + .function("size", &css::uno::Sequence<T>::getLength) + .function("get", + +[](css::uno::Sequence<T> const& self, sal_Int32 index) { + checkSequenceAccess(self, index); + return self[index]; + }) + .function("set", +[](css::uno::Sequence<T>& self, sal_Int32 index, T const& value) { + checkSequenceAccess(self, index); + self.getArray()[index] = value; + }); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/static/source/embindmaker/embindmaker.cxx b/static/source/embindmaker/embindmaker.cxx index 43d315679d6c..fb6ba0880508 100644 --- a/static/source/embindmaker/embindmaker.cxx +++ b/static/source/embindmaker/embindmaker.cxx @@ -725,6 +725,16 @@ void dumpRegisterFunctionEpilog(std::ostream& out, unsigned long long& counter) } } +void recordSequenceTypes(rtl::Reference<TypeManager> const& manager, OUString const& type, + std::set<OUString>& sequences) +{ + auto const res = resolveAllTypedefs(manager, type); + if (manager->getSort(res) == codemaker::UnoType::Sort::Sequence) + { + sequences.insert(res); + } +} + void writeJsMap(std::ostream& out, Module const& module, std::string const& prefix) { auto comma = false; @@ -852,6 +862,7 @@ SAL_IMPLEMENT_MAIN() cppOut << "; "; dumpRegisterFunctionEpilog(cppOut, n); } + std::set<OUString> sequences; for (auto const& str : structs) { auto const ent = mgr->getManager()->findEntity(str); @@ -878,6 +889,10 @@ SAL_IMPLEMENT_MAIN() } cppOut << "; "; dumpRegisterFunctionEpilog(cppOut, n); + for (auto const& mem : strEnt->getDirectMembers()) + { + recordSequenceTypes(mgr, mem.type, sequences); + } } for (auto const& ifc : interfaces) { @@ -931,6 +946,18 @@ SAL_IMPLEMENT_MAIN() dumpMethods(cppOut, mgr, ifc, ifcEnt, {}); cppOut << " ; "; dumpRegisterFunctionEpilog(cppOut, n); + for (auto const& attr : ifcEnt->getDirectAttributes()) + { + recordSequenceTypes(mgr, attr.type, sequences); + } + for (auto const& meth : ifcEnt->getDirectMethods()) + { + for (auto const& param : meth.parameters) + { + recordSequenceTypes(mgr, param.type, sequences); + } + recordSequenceTypes(mgr, meth.returnType, sequences); + } } for (auto const& srv : services) { @@ -960,6 +987,21 @@ SAL_IMPLEMENT_MAIN() { cppOut << " register" << i << "(); "; } + for (auto const& seq : sequences) + { + cppOut << " ::unoembindhelpers::registerSequence<"; + assert(seq.startsWith("[]")); + dumpType(cppOut, mgr, seq.copy(2)); + cppOut << ">(\"uno_Sequence"; + sal_Int32 k; + auto const nuc = b2u(codemaker::UnoType::decompose(u2b(seq), &k)); + assert(k >= 1); + if (k > 1) + { + cppOut << k; + } + cppOut << "_" << jsName(nuc) << "\"); "; + } cppOut << "} "; cppOut.close(); if (!cppOut)