diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index f8a12af789023..fd2e248f5fdab 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -1919,35 +1919,8 @@ class_> register_map(const char* name) { ; } -//////////////////////////////////////////////////////////////////////////////// -// std::optional -//////////////////////////////////////////////////////////////////////////////// - -namespace internal { -template -struct BindingType> { - using ValBinding = BindingType; - using WireType = ValBinding::WireType; - - template - static WireType toWireType(std::optional value, rvp::default_tag) { - if (value) { - return ValBinding::toWireType(val(*value, allow_raw_pointers()), rvp::default_tag{}); - } - return ValBinding::toWireType(val::undefined(), rvp::default_tag{}); - } - static std::optional fromWireType(WireType value) { - val optional = val::take_ownership(value); - if (optional.isUndefined()) { - return {}; - } - return optional.as(); - } -}; -} // end namespace internal - //////////////////////////////////////////////////////////////////////////////// // ENUMS diff --git a/system/include/emscripten/val.h b/system/include/emscripten/val.h index c4e8deaddb419..983c821afe66e 100644 --- a/system/include/emscripten/val.h +++ b/system/include/emscripten/val.h @@ -15,6 +15,7 @@ #include #include #include +#include #if __cplusplus >= 202002L #include #include @@ -815,6 +816,29 @@ struct BindingType::value && } }; +template +struct BindingType> { + using ValBinding = BindingType; + using WireType = ValBinding::WireType; + + template + static WireType toWireType(std::optional value, rvp::default_tag) { + if (value) { + return ValBinding::toWireType(val(*value, allow_raw_pointers()), rvp::default_tag{}); + } + return ValBinding::toWireType(val::undefined(), rvp::default_tag{}); + } + + + static std::optional fromWireType(WireType value) { + val optional = val::take_ownership(value); + if (optional.isUndefined()) { + return {}; + } + return optional.as(); + } +}; + } template diff --git a/test/embind/test_optional_val_lib.cpp b/test/embind/test_optional_val_lib.cpp new file mode 100644 index 0000000000000..f5d38baafba88 --- /dev/null +++ b/test/embind/test_optional_val_lib.cpp @@ -0,0 +1,14 @@ +#include +#include +#include + +// This file deliberately does NOT include + +class MyType { +public: + void RunCallback(emscripten::val callback); +}; + +void MyType::RunCallback(emscripten::val cb) { + cb(std::make_optional(std::string{"Hey"})); +} diff --git a/test/embind/test_optional_val_main.cpp b/test/embind/test_optional_val_main.cpp new file mode 100644 index 0000000000000..3f94c5dc50953 --- /dev/null +++ b/test/embind/test_optional_val_main.cpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +using namespace emscripten; + +class MyType { +public: + void RunCallback(emscripten::val callback); +}; + +int main() { + EM_ASM( + let value = new Module.MyType(); + value.RunCallback((e) => { + console.log("Received: " + e); + if (e !== "Hey") throw "Expected 'Hey', got " + e; + }); + ); + std::cout << "done" << std::endl; +} + +EMSCRIPTEN_BINDINGS(my_module) { + register_optional(); + + class_("MyType") + .constructor<>() + .function("RunCallback", &MyType::RunCallback); +} diff --git a/test/test_other.py b/test/test_other.py index f648b5681e4d9..ce6b514e4a87f 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -14471,6 +14471,15 @@ def test_embind_no_exceptions(self): create_file('a.cpp', '#define try\n#define catch if (0)\n#include ') self.run_process([EMXX, '-fno-exceptions', '-std=c++23', '-lembind', 'a.cpp']) + def test_embind_optional_val_no_bind(self): + # Ensure passing std::optional to emscripten::val works if + # was not included in the compilation unit using val. + self.run_process([EMXX,'-lembind', + test_file('embind/test_optional_val_main.cpp'), + test_file('embind/test_optional_val_lib.cpp')]) + output = self.run_js('a.out.js') + self.assertContained('done', output) + def test_no_pthread(self): self.do_runf('hello_world.c', cflags=['-pthread', '-no-pthread']) self.assertExists('hello_world.js')