Skip to content

feat(wasm)!: native JS arrays via emscripten::val (replaces VectorDouble)#2977

Merged
ibell merged 1 commit into
masterfrom
ihb/wasm-val-arrays-emcc5
May 24, 2026
Merged

feat(wasm)!: native JS arrays via emscripten::val (replaces VectorDouble)#2977
ibell merged 1 commit into
masterfrom
ihb/wasm-val-arrays-emcc5

Conversation

@ibell
Copy link
Copy Markdown
Contributor

@ibell ibell commented May 24, 2026

Summary

Replaces the embind VectorDouble/VectorString wrapper classes on the JS binding surface with native JavaScript arrays via emscripten::val.

Before

var v = new coolprop.VectorDouble();
v.push_back(0.4); v.push_back(0.6);
AS.set_mole_fractions(v);
v.delete();

var z = AS.get_mole_fractions();
console.log(z.get(0).value(), z.get(1).value(), z.size());
z.delete();

After

AS.set_mole_fractions([0.4, 0.6]);

var z = AS.get_mole_fractions();
console.log(z[0], z[1], z.length);

Same shape for get_phase_envelope_data() — returns a plain JS object whose fields (T, p, …) are native arrays. No .delete() calls needed for vector returns; standard JS GC handles them.

Two thin helpers in src/emscripten_interface.cxx do the conversion:

template <class T>
val vec_to_js_array(const std::vector<T>& v);
std::vector<double> js_array_to_vec(const val& arr);

Drops the register_vector/register_optional/value_object registrations, the #include <optional>, and the set_mole_fractions_double/_mass_fractions_double/_volu_fractions_double EMSCRIPTEN-only wrappers from include/AbstractState.h (no longer needed — the val→vector conversion happens in the lambda). The direct internal::_embind_register_optional call from PR #2974 (CoolProp-71a.8) is also gone with this refactor — no more optional<double> registration dependency.

Why this doesn't bump emsdk

The original motivation was to also unblock the emcc 5.x migration (CoolProp-71a.2) by removing the optional<double> dependency that breaks emcc's EMBIND_AOT path. Investigation showed AOT still fails against our binding shape at the link-time <<< EMBIND_AOT_INVOKERS >>> substitution (tsgen.js itself succeeds; the sentinel is missing from the final JS template). The Dockerfile + CI workflow stay pinned to emsdk 4.0.12. CoolProp-71a.2 stays open with this finding documented in the bead.

Breaking change

JS callers using the prior VectorDouble pattern will need to update (see Summary above). Changelog entry added under "Behavior changes (potentially breaking)".

Test plan

  • cd wrappers/Javascript && docker compose run --rm runner against pinned emsdk 4.0.12 links cleanly
  • node test_wasm.mjs exits 0 with all 5 sections passing — including:
    • mixture composition round-trip: get_mole_fractions() returns [0.4, 0.6] (real JS Array)
    • envelope mid-point: env.T[107] and env.p[107] read directly
  • CI Javascript library workflow green

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • JavaScript/WASM API now uses native JavaScript arrays for composition vectors and phase-envelope data. Setters accept arrays directly, and getters return native arrays, improving the developer experience.
  • Documentation

    • Updated changelog documenting JavaScript API behavior changes.

Review Change Stack

…ble) (CoolProp-71a partial)

The JS binding surface previously required JS code to interact with an
embind ``register_vector<double>("VectorDouble")`` wrapper class — push_back
on the way in, .get(i).value() / size() on the way out, with manual .delete()
for memory.  The .get(i) path also depended on a workaround
(CoolProp-71a.8) to register std::optional<double> against an emcc
template-elision quirk under -O3.

This PR replaces every vector-shaped binding with native JS arrays via
emscripten::val:

  - Setters take a JS array directly:
      AS.set_mole_fractions([0.4, 0.6])

  - Getters return a JS Array:
      var z = AS.get_mole_fractions();
      console.log(z[0], z.length);

  - get_phase_envelope_data() returns a plain object whose fields are
    native arrays:
      var d = AS.get_phase_envelope_data();
      console.log(d.T[i], d.p[i]);

Cleaner API, no VectorDouble/VectorString classes on the JS side, no
optional<double> registration needed (CoolProp-71a.8's workaround is
fully removed), no #include <optional> needed in the binding TU.

