Page MenuHomePhabricator

[web] add `std::vector` (C++) <-> `Array` (JS) marshalling
ClosedPublic

Authored by kamil on Jul 19 2023, 6:37 AM.
Tags
None
Referenced Files
F2157636: D8552.id29115.diff
Mon, Jul 1, 2:12 AM
F2157635: D8552.id28826.diff
Mon, Jul 1, 2:12 AM
F2157576: D8552.diff
Mon, Jul 1, 2:08 AM
Unknown Object (File)
Sat, Jun 29, 5:59 PM
Unknown Object (File)
Sun, Jun 23, 2:50 PM
Unknown Object (File)
Mon, Jun 3, 8:43 PM
Unknown Object (File)
May 26 2024, 5:20 PM
Unknown Object (File)
May 4 2024, 3:20 PM
Subscribers

Details

Summary

Why it's .cpp file?

This code does not work when added to .h file (emscripten does not parse it then and has no reflection in generated module).

Why it's called SQLiteQueryExecutorBindings.cpp?
This code to work (for some reason) needs to be placed along with binding, in next diff I am adding SQLiteQueryExecutor bindings to this file.

Why this idea?
We can automate using JS array <-> std::vector marshalling. Without this will need to:

  • bind each vector type (for emscripten std::vector<int> and std::vector<std::string> are two different types.
  • passing data to .wasm module, we will have to create vector objects in JS, add data to it using put() method
  • parse data returned from .wasm module

This makes this process cleaner and easier for devs.

Inspiration
This issue: 11070

How it works?

  • It uses Template Specialization concept
  • it uses SFINAE to ensure it behaves properly for std::vector and ignores other types without an error

Sources:

Depends on D8551

Test Plan

Tested at the end of the stack - making sure that we can pass/retrieve array to .wasm module and works as a vector for both objects/classes and primitive variables as vector elements.

Diff Detail

Repository
rCOMM Comm
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

kamil held this revision as a draft.
kamil edited the test plan for this revision. (Show Details)
kamil added inline comments.
web/scripts/run_emscripten.sh
90 ↗(On Diff #28826)

comment to show this change

kamil published this revision for review.Jul 19 2023, 9:01 AM

My cpp is very rusty, but shouldn't we have a header file? how will we call methods defined here?

This one is really interesting! BindingType and TypeID both already exist in the emscripten codebase, but they are generic definitions (+ some specializations for specific types). We can add our own specializations for vectors, as this diff is doing. And c++ will use the "most specific" definition, so in this case for BindingType<vector<int>>, our definition will be more specific, than the generic BindingType<T> provided by emscripten.

web/cpp/SQLiteQueryExecutorBindings.cpp
8 ↗(On Diff #28826)

Specialization for vector types (with any inner type/ allocator)

12–19 ↗(On Diff #28826)

Seems like this is converting the vector using the emscripten val type.

25–29 ↗(On Diff #28826)

Here we are using SFINAE (substitution failure is not an error). In the definition of the TypeID the second type parameter is not used anywhere but it's used for SFINAE.

std::enable_if_t has ::value if and only if it's first (compile-time) boolean parameter is true. Otherwise it doesn't have ::value member, and compilation fails. That means we get _substitution failure_, but c++ keeps going because it's not an error. It will just use the next most specific variation.

std::is_same is simple. It just returns true or false depending if it's two type parameters are the same.

Canonicalized is an emscripten utility that strips const, violitale or references & from the type.

So finally the result is that, this specialization works for any vector<T>, const vector<T> or vector<T& (or a combination)

31 ↗(On Diff #28826)

The BindingType is serializing using val, so TypeID has to match

Thanks @michal for the extensive comment! My summary was too general though

tomek added 1 blocking reviewer(s): michal.

Looks ok, but I don't know C++ enough to be sure

This revision is now accepted and ready to land.Jul 24 2023, 7:20 AM