@crossbind/core-embind-rust 2.0.0-beta.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,268 @@
1
+ // WEB adapter: stable flat C-ABI -> emscripten embind (passthrough, 10-param identical), plus
2
+ // the host-specific typeid getters. Registration fires from the producer crate's init-array
3
+ // (embind_rs::bindings!), so there is no C++ trigger here - the shim is getters + passthroughs.
4
+ #include "../include/crossbind_embind.h"
5
+ #include <emscripten/bind.h>
6
+ #include <emscripten/em_js.h>
7
+ #include <emscripten/val.h>
8
+ #include <cstdint>
9
+ #include <cstdlib>
10
+ #include <cstring>
11
+ #include <optional>
12
+ #include <string>
13
+ #include <typeinfo>
14
+ #include <unordered_set>
15
+
16
+ // Producer error escape (embind_rs::raise_err): decode the [u32 len][bytes] message, free it,
17
+ // and throw a real JS Error from inside the invoker - it propagates to the JS caller unchanged.
18
+ EM_JS(void, crossbind_embind_raise_error, (uint8_t* w), {
19
+ const len = HEAPU32[w >> 2];
20
+ const msg = UTF8ToString(w + 4, len);
21
+ _free(w);
22
+ throw new Error(msg);
23
+ });
24
+
25
+ // Producer sig chars that emscripten's dynCall alphabet lacks: 's' (a jsi-marshalling hint;
26
+ // the wasm string wire is a real pointer) -> 'p', and 'u' (unsigned 64 - signedness lives in
27
+ // the registered typeid) -> 'j'. Translated copies are one-time registration data, leaked.
28
+ static const char* sigForWasm(const char* sig) {
29
+ if (!sig || (!std::strchr(sig, 's') && !std::strchr(sig, 'u'))) return sig;
30
+ char* copy = strdup(sig);
31
+ for (char* c = copy; *c; ++c) {
32
+ if (*c == 's') *c = 'p';
33
+ else if (*c == 'u') *c = 'j';
34
+ }
35
+ return copy;
36
+ }
37
+
38
+ extern "C" {
39
+
40
+ // Primitive type keys: bridge to the builtin typeids emscripten registered.
41
+ const void* crossbind_tid_int() { return &typeid(int); }
42
+ const void* crossbind_tid_double() { return &typeid(double); }
43
+ const void* crossbind_tid_bool() { return &typeid(bool); }
44
+ const void* crossbind_tid_void() { return &typeid(void); }
45
+ const void* crossbind_tid_std_string() { return &typeid(std::string); }
46
+ const void* crossbind_tid_int64() { return &typeid(int64_t); }
47
+ const void* crossbind_tid_uint64() { return &typeid(uint64_t); }
48
+ // Adapter-local identities, NOT &typeid(std::optional<T>): linked C++ bindings may register
49
+ // the real optional typeids themselves, and these types never interop with C++ signatures.
50
+ const void* crossbind_tid_optional_int() { static const char t = 0; return &t; }
51
+ const void* crossbind_tid_optional_double() { static const char t = 0; return &t; }
52
+ const void* crossbind_tid_optional_bool() { static const char t = 0; return &t; }
53
+ const void* crossbind_tid_optional_string() { static const char t = 0; return &t; }
54
+
55
+ }
56
+
57
+ // Optional wire on wasm is an EM_VAL handle (None = the reserved undefined constant from
58
+ // emscripten's own header). Some-values become handles through Emval.toHandle; the registered
59
+ // optional type's fromWireType does toValue + decref, so the refcount stays balanced.
60
+ EM_JS(void*, crossbind_emval_from_number_js, (double v), { return Emval.toHandle(v); });
61
+ EM_JS(void*, crossbind_emval_from_bool_js, (int v), { return Emval.toHandle(!!v); });
62
+ EM_JS(void*, crossbind_emval_from_string_js, (uint8_t* w), {
63
+ const len = HEAPU32[w >> 2];
64
+ const s = UTF8ToString(w + 4, len);
65
+ _free(w);
66
+ return Emval.toHandle(s);
67
+ });
68
+
69
+ extern "C" {
70
+ void* crossbind_emval_take_value(CrossbindTid inner, const void* argv) {
71
+ if (inner == crossbind_tid_int()) return crossbind_emval_from_number_js((double)*(const int32_t*)argv);
72
+ if (inner == crossbind_tid_double()) return crossbind_emval_from_number_js(*(const double*)argv);
73
+ if (inner == crossbind_tid_bool()) return crossbind_emval_from_bool_js((int)*(const uint8_t*)argv);
74
+ return crossbind_emval_from_string_js(*(uint8_t* const*)argv); // std::string wire pointer
75
+ }
76
+ void* crossbind_emval_undefined() {
77
+ return (void*)emscripten::internal::_EMVAL_UNDEFINED;
78
+ }
79
+
80
+ // Optional PARAMETERS: embind hands the invoker an EM_VAL handle; these readers consume its
81
+ // reference (take_ownership) and yield the native repr, 0 for undefined/null.
82
+ int crossbind_emval_opt_i32(void* h, int32_t* out) {
83
+ emscripten::val v = emscripten::val::take_ownership((emscripten::EM_VAL)h);
84
+ if (v.isUndefined() || v.isNull()) return 0;
85
+ *out = v.as<int32_t>();
86
+ return 1;
87
+ }
88
+ int crossbind_emval_opt_f64(void* h, double* out) {
89
+ emscripten::val v = emscripten::val::take_ownership((emscripten::EM_VAL)h);
90
+ if (v.isUndefined() || v.isNull()) return 0;
91
+ *out = v.as<double>();
92
+ return 1;
93
+ }
94
+ int crossbind_emval_opt_bool(void* h, uint8_t* out) {
95
+ emscripten::val v = emscripten::val::take_ownership((emscripten::EM_VAL)h);
96
+ if (v.isUndefined() || v.isNull()) return 0;
97
+ *out = v.as<bool>() ? 1 : 0;
98
+ return 1;
99
+ }
100
+ int crossbind_emval_opt_string(void* h, uint8_t** out) {
101
+ emscripten::val v = emscripten::val::take_ownership((emscripten::EM_VAL)h);
102
+ if (v.isUndefined() || v.isNull()) return 0;
103
+ std::string s = v.as<std::string>();
104
+ uint8_t* w = (uint8_t*)malloc(4 + s.size());
105
+ uint32_t len = (uint32_t)s.size();
106
+ std::memcpy(w, &len, 4);
107
+ std::memcpy(w + 4, s.data(), s.size());
108
+ *out = w;
109
+ return 1;
110
+ }
111
+
112
+ // JSON-value bridge (serde_json::Value): deep copy through the host's canonical JSON codec.
113
+ // Wire is the usual [u32 len][bytes]; handles cross owned (incref on give, take_ownership on
114
+ // receive), matching the Option emval discipline above.
115
+ const void* crossbind_tid_emval() { return &typeid(emscripten::val); }
116
+
117
+ void* crossbind_emval_json_to_handle(uint8_t* w) {
118
+ const uint32_t len = *(const uint32_t*)w;
119
+ std::string s((const char*)(w + 4), len);
120
+ free(w);
121
+ emscripten::val v = emscripten::val::global("JSON").call<emscripten::val>("parse", emscripten::val::u8string(s.c_str()));
122
+ emscripten::EM_VAL h = v.as_handle();
123
+ emscripten::internal::_emval_incref(h);
124
+ return (void*)h;
125
+ }
126
+
127
+ uint8_t* crossbind_emval_handle_to_json(void* h) {
128
+ emscripten::val v = emscripten::val::take_ownership((emscripten::EM_VAL)h);
129
+ emscripten::val j = emscripten::val::global("JSON").call<emscripten::val>("stringify", v);
130
+ // JSON.stringify(undefined / a bare function) yields undefined: cross as null.
131
+ std::string s = j.isUndefined() ? "null" : j.as<std::string>();
132
+ uint8_t* w = (uint8_t*)malloc(4 + s.size());
133
+ uint32_t len = (uint32_t)s.size();
134
+ std::memcpy(w, &len, 4);
135
+ std::memcpy(w + 4, s.data(), s.size());
136
+ return w;
137
+ }
138
+
139
+ // emscripten's real registration functions (extern "C" in bind.h).
140
+ void _embind_register_class(CrossbindTid, CrossbindTid, CrossbindTid, CrossbindTid, const char*, CrossbindFn, const char*, CrossbindFn, const char*, CrossbindFn, const char*, const char*, CrossbindFn);
141
+ void _embind_register_class_constructor(CrossbindTid, unsigned, const CrossbindTid*, const char*, CrossbindFn, CrossbindFn);
142
+ void _embind_register_class_function(CrossbindTid, const char*, unsigned, const CrossbindTid*, const char*, CrossbindFn, void*, unsigned, bool, bool);
143
+ void _embind_register_class_class_function(CrossbindTid, const char*, unsigned, const CrossbindTid*, const char*, CrossbindFn, CrossbindFn, bool, bool);
144
+ void _embind_register_function(const char*, unsigned, const CrossbindTid*, const char*, CrossbindFn, CrossbindFn, bool, bool);
145
+ void _embind_register_optional(CrossbindTid, CrossbindTid);
146
+ void _embind_register_smart_ptr(CrossbindTid, CrossbindTid, const char*, emscripten::sharing_policy, const char*, CrossbindFn, const char*, CrossbindFn, const char*, CrossbindFn, const char*, CrossbindFn);
147
+ void _embind_register_enum(CrossbindTid, const char*, size_t, bool, int);
148
+ void _embind_register_enum_value(CrossbindTid, const char*, int);
149
+ void _embind_register_value_object(CrossbindTid, const char*, const char*, CrossbindFn, const char*, CrossbindFn);
150
+ void _embind_register_value_object_field(CrossbindTid, const char*, CrossbindTid, const char*, CrossbindFn, void*, CrossbindTid, const char*, CrossbindFn, void*);
151
+ void _embind_finalize_value_object(CrossbindTid);
152
+
153
+ void crossbind_embind_register_class(CrossbindTid a, CrossbindTid b, CrossbindTid c, CrossbindTid d, const char* e, CrossbindFn f, const char* g, CrossbindFn h, const char* i, CrossbindFn j, const char* k, const char* l, CrossbindFn m) {
154
+ _embind_register_class(a, b, c, d, e, f, g, h, i, j, k, l, m);
155
+ }
156
+ void crossbind_embind_register_class_constructor(CrossbindTid a, unsigned b, const CrossbindTid* c, const char* d, CrossbindFn e, CrossbindFn f) {
157
+ _embind_register_class_constructor(a, b, c, sigForWasm(d), e, f);
158
+ }
159
+ void crossbind_embind_register_class_function(CrossbindTid a, const char* b, unsigned c, const CrossbindTid* d, const char* e, CrossbindFn f, void* g, unsigned h, bool i, bool j) {
160
+ _embind_register_class_function(a, b, c, d, sigForWasm(e), f, g, h, i, j); // 10-param, identical
161
+ }
162
+ void crossbind_embind_register_class_class_function(CrossbindTid a, const char* b, unsigned c, const CrossbindTid* d, const char* e, CrossbindFn f, CrossbindFn g, bool h, bool i) {
163
+ _embind_register_class_class_function(a, b, c, d, sigForWasm(e), f, g, h, i);
164
+ }
165
+ void crossbind_embind_register_function(const char* a, unsigned b, const CrossbindTid* c, const char* d, CrossbindFn e, CrossbindFn f, bool g, bool h) {
166
+ _embind_register_function(a, b, c, sigForWasm(d), e, f, g, h);
167
+ }
168
+ // Idempotent: every Rust archive in the link may ask for the same optional type.
169
+ void crossbind_embind_register_optional(CrossbindTid opt, CrossbindTid inner) {
170
+ static std::unordered_set<CrossbindTid> registered;
171
+ if (!registered.insert(opt).second) return;
172
+ _embind_register_optional(opt, inner);
173
+ }
174
+ void crossbind_embind_register_smart_ptr(CrossbindTid a, CrossbindTid b, const char* c, int d, const char* e, CrossbindFn f, const char* g, CrossbindFn h, const char* i, CrossbindFn j, const char* k, CrossbindFn l) {
175
+ _embind_register_smart_ptr(a, b, c, (emscripten::sharing_policy)d, e, f, g, h, i, j, k, l);
176
+ }
177
+ void crossbind_embind_register_enum(CrossbindTid a, const char* b, size_t c, bool d, int e) {
178
+ _embind_register_enum(a, b, c, d, e);
179
+ }
180
+ void crossbind_embind_register_enum_value(CrossbindTid a, const char* b, int c) {
181
+ _embind_register_enum_value(a, b, c);
182
+ }
183
+ void crossbind_embind_register_value_object(CrossbindTid a, const char* b, const char* c, CrossbindFn d, const char* e, CrossbindFn f) {
184
+ _embind_register_value_object(a, b, c, d, e, f);
185
+ }
186
+ void crossbind_embind_register_value_object_field(CrossbindTid a, const char* b, CrossbindTid c, const char* d, CrossbindFn e, void* f, CrossbindTid g, const char* h, CrossbindFn i, void* j) {
187
+ _embind_register_value_object_field(a, b, c, sigForWasm(d), e, f, g, sigForWasm(h), i, j);
188
+ }
189
+ void crossbind_embind_finalize_value_object(CrossbindTid a) {
190
+ _embind_finalize_value_object(a);
191
+ }
192
+
193
+ // emscripten's InitFunc constructor runs the init immediately and registers it for workers.
194
+ // Leaked on purpose: it lives for the program.
195
+ void crossbind_embind_register_bindings(void (*init)()) {
196
+ new emscripten::internal::InitFunc(init);
197
+ }
198
+
199
+ }
200
+
201
+ // ---- live JS value hooks (JsValue / JsFunction) ----
202
+ // EM_JS bodies over embind's own Emval handle table (visible in EM_JS scope, like the Option
203
+ // helpers above). Handles are i32 table indexes on wasm32, so argv reads via HEAPU32.
204
+ EM_JS(void, crossbind_v_ref, (void* h), { __emval_incref(h); });
205
+ EM_JS(void, crossbind_v_unref, (void* h), { __emval_decref(h); });
206
+ EM_JS(void*, crossbind_v_from_f64, (double v), { return Emval.toHandle(v); });
207
+ EM_JS(void*, crossbind_v_from_bool, (int v), { return Emval.toHandle(!!v); });
208
+ EM_JS(void*, crossbind_v_from_str, (uint8_t* w), {
209
+ const len = HEAPU32[w >> 2];
210
+ const s = UTF8ToString(w + 4, len);
211
+ _free(w);
212
+ return Emval.toHandle(s);
213
+ });
214
+ EM_JS(void*, crossbind_v_get_prop, (void* h, uint8_t* w), {
215
+ const len = HEAPU32[w >> 2];
216
+ const k = UTF8ToString(w + 4, len);
217
+ _free(w);
218
+ return Emval.toHandle(Emval.toValue(h)[k]);
219
+ });
220
+ EM_JS(void, crossbind_v_set_prop, (void* h, uint8_t* w, void* v), {
221
+ const len = HEAPU32[w >> 2];
222
+ const k = UTF8ToString(w + 4, len);
223
+ _free(w);
224
+ Emval.toValue(h)[k] = Emval.toValue(v);
225
+ });
226
+ EM_JS(int, crossbind_v_kind, (void* h), {
227
+ const v = Emval.toValue(h);
228
+ if (v === null || v === undefined) return 0;
229
+ const t = typeof v;
230
+ if (t === 'boolean') return 1;
231
+ if (t === 'number') return 2;
232
+ if (t === 'string') return 3;
233
+ if (t === 'function') return 4;
234
+ return 5;
235
+ });
236
+ EM_JS(double, crossbind_v_as_f64, (void* h), { return Number(Emval.toValue(h)); });
237
+ EM_JS(int, crossbind_v_as_bool, (void* h), { return Emval.toValue(h) ? 1 : 0; });
238
+ EM_JS(uint8_t*, crossbind_v_as_str, (void* h), {
239
+ const s = String(Emval.toValue(h));
240
+ const len = lengthBytesUTF8(s);
241
+ const w = _malloc(4 + len);
242
+ HEAPU32[w >> 2] = len;
243
+ stringToUTF8(s, w + 4, len + 1);
244
+ return w;
245
+ });
246
+ EM_JS(void*, crossbind_v_call, (void* f, unsigned argc, void* argv), {
247
+ try {
248
+ const fn = Emval.toValue(f);
249
+ const args = [];
250
+ for (let i = 0; i < argc; i += 1) args.push(Emval.toValue(HEAPU32[(argv >> 2) + i]));
251
+ return Emval.toHandle(fn(...args));
252
+ } catch (e) {
253
+ globalThis.__crossbind_cb_err = String((e && e.message) || e);
254
+ return 0;
255
+ }
256
+ });
257
+ EM_JS(uint8_t*, crossbind_v_cb_err_take, (), {
258
+ const s = globalThis.__crossbind_cb_err;
259
+ if (s === undefined) return 0;
260
+ delete globalThis.__crossbind_cb_err;
261
+ const len = lengthBytesUTF8(s);
262
+ const w = _malloc(4 + len);
263
+ HEAPU32[w >> 2] = len;
264
+ stringToUTF8(s, w + 4, len + 1);
265
+ return w;
266
+ });
267
+
268
+ extern "C" void* crossbind_v_undef() { return (void*)emscripten::internal::_EMVAL_UNDEFINED; }
@@ -0,0 +1,7 @@
1
+ # This file is automatically @generated by Cargo.
2
+ # It is not intended for manual editing.
3
+ version = 4
4
+
5
+ [[package]]
6
+ name = "embind-rs"
7
+ version = "0.1.0"
@@ -0,0 +1,7 @@
1
+ [package]
2
+ name = "embind-rs"
3
+ version = "0.1.0"
4
+ edition = "2021"
5
+
6
+ [features]
7
+ host-stubs = []