Two thin C++ helpers in src/emscripten_interface.cxx do the conversion:

  template <class T>
  val vec_to_js_array(const std::vector<T>& v);
  std::vector<double> js_array_to_vec(const val& arr);

# Why this PR doesn't bump emsdk

The original motivation was to also unblock the emcc 5.x migration
(CoolProp-71a.2) by removing the optional<double> dependency that breaks
emcc's EMBIND_AOT path.  Investigation showed AOT still fails against
our binding shape at the link-time '<<< EMBIND_AOT_INVOKERS >>>'
substitution step (tsgen.js itself succeeds; the sentinel is missing
from the final JS template).  The Dockerfile + CI workflow stay pinned
to emsdk 4.0.12.  CoolProp-71a.2 stays open with this finding documented.

# Breaking change

JS callers using the previous VectorDouble pattern will need to update:

  Before:  var v = new coolprop.VectorDouble();
           v.push_back(0.4); v.push_back(0.6);
           AS.set_mole_fractions(v);
           v.delete();

  After:   AS.set_mole_fractions([0.4, 0.6]);

  Before:  var z = AS.get_mole_fractions();
           console.log(z.get(0).value(), z.get(1).value());
           z.delete();

  After:   var z = AS.get_mole_fractions();
           console.log(z[0], z[1]);

# Test verification

Local docker build + node test_wasm.mjs against pinned emsdk 4.0.12:
all 5 sections pass (AbstractState, mixture set+get round-trip, enum
coverage, phase envelope value reads, derivative bindings).
test_wasm.mjs no longer constructs/manipulates VectorDouble; uses
[0.4, 0.6] and z[i] / d.T[i] directly.

Changelog entry added under 'Behavior changes (potentially breaking)'.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: aef4423f-0582-4e89-9b77-00ca73b1979f

📥 Commits

Reviewing files that changed from the base of the PR and between 2228c28 and 3859da2.

📒 Files selected for processing (5)
  • Web/coolprop/changelog.rst
  • include/AbstractState.h
  • src/emscripten_interface.cxx
  • wrappers/Javascript/Dockerfile
  • wrappers/Javascript/test_wasm.mjs
💤 Files with no reviewable changes (1)
  • include/AbstractState.h

📝 Walkthrough

Walkthrough

This PR migrates the CoolProp JavaScript/WASM interface from embind-managed vector wrapper types (VectorDouble, VectorString) to native JavaScript arrays. The change includes conversion utilities, updated bindings for composition fractions and phase envelopes, header cleanup, and test validation of the new array-based API surface.

Changes

WASM Vector to Native Array Binding Migration

Layer / File(s) Summary
API Change Documentation
Web/coolprop/changelog.rst
Changelog entry documents the shift from embind wrapper types to native JS arrays for composition vectors and phase-envelope data, with setters accepting and getters returning plain arrays.
Header Cleanup
include/AbstractState.h
Removes the Emscripten-only set_mole_fractions_double, set_mass_fractions_double, and set_volu_fractions_double wrapper methods that were used for embind overload disambiguation.
Emscripten Binding Implementation
src/emscripten_interface.cxx
Adds vec_to_js_array and js_array_to_vec conversion helpers; updates fraction setters to accept emscripten::val JS arrays and convert to std::vector; updates fraction getters to return native JS arrays; rebinds get_phase_envelope_data to a lambda returning a plain JS object with per-field native arrays.
Test Updates & Build Context
wrappers/Javascript/test_wasm.mjs, wrappers/Javascript/Dockerfile
Integration tests now use native JS arrays directly for composition and phase-envelope access, eliminating VectorDouble construction and manual element access; Dockerfile comment updated to document current version pinning reason (EMBIND_AOT migration issue).

Poem

A wrapper falls away, arrays rise so bright,
No more embind vectors wrapping up the night,
JavaScript embraces nature's native form,
Each fraction and phase data, plain and warm! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: replacing embind VectorDouble wrapper classes with native JavaScript arrays using emscripten::val. It is specific, concise, and directly reflects the primary objective of the changeset across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ihb/wasm-val-arrays-emcc5

Comment @coderabbitai help to get the list of available commands and usage tips.

@ibell ibell merged commit 82d58c0 into master May 24, 2026
21 of 22 checks passed
@ibell ibell deleted the ihb/wasm-val-arrays-emcc5 branch May 24, 2026 16:24
@ibell ibell added this to the v8.0.0 milestone May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant