summaryrefslogtreecommitdiffstats
path: root/toolkit/components/uniffi-bindgen-gecko-js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /toolkit/components/uniffi-bindgen-gecko-js
parentInitial commit. (diff)
downloadfirefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz
firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/uniffi-bindgen-gecko-js')
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml21
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/askama.toml2
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/components/generated/README.md6
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs1504
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/components/moz.build12
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/config.toml5
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/README.md36
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/README.md1
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustArithmetic.sys.mjs491
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustCustomTypes.sys.mjs464
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustExternalTypes.sys.mjs356
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustFixtureCallbacks.sys.mjs639
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustGeometry.sys.mjs514
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRondpoint.sys.mjs3363
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustSprites.sys.mjs681
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustTodolist.sys.mjs925
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build24
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_arithmetic.js48
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_callbacks.js47
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_custom_types.js13
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_external_types.js16
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_geometry.js21
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_rondpoint.js311
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_sprites.js28
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_todolist.js71
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_type_checking.js123
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.ini9
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/mach_commands.py92
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/ci_list.rs193
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/lib.rs158
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/main.rs9
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs190
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs302
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/render/mod.rs7
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/render/shared.rs39
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp155
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Boolean.sys.mjs22
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterface.sys.mjs24
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterfaceHandler.sys.mjs19
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterfaceRuntime.sys.mjs195
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CustomType.sys.mjs23
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Enum.sys.mjs115
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Error.sys.mjs80
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/ExternalType.sys.mjs7
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float32.sys.mjs18
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float64.sys.mjs18
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Helpers.sys.mjs234
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int16.sys.mjs27
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int32.sys.mjs27
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int64.sys.mjs24
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int8.sys.mjs27
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Map.sys.mjs54
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.sys.mjs68
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Optional.sys.mjs36
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Record.sys.mjs65
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Sequence.sys.mjs43
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/String.sys.mjs32
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/TopLevelFunctions.sys.mjs6
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Types.sys.mjs89
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt16.sys.mjs27
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt32.sys.mjs27
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt64.sys.mjs27
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt8.sys.mjs27
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/macros.sys.mjs62
-rw-r--r--toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/wrapper.sys.mjs15
65 files changed, 12314 insertions, 0 deletions
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml b/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml
new file mode 100644
index 0000000000..b28f455e3b
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "uniffi-bindgen-gecko-js"
+version = "0.1.0"
+edition = "2018"
+license = "MPL-2.0"
+
+[[bin]]
+name = "uniffi-bindgen-gecko-js"
+path = "src/main.rs"
+
+[dependencies]
+anyhow = "1"
+askama = { version = "0.11", default-features = false, features = ["config"] }
+clap = { version = "3.1", default-features = false, features = ["std", "derive", "cargo"] }
+extend = "1.1"
+heck = "0.4"
+uniffi = { workspace = true }
+uniffi_bindgen = "0.23"
+serde = "1"
+toml = "0.5"
+camino = "1.0.8"
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/askama.toml b/toolkit/components/uniffi-bindgen-gecko-js/askama.toml
new file mode 100644
index 0000000000..066e3c468c
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/askama.toml
@@ -0,0 +1,2 @@
+[general]
+dirs = ["src/templates"]
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/README.md b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/README.md
new file mode 100644
index 0000000000..4e4267acd4
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/README.md
@@ -0,0 +1,6 @@
+This directory is where modules generated by UniFFI will be created.
+
+All files in this directory, other than this one, are generated and should
+not be hand-edited.
+
+To update these files, execute `./mach uniffi generate`
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs
new file mode 100644
index 0000000000..b4b14cea52
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs
@@ -0,0 +1,1504 @@
+// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
+// Trust me, you don't want to mess with it!
+
+import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs";
+
+
+
+// Objects intended to be used in the unit tests
+export var UnitTestObjs = {};
+
+// Write/Read data to/from an ArrayBuffer
+class ArrayBufferDataStream {
+ constructor(arrayBuffer) {
+ this.dataView = new DataView(arrayBuffer);
+ this.pos = 0;
+ }
+
+ readUint8() {
+ let rv = this.dataView.getUint8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeUint8(value) {
+ this.dataView.setUint8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readUint16() {
+ let rv = this.dataView.getUint16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeUint16(value) {
+ this.dataView.setUint16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readUint32() {
+ let rv = this.dataView.getUint32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeUint32(value) {
+ this.dataView.setUint32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readUint64() {
+ let rv = this.dataView.getBigUint64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeUint64(value) {
+ this.dataView.setBigUint64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+
+ readInt8() {
+ let rv = this.dataView.getInt8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeInt8(value) {
+ this.dataView.setInt8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readInt16() {
+ let rv = this.dataView.getInt16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeInt16(value) {
+ this.dataView.setInt16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readInt32() {
+ let rv = this.dataView.getInt32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeInt32(value) {
+ this.dataView.setInt32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readInt64() {
+ let rv = this.dataView.getBigInt64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeInt64(value) {
+ this.dataView.setBigInt64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+ readFloat32() {
+ let rv = this.dataView.getFloat32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeFloat32(value) {
+ this.dataView.setFloat32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readFloat64() {
+ let rv = this.dataView.getFloat64(this.pos);
+ this.pos += 8;
+ return rv;
+ }
+
+ writeFloat64(value) {
+ this.dataView.setFloat64(this.pos, value);
+ this.pos += 8;
+ }
+
+
+ writeString(value) {
+ const encoder = new TextEncoder();
+ // Note: in order to efficiently write this data, we first write the
+ // string data, reserving 4 bytes for the size.
+ const dest = new Uint8Array(this.dataView.buffer, this.pos + 4);
+ const encodeResult = encoder.encodeInto(value, dest);
+ if (encodeResult.read != value.length) {
+ throw new UniFFIError(
+ "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?"
+ );
+ }
+ const size = encodeResult.written;
+ // Next, go back and write the size before the string data
+ this.dataView.setUint32(this.pos, size);
+ // Finally, advance our position past both the size and string data
+ this.pos += size + 4;
+ }
+
+ readString() {
+ const decoder = new TextDecoder();
+ const size = this.readUint32();
+ const source = new Uint8Array(this.dataView.buffer, this.pos, size)
+ const value = decoder.decode(source);
+ this.pos += size;
+ return value;
+ }
+
+ // Reads a TabsStore pointer from the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ readPointerTabsStore() {
+ const pointerId = 0; // tabs:TabsStore
+ const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ return res;
+ }
+
+ // Writes a TabsStore pointer into the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ writePointerTabsStore(value) {
+ const pointerId = 0; // tabs:TabsStore
+ UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ }
+
+
+ // Reads a TabsBridgedEngine pointer from the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ readPointerTabsBridgedEngine() {
+ const pointerId = 1; // tabs:TabsBridgedEngine
+ const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ return res;
+ }
+
+ // Writes a TabsBridgedEngine pointer into the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ writePointerTabsBridgedEngine(value) {
+ const pointerId = 1; // tabs:TabsBridgedEngine
+ UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ }
+
+}
+
+function handleRustResult(result, liftCallback, liftErrCallback) {
+ switch (result.code) {
+ case "success":
+ return liftCallback(result.data);
+
+ case "error":
+ throw liftErrCallback(result.data);
+
+ case "internal-error":
+ let message = result.internalErrorMessage;
+ if (message) {
+ throw new UniFFIInternalError(message);
+ } else {
+ throw new UniFFIInternalError("Unknown error");
+ }
+
+ default:
+ throw new UniFFIError(`Unexpected status code: ${result.code}`);
+ }
+}
+
+class UniFFIError {
+ constructor(message) {
+ this.message = message;
+ }
+
+ toString() {
+ return `UniFFIError: ${this.message}`
+ }
+}
+
+class UniFFIInternalError extends UniFFIError {}
+
+// Base class for FFI converters
+class FfiConverter {
+ // throw `UniFFITypeError` if a value to be converted has an invalid type
+ static checkType(value) {
+ if (value === undefined ) {
+ throw new UniFFITypeError(`undefined`);
+ }
+ if (value === null ) {
+ throw new UniFFITypeError(`null`);
+ }
+ }
+}
+
+// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer
+class FfiConverterArrayBuffer extends FfiConverter {
+ static lift(buf) {
+ return this.read(new ArrayBufferDataStream(buf));
+ }
+
+ static lower(value) {
+ const buf = new ArrayBuffer(this.computeSize(value));
+ const dataStream = new ArrayBufferDataStream(buf);
+ this.write(dataStream, value);
+ return buf;
+ }
+}
+
+// Symbols that are used to ensure that Object constructors
+// can only be used with a proper UniFFI pointer
+const uniffiObjectPtr = Symbol("uniffiObjectPtr");
+const constructUniffiObject = Symbol("constructUniffiObject");
+UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr;
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterI64 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isSafeInteger(value)) {
+ throw new UniFFITypeError(`${value} exceeds the safe integer bounds`);
+ }
+ }
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt64()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterString extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (typeof value !== "string") {
+ throw new UniFFITypeError(`${value} is not a string`);
+ }
+ }
+
+ static lift(buf) {
+ const decoder = new TextDecoder();
+ const utf8Arr = new Uint8Array(buf);
+ return decoder.decode(utf8Arr);
+ }
+ static lower(value) {
+ const encoder = new TextEncoder();
+ return encoder.encode(value).buffer;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeString(value);
+ }
+
+ static read(dataStream) {
+ return dataStream.readString();
+ }
+
+ static computeSize(value) {
+ const encoder = new TextEncoder();
+ return 4 + encoder.encode(value).length
+ }
+}
+
+export class TabsBridgedEngine {
+ // Use `init` to instantiate this class.
+ // DO NOT USE THIS CONSTRUCTOR DIRECTLY
+ constructor(opts) {
+ if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
+ throw new UniFFIError("Attempting to construct an object using the JavaScript constructor directly" +
+ "Please use a UDL defined constructor, or the init function for the primary constructor")
+ }
+ if (!opts[constructUniffiObject] instanceof UniFFIPointer) {
+ throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
+ }
+ this[uniffiObjectPtr] = opts[constructUniffiObject];
+ }
+
+ lastSync() {
+ const liftResult = (result) => FfiConverterI64.lift(result);
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 7, // tabs:tabs_dffd_TabsBridgedEngine_last_sync
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ setLastSync(lastSync) {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterI64.checkType(lastSync)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("lastSync");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 8, // tabs:tabs_dffd_TabsBridgedEngine_set_last_sync
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ FfiConverterI64.lower(lastSync),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ syncId() {
+ const liftResult = (result) => FfiConverterOptionalstring.lift(result);
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 9, // tabs:tabs_dffd_TabsBridgedEngine_sync_id
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ resetSyncId() {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 10, // tabs:tabs_dffd_TabsBridgedEngine_reset_sync_id
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ ensureCurrentSyncId(newSyncId) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterString.checkType(newSyncId)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("newSyncId");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 11, // tabs:tabs_dffd_TabsBridgedEngine_ensure_current_sync_id
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ FfiConverterString.lower(newSyncId),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ prepareForSync(clientData) {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterString.checkType(clientData)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("clientData");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 12, // tabs:tabs_dffd_TabsBridgedEngine_prepare_for_sync
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ FfiConverterString.lower(clientData),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ syncStarted() {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 13, // tabs:tabs_dffd_TabsBridgedEngine_sync_started
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ storeIncoming(incomingEnvelopesAsJson) {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterSequencestring.checkType(incomingEnvelopesAsJson)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("incomingEnvelopesAsJson");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 14, // tabs:tabs_dffd_TabsBridgedEngine_store_incoming
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ FfiConverterSequencestring.lower(incomingEnvelopesAsJson),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ apply() {
+ const liftResult = (result) => FfiConverterSequencestring.lift(result);
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 15, // tabs:tabs_dffd_TabsBridgedEngine_apply
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ setUploaded(newTimestamp,uploadedIds) {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterI64.checkType(newTimestamp)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("newTimestamp");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterSequenceTypeTabsGuid.checkType(uploadedIds)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("uploadedIds");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 16, // tabs:tabs_dffd_TabsBridgedEngine_set_uploaded
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ FfiConverterI64.lower(newTimestamp),
+ FfiConverterSequenceTypeTabsGuid.lower(uploadedIds),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ syncFinished() {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 17, // tabs:tabs_dffd_TabsBridgedEngine_sync_finished
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ reset() {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 18, // tabs:tabs_dffd_TabsBridgedEngine_reset
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ wipe() {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 19, // tabs:tabs_dffd_TabsBridgedEngine_wipe
+ FfiConverterTypeTabsBridgedEngine.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeTabsBridgedEngine extends FfiConverter {
+ static lift(value) {
+ const opts = {};
+ opts[constructUniffiObject] = value;
+ return new TabsBridgedEngine(opts);
+ }
+
+ static lower(value) {
+ return value[uniffiObjectPtr];
+ }
+
+ static read(dataStream) {
+ return this.lift(dataStream.readPointerTabsBridgedEngine());
+ }
+
+ static write(dataStream, value) {
+ dataStream.writePointerTabsBridgedEngine(value[uniffiObjectPtr]);
+ }
+
+ static computeSize(value) {
+ return 8;
+ }
+}
+
+export class TabsStore {
+ // Use `init` to instantiate this class.
+ // DO NOT USE THIS CONSTRUCTOR DIRECTLY
+ constructor(opts) {
+ if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
+ throw new UniFFIError("Attempting to construct an object using the JavaScript constructor directly" +
+ "Please use a UDL defined constructor, or the init function for the primary constructor")
+ }
+ if (!opts[constructUniffiObject] instanceof UniFFIPointer) {
+ throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
+ }
+ this[uniffiObjectPtr] = opts[constructUniffiObject];
+ }
+ /**
+ * An async constructor for TabsStore.
+ *
+ * @returns {Promise<TabsStore>}: A promise that resolves
+ * to a newly constructed TabsStore
+ */
+ static init(path) {
+ const liftResult = (result) => FfiConverterTypeTabsStore.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterString.checkType(path)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("path");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 0, // tabs:tabs_dffd_TabsStore_new
+ FfiConverterString.lower(path),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }}
+
+ getAll() {
+ const liftResult = (result) => FfiConverterSequenceTypeClientRemoteTabs.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 1, // tabs:tabs_dffd_TabsStore_get_all
+ FfiConverterTypeTabsStore.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ setLocalTabs(remoteTabs) {
+ const liftResult = (result) => undefined;
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterSequenceTypeRemoteTabRecord.checkType(remoteTabs)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("remoteTabs");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 2, // tabs:tabs_dffd_TabsStore_set_local_tabs
+ FfiConverterTypeTabsStore.lower(this),
+ FfiConverterSequenceTypeRemoteTabRecord.lower(remoteTabs),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ registerWithSyncManager() {
+ const liftResult = (result) => undefined;
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 3, // tabs:tabs_dffd_TabsStore_register_with_sync_manager
+ FfiConverterTypeTabsStore.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ reset() {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 4, // tabs:tabs_dffd_TabsStore_reset
+ FfiConverterTypeTabsStore.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sync(keyId,accessToken,syncKey,tokenserverUrl,localId) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = (data) => FfiConverterTypeTabsApiError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterString.checkType(keyId)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("keyId");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterString.checkType(accessToken)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("accessToken");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterString.checkType(syncKey)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("syncKey");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterString.checkType(tokenserverUrl)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("tokenserverUrl");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterString.checkType(localId)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("localId");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 5, // tabs:tabs_dffd_TabsStore_sync
+ FfiConverterTypeTabsStore.lower(this),
+ FfiConverterString.lower(keyId),
+ FfiConverterString.lower(accessToken),
+ FfiConverterString.lower(syncKey),
+ FfiConverterString.lower(tokenserverUrl),
+ FfiConverterString.lower(localId),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ bridgedEngine() {
+ const liftResult = (result) => FfiConverterTypeTabsBridgedEngine.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 6, // tabs:tabs_dffd_TabsStore_bridged_engine
+ FfiConverterTypeTabsStore.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeTabsStore extends FfiConverter {
+ static lift(value) {
+ const opts = {};
+ opts[constructUniffiObject] = value;
+ return new TabsStore(opts);
+ }
+
+ static lower(value) {
+ return value[uniffiObjectPtr];
+ }
+
+ static read(dataStream) {
+ return this.lift(dataStream.readPointerTabsStore());
+ }
+
+ static write(dataStream, value) {
+ dataStream.writePointerTabsStore(value[uniffiObjectPtr]);
+ }
+
+ static computeSize(value) {
+ return 8;
+ }
+}
+
+export class ClientRemoteTabs {
+ constructor(clientId,clientName,deviceType,lastModified,remoteTabs) {
+ try {
+ FfiConverterString.checkType(clientId)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("clientId");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterString.checkType(clientName)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("clientName");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypeTabsDeviceType.checkType(deviceType)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("deviceType");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI64.checkType(lastModified)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("lastModified");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterSequenceTypeRemoteTabRecord.checkType(remoteTabs)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("remoteTabs");
+ }
+ throw e;
+ }
+ this.clientId = clientId;
+ this.clientName = clientName;
+ this.deviceType = deviceType;
+ this.lastModified = lastModified;
+ this.remoteTabs = remoteTabs;
+ }
+ equals(other) {
+ return (
+ this.clientId == other.clientId &&
+ this.clientName == other.clientName &&
+ this.deviceType == other.deviceType &&
+ this.lastModified == other.lastModified &&
+ this.remoteTabs == other.remoteTabs
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeClientRemoteTabs extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new ClientRemoteTabs(
+ FfiConverterString.read(dataStream),
+ FfiConverterString.read(dataStream),
+ FfiConverterTypeTabsDeviceType.read(dataStream),
+ FfiConverterI64.read(dataStream),
+ FfiConverterSequenceTypeRemoteTabRecord.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterString.write(dataStream, value.clientId);
+ FfiConverterString.write(dataStream, value.clientName);
+ FfiConverterTypeTabsDeviceType.write(dataStream, value.deviceType);
+ FfiConverterI64.write(dataStream, value.lastModified);
+ FfiConverterSequenceTypeRemoteTabRecord.write(dataStream, value.remoteTabs);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterString.computeSize(value.clientId);
+ totalSize += FfiConverterString.computeSize(value.clientName);
+ totalSize += FfiConverterTypeTabsDeviceType.computeSize(value.deviceType);
+ totalSize += FfiConverterI64.computeSize(value.lastModified);
+ totalSize += FfiConverterSequenceTypeRemoteTabRecord.computeSize(value.remoteTabs);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterString.checkType(value.clientId);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".clientId");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterString.checkType(value.clientName);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".clientName");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypeTabsDeviceType.checkType(value.deviceType);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".deviceType");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI64.checkType(value.lastModified);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".lastModified");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterSequenceTypeRemoteTabRecord.checkType(value.remoteTabs);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".remoteTabs");
+ }
+ throw e;
+ }
+ }
+}
+
+export class RemoteTabRecord {
+ constructor(title,urlHistory,icon,lastUsed) {
+ try {
+ FfiConverterString.checkType(title)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("title");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterSequencestring.checkType(urlHistory)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("urlHistory");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterOptionalstring.checkType(icon)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("icon");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI64.checkType(lastUsed)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("lastUsed");
+ }
+ throw e;
+ }
+ this.title = title;
+ this.urlHistory = urlHistory;
+ this.icon = icon;
+ this.lastUsed = lastUsed;
+ }
+ equals(other) {
+ return (
+ this.title == other.title &&
+ this.urlHistory == other.urlHistory &&
+ this.icon == other.icon &&
+ this.lastUsed == other.lastUsed
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeRemoteTabRecord extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new RemoteTabRecord(
+ FfiConverterString.read(dataStream),
+ FfiConverterSequencestring.read(dataStream),
+ FfiConverterOptionalstring.read(dataStream),
+ FfiConverterI64.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterString.write(dataStream, value.title);
+ FfiConverterSequencestring.write(dataStream, value.urlHistory);
+ FfiConverterOptionalstring.write(dataStream, value.icon);
+ FfiConverterI64.write(dataStream, value.lastUsed);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterString.computeSize(value.title);
+ totalSize += FfiConverterSequencestring.computeSize(value.urlHistory);
+ totalSize += FfiConverterOptionalstring.computeSize(value.icon);
+ totalSize += FfiConverterI64.computeSize(value.lastUsed);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterString.checkType(value.title);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".title");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterSequencestring.checkType(value.urlHistory);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".urlHistory");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterOptionalstring.checkType(value.icon);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".icon");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI64.checkType(value.lastUsed);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".lastUsed");
+ }
+ throw e;
+ }
+ }
+}
+
+export const TabsDeviceType = {
+ DESKTOP: 1,
+ MOBILE: 2,
+ TABLET: 3,
+ VR: 4,
+ TV: 5,
+ UNKNOWN: 6,
+};
+
+Object.freeze(TabsDeviceType);
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeTabsDeviceType extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ switch (dataStream.readInt32()) {
+ case 1:
+ return TabsDeviceType.DESKTOP
+ case 2:
+ return TabsDeviceType.MOBILE
+ case 3:
+ return TabsDeviceType.TABLET
+ case 4:
+ return TabsDeviceType.VR
+ case 5:
+ return TabsDeviceType.TV
+ case 6:
+ return TabsDeviceType.UNKNOWN
+ default:
+ return new Error("Unknown TabsDeviceType variant");
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === TabsDeviceType.DESKTOP) {
+ dataStream.writeInt32(1);
+ return;
+ }
+ if (value === TabsDeviceType.MOBILE) {
+ dataStream.writeInt32(2);
+ return;
+ }
+ if (value === TabsDeviceType.TABLET) {
+ dataStream.writeInt32(3);
+ return;
+ }
+ if (value === TabsDeviceType.VR) {
+ dataStream.writeInt32(4);
+ return;
+ }
+ if (value === TabsDeviceType.TV) {
+ dataStream.writeInt32(5);
+ return;
+ }
+ if (value === TabsDeviceType.UNKNOWN) {
+ dataStream.writeInt32(6);
+ return;
+ }
+ return new Error("Unknown TabsDeviceType variant");
+ }
+
+ static computeSize(value) {
+ return 4;
+ }
+
+ static checkType(value) {
+ if (!Number.isInteger(value) || value < 1 || value > 6) {
+ throw new UniFFITypeError(`${value} is not a valid value for TabsDeviceType`);
+ }
+ }
+}
+
+
+
+export class TabsApiError extends Error {}
+
+
+export class SyncError extends TabsApiError {
+
+ constructor(
+ reason,
+ ...params
+ ) {
+ super(...params);
+ this.reason = reason;
+ }
+ toString() {
+ return `SyncError: ${super.toString()}`
+ }
+}
+
+export class SqlError extends TabsApiError {
+
+ constructor(
+ reason,
+ ...params
+ ) {
+ super(...params);
+ this.reason = reason;
+ }
+ toString() {
+ return `SqlError: ${super.toString()}`
+ }
+}
+
+export class UnexpectedTabsError extends TabsApiError {
+
+ constructor(
+ reason,
+ ...params
+ ) {
+ super(...params);
+ this.reason = reason;
+ }
+ toString() {
+ return `UnexpectedTabsError: ${super.toString()}`
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeTabsApiError extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ switch (dataStream.readInt32()) {
+ case 1:
+ return new SyncError(
+ FfiConverterString.read(dataStream)
+ );
+ case 2:
+ return new SqlError(
+ FfiConverterString.read(dataStream)
+ );
+ case 3:
+ return new UnexpectedTabsError(
+ FfiConverterString.read(dataStream)
+ );
+ default:
+ throw new Error("Unknown TabsApiError variant");
+ }
+ }
+ static computeSize(value) {
+ // Size of the Int indicating the variant
+ let totalSize = 4;
+ if (value instanceof SyncError) {
+ totalSize += FfiConverterString.computeSize(value.reason);
+ return totalSize;
+ }
+ if (value instanceof SqlError) {
+ totalSize += FfiConverterString.computeSize(value.reason);
+ return totalSize;
+ }
+ if (value instanceof UnexpectedTabsError) {
+ totalSize += FfiConverterString.computeSize(value.reason);
+ return totalSize;
+ }
+ throw new Error("Unknown TabsApiError variant");
+ }
+ static write(dataStream, value) {
+ if (value instanceof SyncError) {
+ dataStream.writeInt32(1);
+ FfiConverterString.write(dataStream, value.reason);
+ return;
+ }
+ if (value instanceof SqlError) {
+ dataStream.writeInt32(2);
+ FfiConverterString.write(dataStream, value.reason);
+ return;
+ }
+ if (value instanceof UnexpectedTabsError) {
+ dataStream.writeInt32(3);
+ FfiConverterString.write(dataStream, value.reason);
+ return;
+ }
+ throw new Error("Unknown TabsApiError variant");
+ }
+
+ static errorClass = TabsApiError;
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterOptionalstring extends FfiConverterArrayBuffer {
+ static checkType(value) {
+ if (value !== undefined && value !== null) {
+ FfiConverterString.checkType(value)
+ }
+ }
+
+ static read(dataStream) {
+ const code = dataStream.readUint8(0);
+ switch (code) {
+ case 0:
+ return null
+ case 1:
+ return FfiConverterString.read(dataStream)
+ default:
+ throw UniFFIError(`Unexpected code: ${code}`);
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === null || value === undefined) {
+ dataStream.writeUint8(0);
+ return;
+ }
+ dataStream.writeUint8(1);
+ FfiConverterString.write(dataStream, value)
+ }
+
+ static computeSize(value) {
+ if (value === null || value === undefined) {
+ return 1;
+ }
+ return 1 + FfiConverterString.computeSize(value)
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterSequencestring extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const arr = [];
+ for (let i = 0; i < len; i++) {
+ arr.push(FfiConverterString.read(dataStream));
+ }
+ return arr;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(value.length);
+ value.forEach((innerValue) => {
+ FfiConverterString.write(dataStream, innerValue);
+ })
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const innerValue of value) {
+ size += FfiConverterString.computeSize(innerValue);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ if (!Array.isArray(value)) {
+ throw new UniFFITypeError(`${value} is not an array`);
+ }
+ value.forEach((innerValue, idx) => {
+ try {
+ FfiConverterString.checkType(innerValue);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${idx}]`);
+ }
+ throw e;
+ }
+ })
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterSequenceTypeClientRemoteTabs extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const arr = [];
+ for (let i = 0; i < len; i++) {
+ arr.push(FfiConverterTypeClientRemoteTabs.read(dataStream));
+ }
+ return arr;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(value.length);
+ value.forEach((innerValue) => {
+ FfiConverterTypeClientRemoteTabs.write(dataStream, innerValue);
+ })
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const innerValue of value) {
+ size += FfiConverterTypeClientRemoteTabs.computeSize(innerValue);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ if (!Array.isArray(value)) {
+ throw new UniFFITypeError(`${value} is not an array`);
+ }
+ value.forEach((innerValue, idx) => {
+ try {
+ FfiConverterTypeClientRemoteTabs.checkType(innerValue);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${idx}]`);
+ }
+ throw e;
+ }
+ })
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterSequenceTypeRemoteTabRecord extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const arr = [];
+ for (let i = 0; i < len; i++) {
+ arr.push(FfiConverterTypeRemoteTabRecord.read(dataStream));
+ }
+ return arr;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(value.length);
+ value.forEach((innerValue) => {
+ FfiConverterTypeRemoteTabRecord.write(dataStream, innerValue);
+ })
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const innerValue of value) {
+ size += FfiConverterTypeRemoteTabRecord.computeSize(innerValue);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ if (!Array.isArray(value)) {
+ throw new UniFFITypeError(`${value} is not an array`);
+ }
+ value.forEach((innerValue, idx) => {
+ try {
+ FfiConverterTypeRemoteTabRecord.checkType(innerValue);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${idx}]`);
+ }
+ throw e;
+ }
+ })
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterSequenceTypeTabsGuid extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const arr = [];
+ for (let i = 0; i < len; i++) {
+ arr.push(FfiConverterTypeTabsGuid.read(dataStream));
+ }
+ return arr;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(value.length);
+ value.forEach((innerValue) => {
+ FfiConverterTypeTabsGuid.write(dataStream, innerValue);
+ })
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const innerValue of value) {
+ size += FfiConverterTypeTabsGuid.computeSize(innerValue);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ if (!Array.isArray(value)) {
+ throw new UniFFITypeError(`${value} is not an array`);
+ }
+ value.forEach((innerValue, idx) => {
+ try {
+ FfiConverterTypeTabsGuid.checkType(innerValue);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${idx}]`);
+ }
+ throw e;
+ }
+ })
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeTabsGuid extends FfiConverter {
+ static lift(buf) {
+ return FfiConverterString.lift(buf);
+ }
+
+ static lower(buf) {
+ return FfiConverterString.lower(buf);
+ }
+
+ static write(dataStream, value) {
+ FfiConverterString.write(dataStream, value);
+ }
+
+ static read(buf) {
+ return FfiConverterString.read(buf);
+ }
+
+ static computeSize(value) {
+ return FfiConverterString.computeSize(value);
+ }
+}
+// TODO: We should also allow JS to customize the type eventually.
+
+
+
+
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/moz.build b/toolkit/components/uniffi-bindgen-gecko-js/components/moz.build
new file mode 100644
index 0000000000..0aca753d89
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/components/moz.build
@@ -0,0 +1,12 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXTRA_JS_MODULES += [
+ "generated/RustTabs.sys.mjs",
+]
+
+with Files("**"):
+ BUG_COMPONENT = ("Toolkit", "UniFFI Bindings")
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/config.toml b/toolkit/components/uniffi-bindgen-gecko-js/config.toml
new file mode 100644
index 0000000000..da1cd21c25
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/config.toml
@@ -0,0 +1,5 @@
+[fixture_callbacks.receiver_thread]
+default = "worker"
+main = [
+ "log_even_numbers_main_thread",
+]
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/README.md b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/README.md
new file mode 100644
index 0000000000..632ba88e00
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/README.md
@@ -0,0 +1,36 @@
+This directory contains generated code for the UniFFI examples/fixtures and JS
+unit tests for it.
+
+This is only built if the `--enable-uniffi-fixtures` flag is present in
+`mozconfig`. There's no benefit to including this in a release build.
+
+To add additional examples/fixtures:
+ - For most of these steps, find the code for existing fixtures and use it as a template for the new code.
+ - Edit `toolkit/components/uniffi-bindgen-gecko-js/mach_commands.py`
+ - Add an entry to `FIXTURE_UDL_FILES`
+ - Edit `toolkit/library/rust/shared/Cargo.toml`
+ - Add an optional dependency for the fixture.
+ - Add the feature to the list of features enabled by `uniffi_fixtures`.
+ - Edit `toolkit/library/rust/shared/lib.rs`:
+ - Add an `extern crate [name]` to the `uniffi_fixtures` mod
+ - Note: [name] is the name from the `[lib]` section in the Cargo.toml
+ for the example/fixture crate. This does not always match the package
+ name for the crate.
+ - Add `[name]::reexport_uniffi_scaffolding` to the `uniffi_fixtures` mod
+ - Edit `toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build` and add the fixture name to the `components`
+ list.
+ - Add a test module to the `toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/` directory and an entry for it
+ in `toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell.ini`
+ - Run `mach vendor rust` to vendor in the Rust code.
+ - Run `mach uniffi generate` to generate the scaffolding code.
+ - Check in any new files
+
+To run the tests:
+ - Make sure you have a `mozconfig` file containing the line `ac_add_options --enable-uniffi-fixtures`
+ - Run `mach uniffi generate` if:
+ - You've added or updated a fixture
+ - You've made changes to `uniffi-bindgen-gecko-js`
+ - Run `mach build`
+ - Run `mach xpcshell-test toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/`
+ - You can also use a path to specific test file
+ - For subsequent runs, if you only modify the test files, then you can re-run this step directly
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/README.md b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/README.md
new file mode 100644
index 0000000000..91372fd31c
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/README.md
@@ -0,0 +1 @@
+This directory is where files generated by Uniffi will be created.
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustArithmetic.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustArithmetic.sys.mjs
new file mode 100644
index 0000000000..ca50baec4a
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustArithmetic.sys.mjs
@@ -0,0 +1,491 @@
+// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
+// Trust me, you don't want to mess with it!
+
+import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs";
+
+
+
+// Objects intended to be used in the unit tests
+export var UnitTestObjs = {};
+
+// Write/Read data to/from an ArrayBuffer
+class ArrayBufferDataStream {
+ constructor(arrayBuffer) {
+ this.dataView = new DataView(arrayBuffer);
+ this.pos = 0;
+ }
+
+ readUint8() {
+ let rv = this.dataView.getUint8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeUint8(value) {
+ this.dataView.setUint8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readUint16() {
+ let rv = this.dataView.getUint16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeUint16(value) {
+ this.dataView.setUint16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readUint32() {
+ let rv = this.dataView.getUint32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeUint32(value) {
+ this.dataView.setUint32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readUint64() {
+ let rv = this.dataView.getBigUint64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeUint64(value) {
+ this.dataView.setBigUint64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+
+ readInt8() {
+ let rv = this.dataView.getInt8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeInt8(value) {
+ this.dataView.setInt8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readInt16() {
+ let rv = this.dataView.getInt16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeInt16(value) {
+ this.dataView.setInt16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readInt32() {
+ let rv = this.dataView.getInt32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeInt32(value) {
+ this.dataView.setInt32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readInt64() {
+ let rv = this.dataView.getBigInt64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeInt64(value) {
+ this.dataView.setBigInt64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+ readFloat32() {
+ let rv = this.dataView.getFloat32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeFloat32(value) {
+ this.dataView.setFloat32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readFloat64() {
+ let rv = this.dataView.getFloat64(this.pos);
+ this.pos += 8;
+ return rv;
+ }
+
+ writeFloat64(value) {
+ this.dataView.setFloat64(this.pos, value);
+ this.pos += 8;
+ }
+
+
+ writeString(value) {
+ const encoder = new TextEncoder();
+ // Note: in order to efficiently write this data, we first write the
+ // string data, reserving 4 bytes for the size.
+ const dest = new Uint8Array(this.dataView.buffer, this.pos + 4);
+ const encodeResult = encoder.encodeInto(value, dest);
+ if (encodeResult.read != value.length) {
+ throw new UniFFIError(
+ "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?"
+ );
+ }
+ const size = encodeResult.written;
+ // Next, go back and write the size before the string data
+ this.dataView.setUint32(this.pos, size);
+ // Finally, advance our position past both the size and string data
+ this.pos += size + 4;
+ }
+
+ readString() {
+ const decoder = new TextDecoder();
+ const size = this.readUint32();
+ const source = new Uint8Array(this.dataView.buffer, this.pos, size)
+ const value = decoder.decode(source);
+ this.pos += size;
+ return value;
+ }
+}
+
+function handleRustResult(result, liftCallback, liftErrCallback) {
+ switch (result.code) {
+ case "success":
+ return liftCallback(result.data);
+
+ case "error":
+ throw liftErrCallback(result.data);
+
+ case "internal-error":
+ let message = result.internalErrorMessage;
+ if (message) {
+ throw new UniFFIInternalError(message);
+ } else {
+ throw new UniFFIInternalError("Unknown error");
+ }
+
+ default:
+ throw new UniFFIError(`Unexpected status code: ${result.code}`);
+ }
+}
+
+class UniFFIError {
+ constructor(message) {
+ this.message = message;
+ }
+
+ toString() {
+ return `UniFFIError: ${this.message}`
+ }
+}
+
+class UniFFIInternalError extends UniFFIError {}
+
+// Base class for FFI converters
+class FfiConverter {
+ // throw `UniFFITypeError` if a value to be converted has an invalid type
+ static checkType(value) {
+ if (value === undefined ) {
+ throw new UniFFITypeError(`undefined`);
+ }
+ if (value === null ) {
+ throw new UniFFITypeError(`null`);
+ }
+ }
+}
+
+// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer
+class FfiConverterArrayBuffer extends FfiConverter {
+ static lift(buf) {
+ return this.read(new ArrayBufferDataStream(buf));
+ }
+
+ static lower(value) {
+ const buf = new ArrayBuffer(this.computeSize(value));
+ const dataStream = new ArrayBufferDataStream(buf);
+ this.write(dataStream, value);
+ return buf;
+ }
+}
+
+// Symbols that are used to ensure that Object constructors
+// can only be used with a proper UniFFI pointer
+const uniffiObjectPtr = Symbol("uniffiObjectPtr");
+const constructUniffiObject = Symbol("constructUniffiObject");
+UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr;
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterU64 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isSafeInteger(value)) {
+ throw new UniFFITypeError(`${value} exceeds the safe integer bounds`);
+ }
+ if (value < 0) {
+ throw new UniFFITypeError(`${value} exceeds the U64 bounds`);
+ }
+ }
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readUint64()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterBool extends FfiConverter {
+ static computeSize() {
+ return 1;
+ }
+ static lift(value) {
+ return value == 1;
+ }
+ static lower(value) {
+ if (value) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint8(this.lower(value))
+ }
+ static read(dataStream) {
+ return this.lift(dataStream.readUint8())
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterString extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (typeof value !== "string") {
+ throw new UniFFITypeError(`${value} is not a string`);
+ }
+ }
+
+ static lift(buf) {
+ const decoder = new TextDecoder();
+ const utf8Arr = new Uint8Array(buf);
+ return decoder.decode(utf8Arr);
+ }
+ static lower(value) {
+ const encoder = new TextEncoder();
+ return encoder.encode(value).buffer;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeString(value);
+ }
+
+ static read(dataStream) {
+ return dataStream.readString();
+ }
+
+ static computeSize(value) {
+ const encoder = new TextEncoder();
+ return 4 + encoder.encode(value).length
+ }
+}
+
+
+
+export class ArithmeticError extends Error {}
+
+
+export class IntegerOverflow extends ArithmeticError {
+
+ constructor(message, ...params) {
+ super(...params);
+ this.message = message;
+ }
+ toString() {
+ return `IntegerOverflow: ${super.toString()}`
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeArithmeticError extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ switch (dataStream.readInt32()) {
+ case 1:
+ return new IntegerOverflow(FfiConverterString.read(dataStream));
+ default:
+ throw new Error("Unknown ArithmeticError variant");
+ }
+ }
+ static computeSize(value) {
+ // Size of the Int indicating the variant
+ let totalSize = 4;
+ if (value instanceof IntegerOverflow) {
+ return totalSize;
+ }
+ throw new Error("Unknown ArithmeticError variant");
+ }
+ static write(dataStream, value) {
+ if (value instanceof IntegerOverflow) {
+ dataStream.writeInt32(1);
+ return;
+ }
+ throw new Error("Unknown ArithmeticError variant");
+ }
+
+ static errorClass = ArithmeticError;
+}
+
+
+
+
+
+export function add(a,b) {
+
+ const liftResult = (result) => FfiConverterU64.lift(result);
+ const liftError = (data) => FfiConverterTypeArithmeticError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterU64.checkType(a)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("a");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU64.checkType(b)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("b");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 22, // arithmetic:arithmetic_fd12_add
+ FfiConverterU64.lower(a),
+ FfiConverterU64.lower(b),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function sub(a,b) {
+
+ const liftResult = (result) => FfiConverterU64.lift(result);
+ const liftError = (data) => FfiConverterTypeArithmeticError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterU64.checkType(a)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("a");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU64.checkType(b)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("b");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 23, // arithmetic:arithmetic_fd12_sub
+ FfiConverterU64.lower(a),
+ FfiConverterU64.lower(b),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function div(dividend,divisor) {
+
+ const liftResult = (result) => FfiConverterU64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU64.checkType(dividend)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("dividend");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU64.checkType(divisor)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("divisor");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 24, // arithmetic:arithmetic_fd12_div
+ FfiConverterU64.lower(dividend),
+ FfiConverterU64.lower(divisor),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function equal(a,b) {
+
+ const liftResult = (result) => FfiConverterBool.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU64.checkType(a)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("a");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU64.checkType(b)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("b");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 25, // arithmetic:arithmetic_fd12_equal
+ FfiConverterU64.lower(a),
+ FfiConverterU64.lower(b),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustCustomTypes.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustCustomTypes.sys.mjs
new file mode 100644
index 0000000000..c43ccbf490
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustCustomTypes.sys.mjs
@@ -0,0 +1,464 @@
+// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
+// Trust me, you don't want to mess with it!
+
+import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs";
+
+
+
+// Objects intended to be used in the unit tests
+export var UnitTestObjs = {};
+
+// Write/Read data to/from an ArrayBuffer
+class ArrayBufferDataStream {
+ constructor(arrayBuffer) {
+ this.dataView = new DataView(arrayBuffer);
+ this.pos = 0;
+ }
+
+ readUint8() {
+ let rv = this.dataView.getUint8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeUint8(value) {
+ this.dataView.setUint8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readUint16() {
+ let rv = this.dataView.getUint16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeUint16(value) {
+ this.dataView.setUint16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readUint32() {
+ let rv = this.dataView.getUint32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeUint32(value) {
+ this.dataView.setUint32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readUint64() {
+ let rv = this.dataView.getBigUint64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeUint64(value) {
+ this.dataView.setBigUint64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+
+ readInt8() {
+ let rv = this.dataView.getInt8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeInt8(value) {
+ this.dataView.setInt8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readInt16() {
+ let rv = this.dataView.getInt16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeInt16(value) {
+ this.dataView.setInt16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readInt32() {
+ let rv = this.dataView.getInt32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeInt32(value) {
+ this.dataView.setInt32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readInt64() {
+ let rv = this.dataView.getBigInt64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeInt64(value) {
+ this.dataView.setBigInt64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+ readFloat32() {
+ let rv = this.dataView.getFloat32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeFloat32(value) {
+ this.dataView.setFloat32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readFloat64() {
+ let rv = this.dataView.getFloat64(this.pos);
+ this.pos += 8;
+ return rv;
+ }
+
+ writeFloat64(value) {
+ this.dataView.setFloat64(this.pos, value);
+ this.pos += 8;
+ }
+
+
+ writeString(value) {
+ const encoder = new TextEncoder();
+ // Note: in order to efficiently write this data, we first write the
+ // string data, reserving 4 bytes for the size.
+ const dest = new Uint8Array(this.dataView.buffer, this.pos + 4);
+ const encodeResult = encoder.encodeInto(value, dest);
+ if (encodeResult.read != value.length) {
+ throw new UniFFIError(
+ "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?"
+ );
+ }
+ const size = encodeResult.written;
+ // Next, go back and write the size before the string data
+ this.dataView.setUint32(this.pos, size);
+ // Finally, advance our position past both the size and string data
+ this.pos += size + 4;
+ }
+
+ readString() {
+ const decoder = new TextDecoder();
+ const size = this.readUint32();
+ const source = new Uint8Array(this.dataView.buffer, this.pos, size)
+ const value = decoder.decode(source);
+ this.pos += size;
+ return value;
+ }
+}
+
+function handleRustResult(result, liftCallback, liftErrCallback) {
+ switch (result.code) {
+ case "success":
+ return liftCallback(result.data);
+
+ case "error":
+ throw liftErrCallback(result.data);
+
+ case "internal-error":
+ let message = result.internalErrorMessage;
+ if (message) {
+ throw new UniFFIInternalError(message);
+ } else {
+ throw new UniFFIInternalError("Unknown error");
+ }
+
+ default:
+ throw new UniFFIError(`Unexpected status code: ${result.code}`);
+ }
+}
+
+class UniFFIError {
+ constructor(message) {
+ this.message = message;
+ }
+
+ toString() {
+ return `UniFFIError: ${this.message}`
+ }
+}
+
+class UniFFIInternalError extends UniFFIError {}
+
+// Base class for FFI converters
+class FfiConverter {
+ // throw `UniFFITypeError` if a value to be converted has an invalid type
+ static checkType(value) {
+ if (value === undefined ) {
+ throw new UniFFITypeError(`undefined`);
+ }
+ if (value === null ) {
+ throw new UniFFITypeError(`null`);
+ }
+ }
+}
+
+// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer
+class FfiConverterArrayBuffer extends FfiConverter {
+ static lift(buf) {
+ return this.read(new ArrayBufferDataStream(buf));
+ }
+
+ static lower(value) {
+ const buf = new ArrayBuffer(this.computeSize(value));
+ const dataStream = new ArrayBufferDataStream(buf);
+ this.write(dataStream, value);
+ return buf;
+ }
+}
+
+// Symbols that are used to ensure that Object constructors
+// can only be used with a proper UniFFI pointer
+const uniffiObjectPtr = Symbol("uniffiObjectPtr");
+const constructUniffiObject = Symbol("constructUniffiObject");
+UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr;
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterI64 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isSafeInteger(value)) {
+ throw new UniFFITypeError(`${value} exceeds the safe integer bounds`);
+ }
+ }
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt64()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterString extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (typeof value !== "string") {
+ throw new UniFFITypeError(`${value} is not a string`);
+ }
+ }
+
+ static lift(buf) {
+ const decoder = new TextDecoder();
+ const utf8Arr = new Uint8Array(buf);
+ return decoder.decode(utf8Arr);
+ }
+ static lower(value) {
+ const encoder = new TextEncoder();
+ return encoder.encode(value).buffer;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeString(value);
+ }
+
+ static read(dataStream) {
+ return dataStream.readString();
+ }
+
+ static computeSize(value) {
+ const encoder = new TextEncoder();
+ return 4 + encoder.encode(value).length
+ }
+}
+
+export class CustomTypesDemo {
+ constructor(url,handle) {
+ try {
+ FfiConverterTypeUrl.checkType(url)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("url");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypeHandle.checkType(handle)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("handle");
+ }
+ throw e;
+ }
+ this.url = url;
+ this.handle = handle;
+ }
+ equals(other) {
+ return (
+ this.url == other.url &&
+ this.handle == other.handle
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeCustomTypesDemo extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new CustomTypesDemo(
+ FfiConverterTypeUrl.read(dataStream),
+ FfiConverterTypeHandle.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterTypeUrl.write(dataStream, value.url);
+ FfiConverterTypeHandle.write(dataStream, value.handle);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterTypeUrl.computeSize(value.url);
+ totalSize += FfiConverterTypeHandle.computeSize(value.handle);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterTypeUrl.checkType(value.url);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".url");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypeHandle.checkType(value.handle);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".handle");
+ }
+ throw e;
+ }
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterOptionalTypeCustomTypesDemo extends FfiConverterArrayBuffer {
+ static checkType(value) {
+ if (value !== undefined && value !== null) {
+ FfiConverterTypeCustomTypesDemo.checkType(value)
+ }
+ }
+
+ static read(dataStream) {
+ const code = dataStream.readUint8(0);
+ switch (code) {
+ case 0:
+ return null
+ case 1:
+ return FfiConverterTypeCustomTypesDemo.read(dataStream)
+ default:
+ throw UniFFIError(`Unexpected code: ${code}`);
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === null || value === undefined) {
+ dataStream.writeUint8(0);
+ return;
+ }
+ dataStream.writeUint8(1);
+ FfiConverterTypeCustomTypesDemo.write(dataStream, value)
+ }
+
+ static computeSize(value) {
+ if (value === null || value === undefined) {
+ return 1;
+ }
+ return 1 + FfiConverterTypeCustomTypesDemo.computeSize(value)
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeHandle extends FfiConverter {
+ static lift(buf) {
+ return FfiConverterI64.lift(buf);
+ }
+
+ static lower(buf) {
+ return FfiConverterI64.lower(buf);
+ }
+
+ static write(dataStream, value) {
+ FfiConverterI64.write(dataStream, value);
+ }
+
+ static read(buf) {
+ return FfiConverterI64.read(buf);
+ }
+
+ static computeSize(value) {
+ return FfiConverterI64.computeSize(value);
+ }
+}
+// TODO: We should also allow JS to customize the type eventually.
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeUrl extends FfiConverter {
+ static lift(buf) {
+ return FfiConverterString.lift(buf);
+ }
+
+ static lower(buf) {
+ return FfiConverterString.lower(buf);
+ }
+
+ static write(dataStream, value) {
+ FfiConverterString.write(dataStream, value);
+ }
+
+ static read(buf) {
+ return FfiConverterString.read(buf);
+ }
+
+ static computeSize(value) {
+ return FfiConverterString.computeSize(value);
+ }
+}
+// TODO: We should also allow JS to customize the type eventually.
+
+
+
+
+
+export function getCustomTypesDemo(demo) {
+
+ const liftResult = (result) => FfiConverterTypeCustomTypesDemo.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterOptionalTypeCustomTypesDemo.checkType(demo)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("demo");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 109, // custom_types:custom_types_881f_get_custom_types_demo
+ FfiConverterOptionalTypeCustomTypesDemo.lower(demo),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustExternalTypes.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustExternalTypes.sys.mjs
new file mode 100644
index 0000000000..90889d1cd0
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustExternalTypes.sys.mjs
@@ -0,0 +1,356 @@
+// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
+// Trust me, you don't want to mess with it!
+
+import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs";
+
+
+
+// Objects intended to be used in the unit tests
+export var UnitTestObjs = {};
+
+// Write/Read data to/from an ArrayBuffer
+class ArrayBufferDataStream {
+ constructor(arrayBuffer) {
+ this.dataView = new DataView(arrayBuffer);
+ this.pos = 0;
+ }
+
+ readUint8() {
+ let rv = this.dataView.getUint8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeUint8(value) {
+ this.dataView.setUint8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readUint16() {
+ let rv = this.dataView.getUint16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeUint16(value) {
+ this.dataView.setUint16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readUint32() {
+ let rv = this.dataView.getUint32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeUint32(value) {
+ this.dataView.setUint32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readUint64() {
+ let rv = this.dataView.getBigUint64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeUint64(value) {
+ this.dataView.setBigUint64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+
+ readInt8() {
+ let rv = this.dataView.getInt8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeInt8(value) {
+ this.dataView.setInt8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readInt16() {
+ let rv = this.dataView.getInt16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeInt16(value) {
+ this.dataView.setInt16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readInt32() {
+ let rv = this.dataView.getInt32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeInt32(value) {
+ this.dataView.setInt32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readInt64() {
+ let rv = this.dataView.getBigInt64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeInt64(value) {
+ this.dataView.setBigInt64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+ readFloat32() {
+ let rv = this.dataView.getFloat32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeFloat32(value) {
+ this.dataView.setFloat32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readFloat64() {
+ let rv = this.dataView.getFloat64(this.pos);
+ this.pos += 8;
+ return rv;
+ }
+
+ writeFloat64(value) {
+ this.dataView.setFloat64(this.pos, value);
+ this.pos += 8;
+ }
+
+
+ writeString(value) {
+ const encoder = new TextEncoder();
+ // Note: in order to efficiently write this data, we first write the
+ // string data, reserving 4 bytes for the size.
+ const dest = new Uint8Array(this.dataView.buffer, this.pos + 4);
+ const encodeResult = encoder.encodeInto(value, dest);
+ if (encodeResult.read != value.length) {
+ throw new UniFFIError(
+ "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?"
+ );
+ }
+ const size = encodeResult.written;
+ // Next, go back and write the size before the string data
+ this.dataView.setUint32(this.pos, size);
+ // Finally, advance our position past both the size and string data
+ this.pos += size + 4;
+ }
+
+ readString() {
+ const decoder = new TextDecoder();
+ const size = this.readUint32();
+ const source = new Uint8Array(this.dataView.buffer, this.pos, size)
+ const value = decoder.decode(source);
+ this.pos += size;
+ return value;
+ }
+}
+
+function handleRustResult(result, liftCallback, liftErrCallback) {
+ switch (result.code) {
+ case "success":
+ return liftCallback(result.data);
+
+ case "error":
+ throw liftErrCallback(result.data);
+
+ case "internal-error":
+ let message = result.internalErrorMessage;
+ if (message) {
+ throw new UniFFIInternalError(message);
+ } else {
+ throw new UniFFIInternalError("Unknown error");
+ }
+
+ default:
+ throw new UniFFIError(`Unexpected status code: ${result.code}`);
+ }
+}
+
+class UniFFIError {
+ constructor(message) {
+ this.message = message;
+ }
+
+ toString() {
+ return `UniFFIError: ${this.message}`
+ }
+}
+
+class UniFFIInternalError extends UniFFIError {}
+
+// Base class for FFI converters
+class FfiConverter {
+ // throw `UniFFITypeError` if a value to be converted has an invalid type
+ static checkType(value) {
+ if (value === undefined ) {
+ throw new UniFFITypeError(`undefined`);
+ }
+ if (value === null ) {
+ throw new UniFFITypeError(`null`);
+ }
+ }
+}
+
+// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer
+class FfiConverterArrayBuffer extends FfiConverter {
+ static lift(buf) {
+ return this.read(new ArrayBufferDataStream(buf));
+ }
+
+ static lower(value) {
+ const buf = new ArrayBuffer(this.computeSize(value));
+ const dataStream = new ArrayBufferDataStream(buf);
+ this.write(dataStream, value);
+ return buf;
+ }
+}
+
+// Symbols that are used to ensure that Object constructors
+// can only be used with a proper UniFFI pointer
+const uniffiObjectPtr = Symbol("uniffiObjectPtr");
+const constructUniffiObject = Symbol("constructUniffiObject");
+UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr;
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterF64 extends FfiConverter {
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeFloat64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readFloat64()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterString extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (typeof value !== "string") {
+ throw new UniFFITypeError(`${value} is not a string`);
+ }
+ }
+
+ static lift(buf) {
+ const decoder = new TextDecoder();
+ const utf8Arr = new Uint8Array(buf);
+ return decoder.decode(utf8Arr);
+ }
+ static lower(value) {
+ const encoder = new TextEncoder();
+ return encoder.encode(value).buffer;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeString(value);
+ }
+
+ static read(dataStream) {
+ return dataStream.readString();
+ }
+
+ static computeSize(value) {
+ const encoder = new TextEncoder();
+ return 4 + encoder.encode(value).length
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterOptionalTypeLine extends FfiConverterArrayBuffer {
+ static checkType(value) {
+ if (value !== undefined && value !== null) {
+ FfiConverterTypeLine.checkType(value)
+ }
+ }
+
+ static read(dataStream) {
+ const code = dataStream.readUint8(0);
+ switch (code) {
+ case 0:
+ return null
+ case 1:
+ return FfiConverterTypeLine.read(dataStream)
+ default:
+ throw UniFFIError(`Unexpected code: ${code}`);
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === null || value === undefined) {
+ dataStream.writeUint8(0);
+ return;
+ }
+ dataStream.writeUint8(1);
+ FfiConverterTypeLine.write(dataStream, value)
+ }
+
+ static computeSize(value) {
+ if (value === null || value === undefined) {
+ return 1;
+ }
+ return 1 + FfiConverterTypeLine.computeSize(value)
+ }
+}
+
+import {
+ FfiConverterTypeLine,
+ Line,
+} from "resource://gre/modules/RustGeometry.sys.mjs";
+
+// Export the FFIConverter object to make external types work.
+export { FfiConverterTypeLine, Line };
+
+import {
+ FfiConverterTypePoint,
+ Point,
+} from "resource://gre/modules/RustGeometry.sys.mjs";
+
+// Export the FFIConverter object to make external types work.
+export { FfiConverterTypePoint, Point };
+
+
+
+
+
+export function gradient(value) {
+
+ const liftResult = (result) => FfiConverterF64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterOptionalTypeLine.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 110, // external_types:external_types_c083_gradient
+ FfiConverterOptionalTypeLine.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustFixtureCallbacks.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustFixtureCallbacks.sys.mjs
new file mode 100644
index 0000000000..221669920a
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustFixtureCallbacks.sys.mjs
@@ -0,0 +1,639 @@
+// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
+// Trust me, you don't want to mess with it!
+
+import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs";
+
+
+
+// Objects intended to be used in the unit tests
+export var UnitTestObjs = {};
+
+// Write/Read data to/from an ArrayBuffer
+class ArrayBufferDataStream {
+ constructor(arrayBuffer) {
+ this.dataView = new DataView(arrayBuffer);
+ this.pos = 0;
+ }
+
+ readUint8() {
+ let rv = this.dataView.getUint8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeUint8(value) {
+ this.dataView.setUint8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readUint16() {
+ let rv = this.dataView.getUint16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeUint16(value) {
+ this.dataView.setUint16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readUint32() {
+ let rv = this.dataView.getUint32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeUint32(value) {
+ this.dataView.setUint32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readUint64() {
+ let rv = this.dataView.getBigUint64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeUint64(value) {
+ this.dataView.setBigUint64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+
+ readInt8() {
+ let rv = this.dataView.getInt8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeInt8(value) {
+ this.dataView.setInt8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readInt16() {
+ let rv = this.dataView.getInt16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeInt16(value) {
+ this.dataView.setInt16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readInt32() {
+ let rv = this.dataView.getInt32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeInt32(value) {
+ this.dataView.setInt32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readInt64() {
+ let rv = this.dataView.getBigInt64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeInt64(value) {
+ this.dataView.setBigInt64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+ readFloat32() {
+ let rv = this.dataView.getFloat32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeFloat32(value) {
+ this.dataView.setFloat32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readFloat64() {
+ let rv = this.dataView.getFloat64(this.pos);
+ this.pos += 8;
+ return rv;
+ }
+
+ writeFloat64(value) {
+ this.dataView.setFloat64(this.pos, value);
+ this.pos += 8;
+ }
+
+
+ writeString(value) {
+ const encoder = new TextEncoder();
+ // Note: in order to efficiently write this data, we first write the
+ // string data, reserving 4 bytes for the size.
+ const dest = new Uint8Array(this.dataView.buffer, this.pos + 4);
+ const encodeResult = encoder.encodeInto(value, dest);
+ if (encodeResult.read != value.length) {
+ throw new UniFFIError(
+ "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?"
+ );
+ }
+ const size = encodeResult.written;
+ // Next, go back and write the size before the string data
+ this.dataView.setUint32(this.pos, size);
+ // Finally, advance our position past both the size and string data
+ this.pos += size + 4;
+ }
+
+ readString() {
+ const decoder = new TextDecoder();
+ const size = this.readUint32();
+ const source = new Uint8Array(this.dataView.buffer, this.pos, size)
+ const value = decoder.decode(source);
+ this.pos += size;
+ return value;
+ }
+}
+
+function handleRustResult(result, liftCallback, liftErrCallback) {
+ switch (result.code) {
+ case "success":
+ return liftCallback(result.data);
+
+ case "error":
+ throw liftErrCallback(result.data);
+
+ case "internal-error":
+ let message = result.internalErrorMessage;
+ if (message) {
+ throw new UniFFIInternalError(message);
+ } else {
+ throw new UniFFIInternalError("Unknown error");
+ }
+
+ default:
+ throw new UniFFIError(`Unexpected status code: ${result.code}`);
+ }
+}
+
+class UniFFIError {
+ constructor(message) {
+ this.message = message;
+ }
+
+ toString() {
+ return `UniFFIError: ${this.message}`
+ }
+}
+
+class UniFFIInternalError extends UniFFIError {}
+
+// Base class for FFI converters
+class FfiConverter {
+ // throw `UniFFITypeError` if a value to be converted has an invalid type
+ static checkType(value) {
+ if (value === undefined ) {
+ throw new UniFFITypeError(`undefined`);
+ }
+ if (value === null ) {
+ throw new UniFFITypeError(`null`);
+ }
+ }
+}
+
+// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer
+class FfiConverterArrayBuffer extends FfiConverter {
+ static lift(buf) {
+ return this.read(new ArrayBufferDataStream(buf));
+ }
+
+ static lower(value) {
+ const buf = new ArrayBuffer(this.computeSize(value));
+ const dataStream = new ArrayBufferDataStream(buf);
+ this.write(dataStream, value);
+ return buf;
+ }
+}
+
+// Symbols that are used to ensure that Object constructors
+// can only be used with a proper UniFFI pointer
+const uniffiObjectPtr = Symbol("uniffiObjectPtr");
+const constructUniffiObject = Symbol("constructUniffiObject");
+UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr;
+
+
+/**
+ * Handler for a single UniFFI CallbackInterface
+ *
+ * This class stores objects that implement a callback interface in a handle
+ * map, allowing them to be referenced by the Rust code using an integer
+ * handle.
+ *
+ * While the callback object is stored in the map, it allows the Rust code to
+ * call methods on the object using the callback object handle, a method id,
+ * and an ArrayBuffer packed with the method arguments.
+ *
+ * When the Rust code drops its reference, it sends a call with the methodId=0,
+ * which causes callback object to be removed from the map.
+ */
+class UniFFICallbackHandler {
+ #name;
+ #interfaceId;
+ #handleCounter;
+ #handleMap;
+ #methodHandlers;
+ #allowNewCallbacks
+
+ /**
+ * Create a UniFFICallbackHandler
+ * @param {string} name - Human-friendly name for this callback interface
+ * @param {int} interfaceId - Interface ID for this CallbackInterface.
+ * @param {UniFFICallbackMethodHandler[]} methodHandlers -- UniFFICallbackHandler for each method, in the same order as the UDL file
+ */
+ constructor(name, interfaceId, methodHandlers) {
+ this.#name = name;
+ this.#interfaceId = interfaceId;
+ this.#handleCounter = 0;
+ this.#handleMap = new Map();
+ this.#methodHandlers = methodHandlers;
+ this.#allowNewCallbacks = true;
+
+ UniFFIScaffolding.registerCallbackHandler(this.#interfaceId, this.invokeCallback.bind(this));
+ Services.obs.addObserver(this, "xpcom-shutdown");
+ }
+
+ /**
+ * Store a callback object in the handle map and return the handle
+ *
+ * @param {obj} callbackObj - Object that implements the callback interface
+ * @returns {int} - Handle for this callback object, this is what gets passed back to Rust.
+ */
+ storeCallbackObj(callbackObj) {
+ if (!this.#allowNewCallbacks) {
+ throw new UniFFIError(`No new callbacks allowed for ${this.#name}`);
+ }
+ const handle = this.#handleCounter;
+ this.#handleCounter += 1;
+ this.#handleMap.set(handle, new UniFFICallbackHandleMapEntry(callbackObj, Components.stack.caller.formattedStack.trim()));
+ return handle;
+ }
+
+ /**
+ * Get a previously stored callback object
+ *
+ * @param {int} handle - Callback object handle, returned from `storeCallbackObj()`
+ * @returns {obj} - Callback object
+ */
+ getCallbackObj(handle) {
+ return this.#handleMap.get(handle).callbackObj;
+ }
+
+ /**
+ * Set if new callbacks are allowed for this handler
+ *
+ * This is called with false during shutdown to ensure the callback maps don't
+ * prevent JS objects from being GCed.
+ */
+ setAllowNewCallbacks(allow) {
+ this.#allowNewCallbacks = allow
+ }
+
+ /**
+ * Check that no callbacks are currently registered
+ *
+ * If there are callbacks registered a UniFFIError will be thrown. This is
+ * called during shutdown to generate an alert if there are leaked callback
+ * interfaces.
+ */
+ assertNoRegisteredCallbacks() {
+ if (this.#handleMap.size > 0) {
+ const entry = this.#handleMap.values().next().value;
+ throw new UniFFIError(`UniFFI interface ${this.#name} has ${this.#handleMap.size} registered callbacks at xpcom-shutdown. This likely indicates a UniFFI callback leak.\nStack trace for the first leaked callback:\n${entry.stackTrace}.`);
+ }
+ }
+
+ /**
+ * Invoke a method on a stored callback object
+ * @param {int} handle - Object handle
+ * @param {int} methodId - Method identifier. This the 1-based index of
+ * the method from the UDL file. 0 is the special drop method, which
+ * removes the callback object from the handle map.
+ * @param {ArrayBuffer} argsArrayBuffer - Arguments to pass to the method, packed in an ArrayBuffer
+ */
+ invokeCallback(handle, methodId, argsArrayBuffer) {
+ try {
+ this.#invokeCallbackInner(handle, methodId, argsArrayBuffer);
+ } catch (e) {
+ console.error(`internal error invoking callback: ${e}`)
+ }
+ }
+
+ #invokeCallbackInner(handle, methodId, argsArrayBuffer) {
+ const callbackObj = this.getCallbackObj(handle);
+ if (callbackObj === undefined) {
+ throw new UniFFIError(`${this.#name}: invalid callback handle id: ${handle}`);
+ }
+
+ // Special-cased drop method, remove the object from the handle map and
+ // return an empty array buffer
+ if (methodId == 0) {
+ this.#handleMap.delete(handle);
+ return;
+ }
+
+ // Get the method data, converting from 1-based indexing
+ const methodHandler = this.#methodHandlers[methodId - 1];
+ if (methodHandler === undefined) {
+ throw new UniFFIError(`${this.#name}: invalid method id: ${methodId}`)
+ }
+
+ methodHandler.call(callbackObj, argsArrayBuffer);
+ }
+
+ /**
+ * xpcom-shutdown observer method
+ *
+ * This handles:
+ * - Deregistering ourselves as the UniFFI callback handler
+ * - Checks for any leftover stored callbacks which indicate memory leaks
+ */
+ observe(aSubject, aTopic, aData) {
+ if (aTopic == "xpcom-shutdown") {
+ try {
+ this.setAllowNewCallbacks(false);
+ this.assertNoRegisteredCallbacks();
+ UniFFIScaffolding.deregisterCallbackHandler(this.#interfaceId);
+ } catch (ex) {
+ console.error(`UniFFI Callback interface error during xpcom-shutdown: ${ex}`);
+ Cc["@mozilla.org/xpcom/debug;1"]
+ .getService(Ci.nsIDebug2)
+ .abort(ex.filename, ex.lineNumber);
+ }
+ }
+ }
+}
+
+/**
+ * Handles calling a single method for a callback interface
+ */
+class UniFFICallbackMethodHandler {
+ #name;
+ #argsConverters;
+
+ /**
+ * Create a UniFFICallbackMethodHandler
+
+ * @param {string} name -- Name of the method to call on the callback object
+ * @param {FfiConverter[]} argsConverters - FfiConverter for each argument type
+ */
+ constructor(name, argsConverters) {
+ this.#name = name;
+ this.#argsConverters = argsConverters;
+ }
+
+ /**
+ * Invoke the method
+ *
+ * @param {obj} callbackObj -- Object implementing the callback interface for this method
+ * @param {ArrayBuffer} argsArrayBuffer -- Arguments for the method, packed in an ArrayBuffer
+ */
+ call(callbackObj, argsArrayBuffer) {
+ const argsStream = new ArrayBufferDataStream(argsArrayBuffer);
+ const args = this.#argsConverters.map(converter => converter.read(argsStream));
+ callbackObj[this.#name](...args);
+ }
+}
+
+/**
+ * UniFFICallbackHandler.handleMap entry
+ *
+ * @property callbackObj - Callback object, this must implement the callback interface.
+ * @property {string} stackTrace - Stack trace from when the callback object was registered. This is used to proved extra context when debugging leaked callback objects.
+ */
+class UniFFICallbackHandleMapEntry {
+ constructor(callbackObj, stackTrace) {
+ this.callbackObj = callbackObj;
+ this.stackTrace = stackTrace
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterI32 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < -2147483648 || value > 2147483647) {
+ throw new UniFFITypeError(`${value} exceeds the I32 bounds`);
+ }
+ }
+ static computeSize() {
+ return 4;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt32(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt32()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterString extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (typeof value !== "string") {
+ throw new UniFFITypeError(`${value} is not a string`);
+ }
+ }
+
+ static lift(buf) {
+ const decoder = new TextDecoder();
+ const utf8Arr = new Uint8Array(buf);
+ return decoder.decode(utf8Arr);
+ }
+ static lower(value) {
+ const encoder = new TextEncoder();
+ return encoder.encode(value).buffer;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeString(value);
+ }
+
+ static read(dataStream) {
+ return dataStream.readString();
+ }
+
+ static computeSize(value) {
+ const encoder = new TextEncoder();
+ return 4 + encoder.encode(value).length
+ }
+}
+
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterCallbackInterfaceLogger extends FfiConverter {
+ static lower(callbackObj) {
+ return callbackHandlerLogger.storeCallbackObj(callbackObj)
+ }
+
+ static lift(handleId) {
+ return callbackHandlerLogger.getCallbackObj(handleId)
+ }
+
+ static read(dataStream) {
+ return this.lift(dataStream.readInt64())
+ }
+
+ static write(dataStream, callbackObj) {
+ dataStream.writeInt64(this.lower(callbackObj))
+ }
+
+ static computeSize(callbackObj) {
+ return 8;
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterSequencei32 extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const arr = [];
+ for (let i = 0; i < len; i++) {
+ arr.push(FfiConverterI32.read(dataStream));
+ }
+ return arr;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(value.length);
+ value.forEach((innerValue) => {
+ FfiConverterI32.write(dataStream, innerValue);
+ })
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const innerValue of value) {
+ size += FfiConverterI32.computeSize(innerValue);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ if (!Array.isArray(value)) {
+ throw new UniFFITypeError(`${value} is not an array`);
+ }
+ value.forEach((innerValue, idx) => {
+ try {
+ FfiConverterI32.checkType(innerValue);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${idx}]`);
+ }
+ throw e;
+ }
+ })
+ }
+}
+
+
+// Define callback interface handlers, this must come after the type loop since they reference the FfiConverters defined above.
+
+const callbackHandlerLogger = new UniFFICallbackHandler(
+ "fixture_callbacks:Logger",
+ 0,
+ [
+ new UniFFICallbackMethodHandler(
+ "log",
+ [
+ FfiConverterString,
+ ],
+ ),
+ new UniFFICallbackMethodHandler(
+ "finished",
+ [
+ ],
+ ),
+ ]
+);
+
+// Allow the shutdown-related functionality to be tested in the unit tests
+UnitTestObjs.callbackHandlerLogger = callbackHandlerLogger;
+
+
+
+
+
+export function logEvenNumbers(logger,items) {
+
+ const liftResult = (result) => undefined;
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterCallbackInterfaceLogger.checkType(logger)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("logger");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterSequencei32.checkType(items)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("items");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 107, // fixture_callbacks:fixture_callbacks_fdf_log_even_numbers
+ FfiConverterCallbackInterfaceLogger.lower(logger),
+ FfiConverterSequencei32.lower(items),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function logEvenNumbersMainThread(logger,items) {
+
+ const liftResult = (result) => undefined;
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterCallbackInterfaceLogger.checkType(logger)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("logger");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterSequencei32.checkType(items)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("items");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callSync(
+ 108, // fixture_callbacks:fixture_callbacks_fdf_log_even_numbers_main_thread
+ FfiConverterCallbackInterfaceLogger.lower(logger),
+ FfiConverterSequencei32.lower(items),
+ )
+ }
+ return handleRustResult(functionCall(), liftResult, liftError);
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustGeometry.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustGeometry.sys.mjs
new file mode 100644
index 0000000000..15a9c55c0c
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustGeometry.sys.mjs
@@ -0,0 +1,514 @@
+// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
+// Trust me, you don't want to mess with it!
+
+import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs";
+
+
+
+// Objects intended to be used in the unit tests
+export var UnitTestObjs = {};
+
+// Write/Read data to/from an ArrayBuffer
+class ArrayBufferDataStream {
+ constructor(arrayBuffer) {
+ this.dataView = new DataView(arrayBuffer);
+ this.pos = 0;
+ }
+
+ readUint8() {
+ let rv = this.dataView.getUint8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeUint8(value) {
+ this.dataView.setUint8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readUint16() {
+ let rv = this.dataView.getUint16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeUint16(value) {
+ this.dataView.setUint16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readUint32() {
+ let rv = this.dataView.getUint32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeUint32(value) {
+ this.dataView.setUint32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readUint64() {
+ let rv = this.dataView.getBigUint64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeUint64(value) {
+ this.dataView.setBigUint64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+
+ readInt8() {
+ let rv = this.dataView.getInt8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeInt8(value) {
+ this.dataView.setInt8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readInt16() {
+ let rv = this.dataView.getInt16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeInt16(value) {
+ this.dataView.setInt16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readInt32() {
+ let rv = this.dataView.getInt32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeInt32(value) {
+ this.dataView.setInt32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readInt64() {
+ let rv = this.dataView.getBigInt64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeInt64(value) {
+ this.dataView.setBigInt64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+ readFloat32() {
+ let rv = this.dataView.getFloat32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeFloat32(value) {
+ this.dataView.setFloat32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readFloat64() {
+ let rv = this.dataView.getFloat64(this.pos);
+ this.pos += 8;
+ return rv;
+ }
+
+ writeFloat64(value) {
+ this.dataView.setFloat64(this.pos, value);
+ this.pos += 8;
+ }
+
+
+ writeString(value) {
+ const encoder = new TextEncoder();
+ // Note: in order to efficiently write this data, we first write the
+ // string data, reserving 4 bytes for the size.
+ const dest = new Uint8Array(this.dataView.buffer, this.pos + 4);
+ const encodeResult = encoder.encodeInto(value, dest);
+ if (encodeResult.read != value.length) {
+ throw new UniFFIError(
+ "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?"
+ );
+ }
+ const size = encodeResult.written;
+ // Next, go back and write the size before the string data
+ this.dataView.setUint32(this.pos, size);
+ // Finally, advance our position past both the size and string data
+ this.pos += size + 4;
+ }
+
+ readString() {
+ const decoder = new TextDecoder();
+ const size = this.readUint32();
+ const source = new Uint8Array(this.dataView.buffer, this.pos, size)
+ const value = decoder.decode(source);
+ this.pos += size;
+ return value;
+ }
+}
+
+function handleRustResult(result, liftCallback, liftErrCallback) {
+ switch (result.code) {
+ case "success":
+ return liftCallback(result.data);
+
+ case "error":
+ throw liftErrCallback(result.data);
+
+ case "internal-error":
+ let message = result.internalErrorMessage;
+ if (message) {
+ throw new UniFFIInternalError(message);
+ } else {
+ throw new UniFFIInternalError("Unknown error");
+ }
+
+ default:
+ throw new UniFFIError(`Unexpected status code: ${result.code}`);
+ }
+}
+
+class UniFFIError {
+ constructor(message) {
+ this.message = message;
+ }
+
+ toString() {
+ return `UniFFIError: ${this.message}`
+ }
+}
+
+class UniFFIInternalError extends UniFFIError {}
+
+// Base class for FFI converters
+class FfiConverter {
+ // throw `UniFFITypeError` if a value to be converted has an invalid type
+ static checkType(value) {
+ if (value === undefined ) {
+ throw new UniFFITypeError(`undefined`);
+ }
+ if (value === null ) {
+ throw new UniFFITypeError(`null`);
+ }
+ }
+}
+
+// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer
+class FfiConverterArrayBuffer extends FfiConverter {
+ static lift(buf) {
+ return this.read(new ArrayBufferDataStream(buf));
+ }
+
+ static lower(value) {
+ const buf = new ArrayBuffer(this.computeSize(value));
+ const dataStream = new ArrayBufferDataStream(buf);
+ this.write(dataStream, value);
+ return buf;
+ }
+}
+
+// Symbols that are used to ensure that Object constructors
+// can only be used with a proper UniFFI pointer
+const uniffiObjectPtr = Symbol("uniffiObjectPtr");
+const constructUniffiObject = Symbol("constructUniffiObject");
+UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr;
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterF64 extends FfiConverter {
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeFloat64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readFloat64()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterString extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (typeof value !== "string") {
+ throw new UniFFITypeError(`${value} is not a string`);
+ }
+ }
+
+ static lift(buf) {
+ const decoder = new TextDecoder();
+ const utf8Arr = new Uint8Array(buf);
+ return decoder.decode(utf8Arr);
+ }
+ static lower(value) {
+ const encoder = new TextEncoder();
+ return encoder.encode(value).buffer;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeString(value);
+ }
+
+ static read(dataStream) {
+ return dataStream.readString();
+ }
+
+ static computeSize(value) {
+ const encoder = new TextEncoder();
+ return 4 + encoder.encode(value).length
+ }
+}
+
+export class Line {
+ constructor(start,end) {
+ try {
+ FfiConverterTypePoint.checkType(start)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("start");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypePoint.checkType(end)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("end");
+ }
+ throw e;
+ }
+ this.start = start;
+ this.end = end;
+ }
+ equals(other) {
+ return (
+ this.start.equals(other.start) &&
+ this.end.equals(other.end)
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeLine extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new Line(
+ FfiConverterTypePoint.read(dataStream),
+ FfiConverterTypePoint.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterTypePoint.write(dataStream, value.start);
+ FfiConverterTypePoint.write(dataStream, value.end);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterTypePoint.computeSize(value.start);
+ totalSize += FfiConverterTypePoint.computeSize(value.end);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterTypePoint.checkType(value.start);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".start");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypePoint.checkType(value.end);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".end");
+ }
+ throw e;
+ }
+ }
+}
+
+export class Point {
+ constructor(coordX,coordY) {
+ try {
+ FfiConverterF64.checkType(coordX)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("coordX");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterF64.checkType(coordY)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("coordY");
+ }
+ throw e;
+ }
+ this.coordX = coordX;
+ this.coordY = coordY;
+ }
+ equals(other) {
+ return (
+ this.coordX == other.coordX &&
+ this.coordY == other.coordY
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypePoint extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new Point(
+ FfiConverterF64.read(dataStream),
+ FfiConverterF64.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterF64.write(dataStream, value.coordX);
+ FfiConverterF64.write(dataStream, value.coordY);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterF64.computeSize(value.coordX);
+ totalSize += FfiConverterF64.computeSize(value.coordY);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterF64.checkType(value.coordX);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".coordX");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterF64.checkType(value.coordY);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".coordY");
+ }
+ throw e;
+ }
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterOptionalTypePoint extends FfiConverterArrayBuffer {
+ static checkType(value) {
+ if (value !== undefined && value !== null) {
+ FfiConverterTypePoint.checkType(value)
+ }
+ }
+
+ static read(dataStream) {
+ const code = dataStream.readUint8(0);
+ switch (code) {
+ case 0:
+ return null
+ case 1:
+ return FfiConverterTypePoint.read(dataStream)
+ default:
+ throw UniFFIError(`Unexpected code: ${code}`);
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === null || value === undefined) {
+ dataStream.writeUint8(0);
+ return;
+ }
+ dataStream.writeUint8(1);
+ FfiConverterTypePoint.write(dataStream, value)
+ }
+
+ static computeSize(value) {
+ if (value === null || value === undefined) {
+ return 1;
+ }
+ return 1 + FfiConverterTypePoint.computeSize(value)
+ }
+}
+
+
+
+
+
+export function gradient(ln) {
+
+ const liftResult = (result) => FfiConverterF64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypeLine.checkType(ln)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("ln");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 20, // geometry:geometry_f26e_gradient
+ FfiConverterTypeLine.lower(ln),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function intersection(ln1,ln2) {
+
+ const liftResult = (result) => FfiConverterOptionalTypePoint.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypeLine.checkType(ln1)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("ln1");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypeLine.checkType(ln2)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("ln2");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 21, // geometry:geometry_f26e_intersection
+ FfiConverterTypeLine.lower(ln1),
+ FfiConverterTypeLine.lower(ln2),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRondpoint.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRondpoint.sys.mjs
new file mode 100644
index 0000000000..97990fc054
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRondpoint.sys.mjs
@@ -0,0 +1,3363 @@
+// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
+// Trust me, you don't want to mess with it!
+
+import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs";
+
+
+
+// Objects intended to be used in the unit tests
+export var UnitTestObjs = {};
+
+// Write/Read data to/from an ArrayBuffer
+class ArrayBufferDataStream {
+ constructor(arrayBuffer) {
+ this.dataView = new DataView(arrayBuffer);
+ this.pos = 0;
+ }
+
+ readUint8() {
+ let rv = this.dataView.getUint8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeUint8(value) {
+ this.dataView.setUint8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readUint16() {
+ let rv = this.dataView.getUint16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeUint16(value) {
+ this.dataView.setUint16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readUint32() {
+ let rv = this.dataView.getUint32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeUint32(value) {
+ this.dataView.setUint32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readUint64() {
+ let rv = this.dataView.getBigUint64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeUint64(value) {
+ this.dataView.setBigUint64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+
+ readInt8() {
+ let rv = this.dataView.getInt8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeInt8(value) {
+ this.dataView.setInt8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readInt16() {
+ let rv = this.dataView.getInt16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeInt16(value) {
+ this.dataView.setInt16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readInt32() {
+ let rv = this.dataView.getInt32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeInt32(value) {
+ this.dataView.setInt32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readInt64() {
+ let rv = this.dataView.getBigInt64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeInt64(value) {
+ this.dataView.setBigInt64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+ readFloat32() {
+ let rv = this.dataView.getFloat32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeFloat32(value) {
+ this.dataView.setFloat32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readFloat64() {
+ let rv = this.dataView.getFloat64(this.pos);
+ this.pos += 8;
+ return rv;
+ }
+
+ writeFloat64(value) {
+ this.dataView.setFloat64(this.pos, value);
+ this.pos += 8;
+ }
+
+
+ writeString(value) {
+ const encoder = new TextEncoder();
+ // Note: in order to efficiently write this data, we first write the
+ // string data, reserving 4 bytes for the size.
+ const dest = new Uint8Array(this.dataView.buffer, this.pos + 4);
+ const encodeResult = encoder.encodeInto(value, dest);
+ if (encodeResult.read != value.length) {
+ throw new UniFFIError(
+ "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?"
+ );
+ }
+ const size = encodeResult.written;
+ // Next, go back and write the size before the string data
+ this.dataView.setUint32(this.pos, size);
+ // Finally, advance our position past both the size and string data
+ this.pos += size + 4;
+ }
+
+ readString() {
+ const decoder = new TextDecoder();
+ const size = this.readUint32();
+ const source = new Uint8Array(this.dataView.buffer, this.pos, size)
+ const value = decoder.decode(source);
+ this.pos += size;
+ return value;
+ }
+
+ // Reads a Retourneur pointer from the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ readPointerRetourneur() {
+ const pointerId = 2; // rondpoint:Retourneur
+ const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ return res;
+ }
+
+ // Writes a Retourneur pointer into the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ writePointerRetourneur(value) {
+ const pointerId = 2; // rondpoint:Retourneur
+ UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ }
+
+
+ // Reads a Stringifier pointer from the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ readPointerStringifier() {
+ const pointerId = 3; // rondpoint:Stringifier
+ const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ return res;
+ }
+
+ // Writes a Stringifier pointer into the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ writePointerStringifier(value) {
+ const pointerId = 3; // rondpoint:Stringifier
+ UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ }
+
+
+ // Reads a Optionneur pointer from the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ readPointerOptionneur() {
+ const pointerId = 4; // rondpoint:Optionneur
+ const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ return res;
+ }
+
+ // Writes a Optionneur pointer into the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ writePointerOptionneur(value) {
+ const pointerId = 4; // rondpoint:Optionneur
+ UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ }
+
+}
+
+function handleRustResult(result, liftCallback, liftErrCallback) {
+ switch (result.code) {
+ case "success":
+ return liftCallback(result.data);
+
+ case "error":
+ throw liftErrCallback(result.data);
+
+ case "internal-error":
+ let message = result.internalErrorMessage;
+ if (message) {
+ throw new UniFFIInternalError(message);
+ } else {
+ throw new UniFFIInternalError("Unknown error");
+ }
+
+ default:
+ throw new UniFFIError(`Unexpected status code: ${result.code}`);
+ }
+}
+
+class UniFFIError {
+ constructor(message) {
+ this.message = message;
+ }
+
+ toString() {
+ return `UniFFIError: ${this.message}`
+ }
+}
+
+class UniFFIInternalError extends UniFFIError {}
+
+// Base class for FFI converters
+class FfiConverter {
+ // throw `UniFFITypeError` if a value to be converted has an invalid type
+ static checkType(value) {
+ if (value === undefined ) {
+ throw new UniFFITypeError(`undefined`);
+ }
+ if (value === null ) {
+ throw new UniFFITypeError(`null`);
+ }
+ }
+}
+
+// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer
+class FfiConverterArrayBuffer extends FfiConverter {
+ static lift(buf) {
+ return this.read(new ArrayBufferDataStream(buf));
+ }
+
+ static lower(value) {
+ const buf = new ArrayBuffer(this.computeSize(value));
+ const dataStream = new ArrayBufferDataStream(buf);
+ this.write(dataStream, value);
+ return buf;
+ }
+}
+
+// Symbols that are used to ensure that Object constructors
+// can only be used with a proper UniFFI pointer
+const uniffiObjectPtr = Symbol("uniffiObjectPtr");
+const constructUniffiObject = Symbol("constructUniffiObject");
+UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr;
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterU8 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < 0 || value > 256) {
+ throw new UniFFITypeError(`${value} exceeds the U8 bounds`);
+ }
+ }
+ static computeSize() {
+ return 1;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint8(value)
+ }
+ static read(dataStream) {
+ return dataStream.readUint8()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterI8 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < -128 || value > 127) {
+ throw new UniFFITypeError(`${value} exceeds the I8 bounds`);
+ }
+ }
+ static computeSize() {
+ return 1;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt8(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt8()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterU16 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < 0 || value > 65535) {
+ throw new UniFFITypeError(`${value} exceeds the U16 bounds`);
+ }
+ }
+ static computeSize() {
+ return 2;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint16(value)
+ }
+ static read(dataStream) {
+ return dataStream.readUint16()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterI16 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < -32768 || value > 32767) {
+ throw new UniFFITypeError(`${value} exceeds the I16 bounds`);
+ }
+ }
+ static computeSize() {
+ return 2;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt16(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt16()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterU32 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < 0 || value > 4294967295) {
+ throw new UniFFITypeError(`${value} exceeds the U32 bounds`);
+ }
+ }
+ static computeSize() {
+ return 4;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint32(value)
+ }
+ static read(dataStream) {
+ return dataStream.readUint32()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterI32 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < -2147483648 || value > 2147483647) {
+ throw new UniFFITypeError(`${value} exceeds the I32 bounds`);
+ }
+ }
+ static computeSize() {
+ return 4;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt32(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt32()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterU64 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isSafeInteger(value)) {
+ throw new UniFFITypeError(`${value} exceeds the safe integer bounds`);
+ }
+ if (value < 0) {
+ throw new UniFFITypeError(`${value} exceeds the U64 bounds`);
+ }
+ }
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readUint64()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterI64 extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isSafeInteger(value)) {
+ throw new UniFFITypeError(`${value} exceeds the safe integer bounds`);
+ }
+ }
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt64()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterF32 extends FfiConverter {
+ static computeSize() {
+ return 4;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeFloat32(value)
+ }
+ static read(dataStream) {
+ return dataStream.readFloat32()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterF64 extends FfiConverter {
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeFloat64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readFloat64()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterBool extends FfiConverter {
+ static computeSize() {
+ return 1;
+ }
+ static lift(value) {
+ return value == 1;
+ }
+ static lower(value) {
+ if (value) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint8(this.lower(value))
+ }
+ static read(dataStream) {
+ return this.lift(dataStream.readUint8())
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterString extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (typeof value !== "string") {
+ throw new UniFFITypeError(`${value} is not a string`);
+ }
+ }
+
+ static lift(buf) {
+ const decoder = new TextDecoder();
+ const utf8Arr = new Uint8Array(buf);
+ return decoder.decode(utf8Arr);
+ }
+ static lower(value) {
+ const encoder = new TextEncoder();
+ return encoder.encode(value).buffer;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeString(value);
+ }
+
+ static read(dataStream) {
+ return dataStream.readString();
+ }
+
+ static computeSize(value) {
+ const encoder = new TextEncoder();
+ return 4 + encoder.encode(value).length
+ }
+}
+
+export class Optionneur {
+ // Use `init` to instantiate this class.
+ // DO NOT USE THIS CONSTRUCTOR DIRECTLY
+ constructor(opts) {
+ if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
+ throw new UniFFIError("Attempting to construct an object using the JavaScript constructor directly" +
+ "Please use a UDL defined constructor, or the init function for the primary constructor")
+ }
+ if (!opts[constructUniffiObject] instanceof UniFFIPointer) {
+ throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
+ }
+ this[uniffiObjectPtr] = opts[constructUniffiObject];
+ }
+ /**
+ * An async constructor for Optionneur.
+ *
+ * @returns {Promise<Optionneur>}: A promise that resolves
+ * to a newly constructed Optionneur
+ */
+ static init() {
+ const liftResult = (result) => FfiConverterTypeOptionneur.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 55, // rondpoint:rondpoint_7b7b_Optionneur_new
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }}
+
+ sinonBoolean(value = false) {
+ const liftResult = (result) => FfiConverterBool.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterBool.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 56, // rondpoint:rondpoint_7b7b_Optionneur_sinon_boolean
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterBool.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonString(value = "default") {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterString.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 57, // rondpoint:rondpoint_7b7b_Optionneur_sinon_string
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterString.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonSequence(value = []) {
+ const liftResult = (result) => FfiConverterSequencestring.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterSequencestring.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 58, // rondpoint:rondpoint_7b7b_Optionneur_sinon_sequence
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterSequencestring.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonNull(value = null) {
+ const liftResult = (result) => FfiConverterOptionalstring.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterOptionalstring.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 59, // rondpoint:rondpoint_7b7b_Optionneur_sinon_null
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterOptionalstring.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonZero(value = 0) {
+ const liftResult = (result) => FfiConverterOptionali32.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterOptionali32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 60, // rondpoint:rondpoint_7b7b_Optionneur_sinon_zero
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterOptionali32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonU8Dec(value = 42) {
+ const liftResult = (result) => FfiConverterU8.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU8.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 61, // rondpoint:rondpoint_7b7b_Optionneur_sinon_u8_dec
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterU8.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonI8Dec(value = -42) {
+ const liftResult = (result) => FfiConverterI8.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI8.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 62, // rondpoint:rondpoint_7b7b_Optionneur_sinon_i8_dec
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterI8.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonU16Dec(value = 42) {
+ const liftResult = (result) => FfiConverterU16.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU16.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 63, // rondpoint:rondpoint_7b7b_Optionneur_sinon_u16_dec
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterU16.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonI16Dec(value = 42) {
+ const liftResult = (result) => FfiConverterI16.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI16.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 64, // rondpoint:rondpoint_7b7b_Optionneur_sinon_i16_dec
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterI16.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonU32Dec(value = 42) {
+ const liftResult = (result) => FfiConverterU32.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 65, // rondpoint:rondpoint_7b7b_Optionneur_sinon_u32_dec
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterU32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonI32Dec(value = 42) {
+ const liftResult = (result) => FfiConverterI32.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 66, // rondpoint:rondpoint_7b7b_Optionneur_sinon_i32_dec
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterI32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonU64Dec(value = 42) {
+ const liftResult = (result) => FfiConverterU64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 67, // rondpoint:rondpoint_7b7b_Optionneur_sinon_u64_dec
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterU64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonI64Dec(value = 42) {
+ const liftResult = (result) => FfiConverterI64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 68, // rondpoint:rondpoint_7b7b_Optionneur_sinon_i64_dec
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterI64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonU8Hex(value = 0xff) {
+ const liftResult = (result) => FfiConverterU8.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU8.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 69, // rondpoint:rondpoint_7b7b_Optionneur_sinon_u8_hex
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterU8.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonI8Hex(value = -127) {
+ const liftResult = (result) => FfiConverterI8.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI8.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 70, // rondpoint:rondpoint_7b7b_Optionneur_sinon_i8_hex
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterI8.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonU16Hex(value = 0xffff) {
+ const liftResult = (result) => FfiConverterU16.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU16.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 71, // rondpoint:rondpoint_7b7b_Optionneur_sinon_u16_hex
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterU16.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonI16Hex(value = 0x7f) {
+ const liftResult = (result) => FfiConverterI16.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI16.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 72, // rondpoint:rondpoint_7b7b_Optionneur_sinon_i16_hex
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterI16.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonU32Hex(value = 0xffffffff) {
+ const liftResult = (result) => FfiConverterU32.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 73, // rondpoint:rondpoint_7b7b_Optionneur_sinon_u32_hex
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterU32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonI32Hex(value = 0x7fffffff) {
+ const liftResult = (result) => FfiConverterI32.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 74, // rondpoint:rondpoint_7b7b_Optionneur_sinon_i32_hex
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterI32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonU64Hex(value = 0xffffffffffffffff) {
+ const liftResult = (result) => FfiConverterU64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 75, // rondpoint:rondpoint_7b7b_Optionneur_sinon_u64_hex
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterU64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonI64Hex(value = 0x7fffffffffffffff) {
+ const liftResult = (result) => FfiConverterI64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 76, // rondpoint:rondpoint_7b7b_Optionneur_sinon_i64_hex
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterI64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonU32Oct(value = 0o755) {
+ const liftResult = (result) => FfiConverterU32.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 77, // rondpoint:rondpoint_7b7b_Optionneur_sinon_u32_oct
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterU32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonF32(value = 42.0) {
+ const liftResult = (result) => FfiConverterF32.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterF32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 78, // rondpoint:rondpoint_7b7b_Optionneur_sinon_f32
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterF32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonF64(value = 42.1) {
+ const liftResult = (result) => FfiConverterF64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterF64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 79, // rondpoint:rondpoint_7b7b_Optionneur_sinon_f64
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterF64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ sinonEnum(value = Enumeration.TROIS) {
+ const liftResult = (result) => FfiConverterTypeEnumeration.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypeEnumeration.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 80, // rondpoint:rondpoint_7b7b_Optionneur_sinon_enum
+ FfiConverterTypeOptionneur.lower(this),
+ FfiConverterTypeEnumeration.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeOptionneur extends FfiConverter {
+ static lift(value) {
+ const opts = {};
+ opts[constructUniffiObject] = value;
+ return new Optionneur(opts);
+ }
+
+ static lower(value) {
+ return value[uniffiObjectPtr];
+ }
+
+ static read(dataStream) {
+ return this.lift(dataStream.readPointerOptionneur());
+ }
+
+ static write(dataStream, value) {
+ dataStream.writePointerOptionneur(value[uniffiObjectPtr]);
+ }
+
+ static computeSize(value) {
+ return 8;
+ }
+}
+
+export class Retourneur {
+ // Use `init` to instantiate this class.
+ // DO NOT USE THIS CONSTRUCTOR DIRECTLY
+ constructor(opts) {
+ if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
+ throw new UniFFIError("Attempting to construct an object using the JavaScript constructor directly" +
+ "Please use a UDL defined constructor, or the init function for the primary constructor")
+ }
+ if (!opts[constructUniffiObject] instanceof UniFFIPointer) {
+ throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
+ }
+ this[uniffiObjectPtr] = opts[constructUniffiObject];
+ }
+ /**
+ * An async constructor for Retourneur.
+ *
+ * @returns {Promise<Retourneur>}: A promise that resolves
+ * to a newly constructed Retourneur
+ */
+ static init() {
+ const liftResult = (result) => FfiConverterTypeRetourneur.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 26, // rondpoint:rondpoint_7b7b_Retourneur_new
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }}
+
+ identiqueI8(value) {
+ const liftResult = (result) => FfiConverterI8.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI8.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 27, // rondpoint:rondpoint_7b7b_Retourneur_identique_i8
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterI8.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueU8(value) {
+ const liftResult = (result) => FfiConverterU8.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU8.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 28, // rondpoint:rondpoint_7b7b_Retourneur_identique_u8
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterU8.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueI16(value) {
+ const liftResult = (result) => FfiConverterI16.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI16.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 29, // rondpoint:rondpoint_7b7b_Retourneur_identique_i16
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterI16.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueU16(value) {
+ const liftResult = (result) => FfiConverterU16.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU16.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 30, // rondpoint:rondpoint_7b7b_Retourneur_identique_u16
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterU16.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueI32(value) {
+ const liftResult = (result) => FfiConverterI32.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 31, // rondpoint:rondpoint_7b7b_Retourneur_identique_i32
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterI32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueU32(value) {
+ const liftResult = (result) => FfiConverterU32.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 32, // rondpoint:rondpoint_7b7b_Retourneur_identique_u32
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterU32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueI64(value) {
+ const liftResult = (result) => FfiConverterI64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 33, // rondpoint:rondpoint_7b7b_Retourneur_identique_i64
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterI64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueU64(value) {
+ const liftResult = (result) => FfiConverterU64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 34, // rondpoint:rondpoint_7b7b_Retourneur_identique_u64
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterU64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueFloat(value) {
+ const liftResult = (result) => FfiConverterF32.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterF32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 35, // rondpoint:rondpoint_7b7b_Retourneur_identique_float
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterF32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueDouble(value) {
+ const liftResult = (result) => FfiConverterF64.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterF64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 36, // rondpoint:rondpoint_7b7b_Retourneur_identique_double
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterF64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueBoolean(value) {
+ const liftResult = (result) => FfiConverterBool.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterBool.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 37, // rondpoint:rondpoint_7b7b_Retourneur_identique_boolean
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterBool.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueString(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterString.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 38, // rondpoint:rondpoint_7b7b_Retourneur_identique_string
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterString.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueNombresSignes(value) {
+ const liftResult = (result) => FfiConverterTypeDictionnaireNombresSignes.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypeDictionnaireNombresSignes.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 39, // rondpoint:rondpoint_7b7b_Retourneur_identique_nombres_signes
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterTypeDictionnaireNombresSignes.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueNombres(value) {
+ const liftResult = (result) => FfiConverterTypeDictionnaireNombres.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypeDictionnaireNombres.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 40, // rondpoint:rondpoint_7b7b_Retourneur_identique_nombres
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterTypeDictionnaireNombres.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ identiqueOptionneurDictionnaire(value) {
+ const liftResult = (result) => FfiConverterTypeOptionneurDictionnaire.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypeOptionneurDictionnaire.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 41, // rondpoint:rondpoint_7b7b_Retourneur_identique_optionneur_dictionnaire
+ FfiConverterTypeRetourneur.lower(this),
+ FfiConverterTypeOptionneurDictionnaire.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeRetourneur extends FfiConverter {
+ static lift(value) {
+ const opts = {};
+ opts[constructUniffiObject] = value;
+ return new Retourneur(opts);
+ }
+
+ static lower(value) {
+ return value[uniffiObjectPtr];
+ }
+
+ static read(dataStream) {
+ return this.lift(dataStream.readPointerRetourneur());
+ }
+
+ static write(dataStream, value) {
+ dataStream.writePointerRetourneur(value[uniffiObjectPtr]);
+ }
+
+ static computeSize(value) {
+ return 8;
+ }
+}
+
+export class Stringifier {
+ // Use `init` to instantiate this class.
+ // DO NOT USE THIS CONSTRUCTOR DIRECTLY
+ constructor(opts) {
+ if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
+ throw new UniFFIError("Attempting to construct an object using the JavaScript constructor directly" +
+ "Please use a UDL defined constructor, or the init function for the primary constructor")
+ }
+ if (!opts[constructUniffiObject] instanceof UniFFIPointer) {
+ throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
+ }
+ this[uniffiObjectPtr] = opts[constructUniffiObject];
+ }
+ /**
+ * An async constructor for Stringifier.
+ *
+ * @returns {Promise<Stringifier>}: A promise that resolves
+ * to a newly constructed Stringifier
+ */
+ static init() {
+ const liftResult = (result) => FfiConverterTypeStringifier.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 42, // rondpoint:rondpoint_7b7b_Stringifier_new
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }}
+
+ wellKnownString(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterString.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 43, // rondpoint:rondpoint_7b7b_Stringifier_well_known_string
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterString.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringI8(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI8.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 44, // rondpoint:rondpoint_7b7b_Stringifier_to_string_i8
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterI8.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringU8(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU8.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 45, // rondpoint:rondpoint_7b7b_Stringifier_to_string_u8
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterU8.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringI16(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI16.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 46, // rondpoint:rondpoint_7b7b_Stringifier_to_string_i16
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterI16.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringU16(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU16.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 47, // rondpoint:rondpoint_7b7b_Stringifier_to_string_u16
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterU16.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringI32(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 48, // rondpoint:rondpoint_7b7b_Stringifier_to_string_i32
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterI32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringU32(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 49, // rondpoint:rondpoint_7b7b_Stringifier_to_string_u32
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterU32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringI64(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterI64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 50, // rondpoint:rondpoint_7b7b_Stringifier_to_string_i64
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterI64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringU64(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterU64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 51, // rondpoint:rondpoint_7b7b_Stringifier_to_string_u64
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterU64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringFloat(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterF32.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 52, // rondpoint:rondpoint_7b7b_Stringifier_to_string_float
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterF32.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringDouble(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterF64.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 53, // rondpoint:rondpoint_7b7b_Stringifier_to_string_double
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterF64.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ toStringBoolean(value) {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterBool.checkType(value)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("value");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 54, // rondpoint:rondpoint_7b7b_Stringifier_to_string_boolean
+ FfiConverterTypeStringifier.lower(this),
+ FfiConverterBool.lower(value),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeStringifier extends FfiConverter {
+ static lift(value) {
+ const opts = {};
+ opts[constructUniffiObject] = value;
+ return new Stringifier(opts);
+ }
+
+ static lower(value) {
+ return value[uniffiObjectPtr];
+ }
+
+ static read(dataStream) {
+ return this.lift(dataStream.readPointerStringifier());
+ }
+
+ static write(dataStream, value) {
+ dataStream.writePointerStringifier(value[uniffiObjectPtr]);
+ }
+
+ static computeSize(value) {
+ return 8;
+ }
+}
+
+export class Dictionnaire {
+ constructor(un,deux,petitNombre,grosNombre) {
+ try {
+ FfiConverterTypeEnumeration.checkType(un)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("un");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterBool.checkType(deux)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("deux");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU8.checkType(petitNombre)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("petitNombre");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU64.checkType(grosNombre)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("grosNombre");
+ }
+ throw e;
+ }
+ this.un = un;
+ this.deux = deux;
+ this.petitNombre = petitNombre;
+ this.grosNombre = grosNombre;
+ }
+ equals(other) {
+ return (
+ this.un == other.un &&
+ this.deux == other.deux &&
+ this.petitNombre == other.petitNombre &&
+ this.grosNombre == other.grosNombre
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeDictionnaire extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new Dictionnaire(
+ FfiConverterTypeEnumeration.read(dataStream),
+ FfiConverterBool.read(dataStream),
+ FfiConverterU8.read(dataStream),
+ FfiConverterU64.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterTypeEnumeration.write(dataStream, value.un);
+ FfiConverterBool.write(dataStream, value.deux);
+ FfiConverterU8.write(dataStream, value.petitNombre);
+ FfiConverterU64.write(dataStream, value.grosNombre);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterTypeEnumeration.computeSize(value.un);
+ totalSize += FfiConverterBool.computeSize(value.deux);
+ totalSize += FfiConverterU8.computeSize(value.petitNombre);
+ totalSize += FfiConverterU64.computeSize(value.grosNombre);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterTypeEnumeration.checkType(value.un);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".un");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterBool.checkType(value.deux);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".deux");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU8.checkType(value.petitNombre);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".petitNombre");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU64.checkType(value.grosNombre);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".grosNombre");
+ }
+ throw e;
+ }
+ }
+}
+
+export class DictionnaireNombres {
+ constructor(petitNombre,courtNombre,nombreSimple,grosNombre) {
+ try {
+ FfiConverterU8.checkType(petitNombre)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("petitNombre");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU16.checkType(courtNombre)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("courtNombre");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU32.checkType(nombreSimple)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("nombreSimple");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU64.checkType(grosNombre)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("grosNombre");
+ }
+ throw e;
+ }
+ this.petitNombre = petitNombre;
+ this.courtNombre = courtNombre;
+ this.nombreSimple = nombreSimple;
+ this.grosNombre = grosNombre;
+ }
+ equals(other) {
+ return (
+ this.petitNombre == other.petitNombre &&
+ this.courtNombre == other.courtNombre &&
+ this.nombreSimple == other.nombreSimple &&
+ this.grosNombre == other.grosNombre
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeDictionnaireNombres extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new DictionnaireNombres(
+ FfiConverterU8.read(dataStream),
+ FfiConverterU16.read(dataStream),
+ FfiConverterU32.read(dataStream),
+ FfiConverterU64.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterU8.write(dataStream, value.petitNombre);
+ FfiConverterU16.write(dataStream, value.courtNombre);
+ FfiConverterU32.write(dataStream, value.nombreSimple);
+ FfiConverterU64.write(dataStream, value.grosNombre);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterU8.computeSize(value.petitNombre);
+ totalSize += FfiConverterU16.computeSize(value.courtNombre);
+ totalSize += FfiConverterU32.computeSize(value.nombreSimple);
+ totalSize += FfiConverterU64.computeSize(value.grosNombre);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterU8.checkType(value.petitNombre);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".petitNombre");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU16.checkType(value.courtNombre);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".courtNombre");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU32.checkType(value.nombreSimple);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".nombreSimple");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU64.checkType(value.grosNombre);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".grosNombre");
+ }
+ throw e;
+ }
+ }
+}
+
+export class DictionnaireNombresSignes {
+ constructor(petitNombre,courtNombre,nombreSimple,grosNombre) {
+ try {
+ FfiConverterI8.checkType(petitNombre)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("petitNombre");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI16.checkType(courtNombre)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("courtNombre");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI32.checkType(nombreSimple)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("nombreSimple");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI64.checkType(grosNombre)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("grosNombre");
+ }
+ throw e;
+ }
+ this.petitNombre = petitNombre;
+ this.courtNombre = courtNombre;
+ this.nombreSimple = nombreSimple;
+ this.grosNombre = grosNombre;
+ }
+ equals(other) {
+ return (
+ this.petitNombre == other.petitNombre &&
+ this.courtNombre == other.courtNombre &&
+ this.nombreSimple == other.nombreSimple &&
+ this.grosNombre == other.grosNombre
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeDictionnaireNombresSignes extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new DictionnaireNombresSignes(
+ FfiConverterI8.read(dataStream),
+ FfiConverterI16.read(dataStream),
+ FfiConverterI32.read(dataStream),
+ FfiConverterI64.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterI8.write(dataStream, value.petitNombre);
+ FfiConverterI16.write(dataStream, value.courtNombre);
+ FfiConverterI32.write(dataStream, value.nombreSimple);
+ FfiConverterI64.write(dataStream, value.grosNombre);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterI8.computeSize(value.petitNombre);
+ totalSize += FfiConverterI16.computeSize(value.courtNombre);
+ totalSize += FfiConverterI32.computeSize(value.nombreSimple);
+ totalSize += FfiConverterI64.computeSize(value.grosNombre);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterI8.checkType(value.petitNombre);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".petitNombre");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI16.checkType(value.courtNombre);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".courtNombre");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI32.checkType(value.nombreSimple);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".nombreSimple");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI64.checkType(value.grosNombre);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".grosNombre");
+ }
+ throw e;
+ }
+ }
+}
+
+export class OptionneurDictionnaire {
+ constructor(i8Var = -8,u8Var = 8,i16Var = -16,u16Var = 0x10,i32Var = -32,u32Var = 32,i64Var = -64,u64Var = 64,floatVar = 4.0,doubleVar = 8.0,booleanVar = true,stringVar = "default",listVar = [],enumerationVar = Enumeration.DEUX,dictionnaireVar = null) {
+ try {
+ FfiConverterI8.checkType(i8Var)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("i8Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU8.checkType(u8Var)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("u8Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI16.checkType(i16Var)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("i16Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU16.checkType(u16Var)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("u16Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI32.checkType(i32Var)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("i32Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU32.checkType(u32Var)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("u32Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI64.checkType(i64Var)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("i64Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU64.checkType(u64Var)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("u64Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterF32.checkType(floatVar)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("floatVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterF64.checkType(doubleVar)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("doubleVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterBool.checkType(booleanVar)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("booleanVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterString.checkType(stringVar)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("stringVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterSequencestring.checkType(listVar)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("listVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypeEnumeration.checkType(enumerationVar)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("enumerationVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterOptionalTypeminusculeMajusculeEnum.checkType(dictionnaireVar)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("dictionnaireVar");
+ }
+ throw e;
+ }
+ this.i8Var = i8Var;
+ this.u8Var = u8Var;
+ this.i16Var = i16Var;
+ this.u16Var = u16Var;
+ this.i32Var = i32Var;
+ this.u32Var = u32Var;
+ this.i64Var = i64Var;
+ this.u64Var = u64Var;
+ this.floatVar = floatVar;
+ this.doubleVar = doubleVar;
+ this.booleanVar = booleanVar;
+ this.stringVar = stringVar;
+ this.listVar = listVar;
+ this.enumerationVar = enumerationVar;
+ this.dictionnaireVar = dictionnaireVar;
+ }
+ equals(other) {
+ return (
+ this.i8Var == other.i8Var &&
+ this.u8Var == other.u8Var &&
+ this.i16Var == other.i16Var &&
+ this.u16Var == other.u16Var &&
+ this.i32Var == other.i32Var &&
+ this.u32Var == other.u32Var &&
+ this.i64Var == other.i64Var &&
+ this.u64Var == other.u64Var &&
+ this.floatVar == other.floatVar &&
+ this.doubleVar == other.doubleVar &&
+ this.booleanVar == other.booleanVar &&
+ this.stringVar == other.stringVar &&
+ this.listVar == other.listVar &&
+ this.enumerationVar == other.enumerationVar &&
+ this.dictionnaireVar == other.dictionnaireVar
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeOptionneurDictionnaire extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new OptionneurDictionnaire(
+ FfiConverterI8.read(dataStream),
+ FfiConverterU8.read(dataStream),
+ FfiConverterI16.read(dataStream),
+ FfiConverterU16.read(dataStream),
+ FfiConverterI32.read(dataStream),
+ FfiConverterU32.read(dataStream),
+ FfiConverterI64.read(dataStream),
+ FfiConverterU64.read(dataStream),
+ FfiConverterF32.read(dataStream),
+ FfiConverterF64.read(dataStream),
+ FfiConverterBool.read(dataStream),
+ FfiConverterString.read(dataStream),
+ FfiConverterSequencestring.read(dataStream),
+ FfiConverterTypeEnumeration.read(dataStream),
+ FfiConverterOptionalTypeminusculeMajusculeEnum.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterI8.write(dataStream, value.i8Var);
+ FfiConverterU8.write(dataStream, value.u8Var);
+ FfiConverterI16.write(dataStream, value.i16Var);
+ FfiConverterU16.write(dataStream, value.u16Var);
+ FfiConverterI32.write(dataStream, value.i32Var);
+ FfiConverterU32.write(dataStream, value.u32Var);
+ FfiConverterI64.write(dataStream, value.i64Var);
+ FfiConverterU64.write(dataStream, value.u64Var);
+ FfiConverterF32.write(dataStream, value.floatVar);
+ FfiConverterF64.write(dataStream, value.doubleVar);
+ FfiConverterBool.write(dataStream, value.booleanVar);
+ FfiConverterString.write(dataStream, value.stringVar);
+ FfiConverterSequencestring.write(dataStream, value.listVar);
+ FfiConverterTypeEnumeration.write(dataStream, value.enumerationVar);
+ FfiConverterOptionalTypeminusculeMajusculeEnum.write(dataStream, value.dictionnaireVar);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterI8.computeSize(value.i8Var);
+ totalSize += FfiConverterU8.computeSize(value.u8Var);
+ totalSize += FfiConverterI16.computeSize(value.i16Var);
+ totalSize += FfiConverterU16.computeSize(value.u16Var);
+ totalSize += FfiConverterI32.computeSize(value.i32Var);
+ totalSize += FfiConverterU32.computeSize(value.u32Var);
+ totalSize += FfiConverterI64.computeSize(value.i64Var);
+ totalSize += FfiConverterU64.computeSize(value.u64Var);
+ totalSize += FfiConverterF32.computeSize(value.floatVar);
+ totalSize += FfiConverterF64.computeSize(value.doubleVar);
+ totalSize += FfiConverterBool.computeSize(value.booleanVar);
+ totalSize += FfiConverterString.computeSize(value.stringVar);
+ totalSize += FfiConverterSequencestring.computeSize(value.listVar);
+ totalSize += FfiConverterTypeEnumeration.computeSize(value.enumerationVar);
+ totalSize += FfiConverterOptionalTypeminusculeMajusculeEnum.computeSize(value.dictionnaireVar);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterI8.checkType(value.i8Var);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".i8Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU8.checkType(value.u8Var);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".u8Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI16.checkType(value.i16Var);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".i16Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU16.checkType(value.u16Var);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".u16Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI32.checkType(value.i32Var);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".i32Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU32.checkType(value.u32Var);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".u32Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterI64.checkType(value.i64Var);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".i64Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterU64.checkType(value.u64Var);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".u64Var");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterF32.checkType(value.floatVar);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".floatVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterF64.checkType(value.doubleVar);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".doubleVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterBool.checkType(value.booleanVar);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".booleanVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterString.checkType(value.stringVar);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".stringVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterSequencestring.checkType(value.listVar);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".listVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypeEnumeration.checkType(value.enumerationVar);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".enumerationVar");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterOptionalTypeminusculeMajusculeEnum.checkType(value.dictionnaireVar);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".dictionnaireVar");
+ }
+ throw e;
+ }
+ }
+}
+
+export class MinusculeMajusculeDict {
+ constructor(minusculeMajusculeField) {
+ try {
+ FfiConverterBool.checkType(minusculeMajusculeField)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("minusculeMajusculeField");
+ }
+ throw e;
+ }
+ this.minusculeMajusculeField = minusculeMajusculeField;
+ }
+ equals(other) {
+ return (
+ this.minusculeMajusculeField == other.minusculeMajusculeField
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeminusculeMajusculeDict extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new MinusculeMajusculeDict(
+ FfiConverterBool.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterBool.write(dataStream, value.minusculeMajusculeField);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterBool.computeSize(value.minusculeMajusculeField);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterBool.checkType(value.minusculeMajusculeField);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".minusculeMajusculeField");
+ }
+ throw e;
+ }
+ }
+}
+
+export const Enumeration = {
+ UN: 1,
+ DEUX: 2,
+ TROIS: 3,
+};
+
+Object.freeze(Enumeration);
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeEnumeration extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ switch (dataStream.readInt32()) {
+ case 1:
+ return Enumeration.UN
+ case 2:
+ return Enumeration.DEUX
+ case 3:
+ return Enumeration.TROIS
+ default:
+ return new Error("Unknown Enumeration variant");
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === Enumeration.UN) {
+ dataStream.writeInt32(1);
+ return;
+ }
+ if (value === Enumeration.DEUX) {
+ dataStream.writeInt32(2);
+ return;
+ }
+ if (value === Enumeration.TROIS) {
+ dataStream.writeInt32(3);
+ return;
+ }
+ return new Error("Unknown Enumeration variant");
+ }
+
+ static computeSize(value) {
+ return 4;
+ }
+
+ static checkType(value) {
+ if (!Number.isInteger(value) || value < 1 || value > 3) {
+ throw new UniFFITypeError(`${value} is not a valid value for Enumeration`);
+ }
+ }
+}
+
+export class EnumerationAvecDonnees {}
+EnumerationAvecDonnees.Zero = class extends EnumerationAvecDonnees{
+ constructor(
+ ) {
+ super();
+ }
+}
+EnumerationAvecDonnees.Un = class extends EnumerationAvecDonnees{
+ constructor(
+ premier
+ ) {
+ super();
+ this.premier = premier;
+ }
+}
+EnumerationAvecDonnees.Deux = class extends EnumerationAvecDonnees{
+ constructor(
+ premier,
+ second
+ ) {
+ super();
+ this.premier = premier;
+ this.second = second;
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeEnumerationAvecDonnees extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ switch (dataStream.readInt32()) {
+ case 1:
+ return new EnumerationAvecDonnees.Zero(
+ );
+ case 2:
+ return new EnumerationAvecDonnees.Un(
+ FfiConverterU32.read(dataStream)
+ );
+ case 3:
+ return new EnumerationAvecDonnees.Deux(
+ FfiConverterU32.read(dataStream),
+ FfiConverterString.read(dataStream)
+ );
+ default:
+ return new Error("Unknown EnumerationAvecDonnees variant");
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value instanceof EnumerationAvecDonnees.Zero) {
+ dataStream.writeInt32(1);
+ return;
+ }
+ if (value instanceof EnumerationAvecDonnees.Un) {
+ dataStream.writeInt32(2);
+ FfiConverterU32.write(dataStream, value.premier);
+ return;
+ }
+ if (value instanceof EnumerationAvecDonnees.Deux) {
+ dataStream.writeInt32(3);
+ FfiConverterU32.write(dataStream, value.premier);
+ FfiConverterString.write(dataStream, value.second);
+ return;
+ }
+ return new Error("Unknown EnumerationAvecDonnees variant");
+ }
+
+ static computeSize(value) {
+ // Size of the Int indicating the variant
+ let totalSize = 4;
+ if (value instanceof EnumerationAvecDonnees.Zero) {
+ return totalSize;
+ }
+ if (value instanceof EnumerationAvecDonnees.Un) {
+ totalSize += FfiConverterU32.computeSize(value.premier);
+ return totalSize;
+ }
+ if (value instanceof EnumerationAvecDonnees.Deux) {
+ totalSize += FfiConverterU32.computeSize(value.premier);
+ totalSize += FfiConverterString.computeSize(value.second);
+ return totalSize;
+ }
+ return new Error("Unknown EnumerationAvecDonnees variant");
+ }
+
+ static checkType(value) {
+ if (!(value instanceof EnumerationAvecDonnees)) {
+ throw new UniFFITypeError(`${value} is not a subclass instance of EnumerationAvecDonnees`);
+ }
+ }
+}
+
+export const MinusculeMajusculeEnum = {
+ MINUSCULE_MAJUSCULE_VARIANT: 1,
+};
+
+Object.freeze(MinusculeMajusculeEnum);
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeminusculeMajusculeEnum extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ switch (dataStream.readInt32()) {
+ case 1:
+ return MinusculeMajusculeEnum.MINUSCULE_MAJUSCULE_VARIANT
+ default:
+ return new Error("Unknown MinusculeMajusculeEnum variant");
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === MinusculeMajusculeEnum.MINUSCULE_MAJUSCULE_VARIANT) {
+ dataStream.writeInt32(1);
+ return;
+ }
+ return new Error("Unknown MinusculeMajusculeEnum variant");
+ }
+
+ static computeSize(value) {
+ return 4;
+ }
+
+ static checkType(value) {
+ if (!Number.isInteger(value) || value < 1 || value > 1) {
+ throw new UniFFITypeError(`${value} is not a valid value for MinusculeMajusculeEnum`);
+ }
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterOptionali32 extends FfiConverterArrayBuffer {
+ static checkType(value) {
+ if (value !== undefined && value !== null) {
+ FfiConverterI32.checkType(value)
+ }
+ }
+
+ static read(dataStream) {
+ const code = dataStream.readUint8(0);
+ switch (code) {
+ case 0:
+ return null
+ case 1:
+ return FfiConverterI32.read(dataStream)
+ default:
+ throw UniFFIError(`Unexpected code: ${code}`);
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === null || value === undefined) {
+ dataStream.writeUint8(0);
+ return;
+ }
+ dataStream.writeUint8(1);
+ FfiConverterI32.write(dataStream, value)
+ }
+
+ static computeSize(value) {
+ if (value === null || value === undefined) {
+ return 1;
+ }
+ return 1 + FfiConverterI32.computeSize(value)
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterOptionalstring extends FfiConverterArrayBuffer {
+ static checkType(value) {
+ if (value !== undefined && value !== null) {
+ FfiConverterString.checkType(value)
+ }
+ }
+
+ static read(dataStream) {
+ const code = dataStream.readUint8(0);
+ switch (code) {
+ case 0:
+ return null
+ case 1:
+ return FfiConverterString.read(dataStream)
+ default:
+ throw UniFFIError(`Unexpected code: ${code}`);
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === null || value === undefined) {
+ dataStream.writeUint8(0);
+ return;
+ }
+ dataStream.writeUint8(1);
+ FfiConverterString.write(dataStream, value)
+ }
+
+ static computeSize(value) {
+ if (value === null || value === undefined) {
+ return 1;
+ }
+ return 1 + FfiConverterString.computeSize(value)
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterOptionalTypeminusculeMajusculeEnum extends FfiConverterArrayBuffer {
+ static checkType(value) {
+ if (value !== undefined && value !== null) {
+ FfiConverterTypeminusculeMajusculeEnum.checkType(value)
+ }
+ }
+
+ static read(dataStream) {
+ const code = dataStream.readUint8(0);
+ switch (code) {
+ case 0:
+ return null
+ case 1:
+ return FfiConverterTypeminusculeMajusculeEnum.read(dataStream)
+ default:
+ throw UniFFIError(`Unexpected code: ${code}`);
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === null || value === undefined) {
+ dataStream.writeUint8(0);
+ return;
+ }
+ dataStream.writeUint8(1);
+ FfiConverterTypeminusculeMajusculeEnum.write(dataStream, value)
+ }
+
+ static computeSize(value) {
+ if (value === null || value === undefined) {
+ return 1;
+ }
+ return 1 + FfiConverterTypeminusculeMajusculeEnum.computeSize(value)
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterSequencestring extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const arr = [];
+ for (let i = 0; i < len; i++) {
+ arr.push(FfiConverterString.read(dataStream));
+ }
+ return arr;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(value.length);
+ value.forEach((innerValue) => {
+ FfiConverterString.write(dataStream, innerValue);
+ })
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const innerValue of value) {
+ size += FfiConverterString.computeSize(innerValue);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ if (!Array.isArray(value)) {
+ throw new UniFFITypeError(`${value} is not an array`);
+ }
+ value.forEach((innerValue, idx) => {
+ try {
+ FfiConverterString.checkType(innerValue);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${idx}]`);
+ }
+ throw e;
+ }
+ })
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterSequenceTypeEnumeration extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const arr = [];
+ for (let i = 0; i < len; i++) {
+ arr.push(FfiConverterTypeEnumeration.read(dataStream));
+ }
+ return arr;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(value.length);
+ value.forEach((innerValue) => {
+ FfiConverterTypeEnumeration.write(dataStream, innerValue);
+ })
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const innerValue of value) {
+ size += FfiConverterTypeEnumeration.computeSize(innerValue);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ if (!Array.isArray(value)) {
+ throw new UniFFITypeError(`${value} is not an array`);
+ }
+ value.forEach((innerValue, idx) => {
+ try {
+ FfiConverterTypeEnumeration.checkType(innerValue);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${idx}]`);
+ }
+ throw e;
+ }
+ })
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterMapStringTypeEnumerationAvecDonnees extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const map = {};
+ for (let i = 0; i < len; i++) {
+ const key = FfiConverterString.read(dataStream);
+ const value = FfiConverterTypeEnumerationAvecDonnees.read(dataStream);
+ map[key] = value;
+ }
+
+ return map;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(Object.keys(value).length);
+ for (const key in value) {
+ FfiConverterString.write(dataStream, key);
+ FfiConverterTypeEnumerationAvecDonnees.write(dataStream, value[key]);
+ }
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const key in value) {
+ size += FfiConverterString.computeSize(key);
+ size += FfiConverterTypeEnumerationAvecDonnees.computeSize(value[key]);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ for (const key in value) {
+ try {
+ FfiConverterString.checkType(key);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("(key)");
+ }
+ throw e;
+ }
+
+ try {
+ FfiConverterTypeEnumerationAvecDonnees.checkType(value[key]);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${key}]`);
+ }
+ throw e;
+ }
+ }
+ }
+}
+
+
+
+
+
+export function copieDictionnaire(d) {
+
+ const liftResult = (result) => FfiConverterTypeDictionnaire.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypeDictionnaire.checkType(d)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("d");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 81, // rondpoint:rondpoint_7b7b_copie_dictionnaire
+ FfiConverterTypeDictionnaire.lower(d),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function copieEnumeration(e) {
+
+ const liftResult = (result) => FfiConverterTypeEnumeration.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypeEnumeration.checkType(e)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("e");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 82, // rondpoint:rondpoint_7b7b_copie_enumeration
+ FfiConverterTypeEnumeration.lower(e),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function copieEnumerations(e) {
+
+ const liftResult = (result) => FfiConverterSequenceTypeEnumeration.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterSequenceTypeEnumeration.checkType(e)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("e");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 83, // rondpoint:rondpoint_7b7b_copie_enumerations
+ FfiConverterSequenceTypeEnumeration.lower(e),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function copieCarte(c) {
+
+ const liftResult = (result) => FfiConverterMapStringTypeEnumerationAvecDonnees.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterMapStringTypeEnumerationAvecDonnees.checkType(c)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("c");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 84, // rondpoint:rondpoint_7b7b_copie_carte
+ FfiConverterMapStringTypeEnumerationAvecDonnees.lower(c),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function switcheroo(b) {
+
+ const liftResult = (result) => FfiConverterBool.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterBool.checkType(b)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("b");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 85, // rondpoint:rondpoint_7b7b_switcheroo
+ FfiConverterBool.lower(b),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustSprites.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustSprites.sys.mjs
new file mode 100644
index 0000000000..edb80ea246
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustSprites.sys.mjs
@@ -0,0 +1,681 @@
+// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
+// Trust me, you don't want to mess with it!
+
+import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs";
+
+
+
+// Objects intended to be used in the unit tests
+export var UnitTestObjs = {};
+
+// Write/Read data to/from an ArrayBuffer
+class ArrayBufferDataStream {
+ constructor(arrayBuffer) {
+ this.dataView = new DataView(arrayBuffer);
+ this.pos = 0;
+ }
+
+ readUint8() {
+ let rv = this.dataView.getUint8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeUint8(value) {
+ this.dataView.setUint8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readUint16() {
+ let rv = this.dataView.getUint16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeUint16(value) {
+ this.dataView.setUint16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readUint32() {
+ let rv = this.dataView.getUint32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeUint32(value) {
+ this.dataView.setUint32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readUint64() {
+ let rv = this.dataView.getBigUint64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeUint64(value) {
+ this.dataView.setBigUint64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+
+ readInt8() {
+ let rv = this.dataView.getInt8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeInt8(value) {
+ this.dataView.setInt8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readInt16() {
+ let rv = this.dataView.getInt16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeInt16(value) {
+ this.dataView.setInt16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readInt32() {
+ let rv = this.dataView.getInt32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeInt32(value) {
+ this.dataView.setInt32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readInt64() {
+ let rv = this.dataView.getBigInt64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeInt64(value) {
+ this.dataView.setBigInt64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+ readFloat32() {
+ let rv = this.dataView.getFloat32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeFloat32(value) {
+ this.dataView.setFloat32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readFloat64() {
+ let rv = this.dataView.getFloat64(this.pos);
+ this.pos += 8;
+ return rv;
+ }
+
+ writeFloat64(value) {
+ this.dataView.setFloat64(this.pos, value);
+ this.pos += 8;
+ }
+
+
+ writeString(value) {
+ const encoder = new TextEncoder();
+ // Note: in order to efficiently write this data, we first write the
+ // string data, reserving 4 bytes for the size.
+ const dest = new Uint8Array(this.dataView.buffer, this.pos + 4);
+ const encodeResult = encoder.encodeInto(value, dest);
+ if (encodeResult.read != value.length) {
+ throw new UniFFIError(
+ "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?"
+ );
+ }
+ const size = encodeResult.written;
+ // Next, go back and write the size before the string data
+ this.dataView.setUint32(this.pos, size);
+ // Finally, advance our position past both the size and string data
+ this.pos += size + 4;
+ }
+
+ readString() {
+ const decoder = new TextDecoder();
+ const size = this.readUint32();
+ const source = new Uint8Array(this.dataView.buffer, this.pos, size)
+ const value = decoder.decode(source);
+ this.pos += size;
+ return value;
+ }
+
+ // Reads a Sprite pointer from the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ readPointerSprite() {
+ const pointerId = 5; // sprites:Sprite
+ const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ return res;
+ }
+
+ // Writes a Sprite pointer into the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ writePointerSprite(value) {
+ const pointerId = 5; // sprites:Sprite
+ UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ }
+
+}
+
+function handleRustResult(result, liftCallback, liftErrCallback) {
+ switch (result.code) {
+ case "success":
+ return liftCallback(result.data);
+
+ case "error":
+ throw liftErrCallback(result.data);
+
+ case "internal-error":
+ let message = result.internalErrorMessage;
+ if (message) {
+ throw new UniFFIInternalError(message);
+ } else {
+ throw new UniFFIInternalError("Unknown error");
+ }
+
+ default:
+ throw new UniFFIError(`Unexpected status code: ${result.code}`);
+ }
+}
+
+class UniFFIError {
+ constructor(message) {
+ this.message = message;
+ }
+
+ toString() {
+ return `UniFFIError: ${this.message}`
+ }
+}
+
+class UniFFIInternalError extends UniFFIError {}
+
+// Base class for FFI converters
+class FfiConverter {
+ // throw `UniFFITypeError` if a value to be converted has an invalid type
+ static checkType(value) {
+ if (value === undefined ) {
+ throw new UniFFITypeError(`undefined`);
+ }
+ if (value === null ) {
+ throw new UniFFITypeError(`null`);
+ }
+ }
+}
+
+// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer
+class FfiConverterArrayBuffer extends FfiConverter {
+ static lift(buf) {
+ return this.read(new ArrayBufferDataStream(buf));
+ }
+
+ static lower(value) {
+ const buf = new ArrayBuffer(this.computeSize(value));
+ const dataStream = new ArrayBufferDataStream(buf);
+ this.write(dataStream, value);
+ return buf;
+ }
+}
+
+// Symbols that are used to ensure that Object constructors
+// can only be used with a proper UniFFI pointer
+const uniffiObjectPtr = Symbol("uniffiObjectPtr");
+const constructUniffiObject = Symbol("constructUniffiObject");
+UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr;
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterF64 extends FfiConverter {
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeFloat64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readFloat64()
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterString extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (typeof value !== "string") {
+ throw new UniFFITypeError(`${value} is not a string`);
+ }
+ }
+
+ static lift(buf) {
+ const decoder = new TextDecoder();
+ const utf8Arr = new Uint8Array(buf);
+ return decoder.decode(utf8Arr);
+ }
+ static lower(value) {
+ const encoder = new TextEncoder();
+ return encoder.encode(value).buffer;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeString(value);
+ }
+
+ static read(dataStream) {
+ return dataStream.readString();
+ }
+
+ static computeSize(value) {
+ const encoder = new TextEncoder();
+ return 4 + encoder.encode(value).length
+ }
+}
+
+export class Sprite {
+ // Use `init` to instantiate this class.
+ // DO NOT USE THIS CONSTRUCTOR DIRECTLY
+ constructor(opts) {
+ if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
+ throw new UniFFIError("Attempting to construct an object using the JavaScript constructor directly" +
+ "Please use a UDL defined constructor, or the init function for the primary constructor")
+ }
+ if (!opts[constructUniffiObject] instanceof UniFFIPointer) {
+ throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
+ }
+ this[uniffiObjectPtr] = opts[constructUniffiObject];
+ }
+ /**
+ * An async constructor for Sprite.
+ *
+ * @returns {Promise<Sprite>}: A promise that resolves
+ * to a newly constructed Sprite
+ */
+ static init(initialPosition) {
+ const liftResult = (result) => FfiConverterTypeSprite.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterOptionalTypePoint.checkType(initialPosition)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("initialPosition");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 86, // sprites:sprites_3c8d_Sprite_new
+ FfiConverterOptionalTypePoint.lower(initialPosition),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }}
+ /**
+ * An async constructor for Sprite.
+ *
+ * @returns {Promise<Sprite>}: A promise that resolves
+ * to a newly constructed Sprite
+ */
+ static newRelativeTo(reference,direction) {
+ const liftResult = (result) => FfiConverterTypeSprite.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypePoint.checkType(reference)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("reference");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypeVector.checkType(direction)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("direction");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 87, // sprites:sprites_3c8d_Sprite_new_relative_to
+ FfiConverterTypePoint.lower(reference),
+ FfiConverterTypeVector.lower(direction),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }}
+
+ getPosition() {
+ const liftResult = (result) => FfiConverterTypePoint.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 88, // sprites:sprites_3c8d_Sprite_get_position
+ FfiConverterTypeSprite.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ moveTo(position) {
+ const liftResult = (result) => undefined;
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypePoint.checkType(position)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("position");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 89, // sprites:sprites_3c8d_Sprite_move_to
+ FfiConverterTypeSprite.lower(this),
+ FfiConverterTypePoint.lower(position),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ moveBy(direction) {
+ const liftResult = (result) => undefined;
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypeVector.checkType(direction)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("direction");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 90, // sprites:sprites_3c8d_Sprite_move_by
+ FfiConverterTypeSprite.lower(this),
+ FfiConverterTypeVector.lower(direction),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeSprite extends FfiConverter {
+ static lift(value) {
+ const opts = {};
+ opts[constructUniffiObject] = value;
+ return new Sprite(opts);
+ }
+
+ static lower(value) {
+ return value[uniffiObjectPtr];
+ }
+
+ static read(dataStream) {
+ return this.lift(dataStream.readPointerSprite());
+ }
+
+ static write(dataStream, value) {
+ dataStream.writePointerSprite(value[uniffiObjectPtr]);
+ }
+
+ static computeSize(value) {
+ return 8;
+ }
+}
+
+export class Point {
+ constructor(x,y) {
+ try {
+ FfiConverterF64.checkType(x)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("x");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterF64.checkType(y)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("y");
+ }
+ throw e;
+ }
+ this.x = x;
+ this.y = y;
+ }
+ equals(other) {
+ return (
+ this.x == other.x &&
+ this.y == other.y
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypePoint extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new Point(
+ FfiConverterF64.read(dataStream),
+ FfiConverterF64.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterF64.write(dataStream, value.x);
+ FfiConverterF64.write(dataStream, value.y);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterF64.computeSize(value.x);
+ totalSize += FfiConverterF64.computeSize(value.y);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterF64.checkType(value.x);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".x");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterF64.checkType(value.y);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".y");
+ }
+ throw e;
+ }
+ }
+}
+
+export class Vector {
+ constructor(dx,dy) {
+ try {
+ FfiConverterF64.checkType(dx)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("dx");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterF64.checkType(dy)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("dy");
+ }
+ throw e;
+ }
+ this.dx = dx;
+ this.dy = dy;
+ }
+ equals(other) {
+ return (
+ this.dx == other.dx &&
+ this.dy == other.dy
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeVector extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new Vector(
+ FfiConverterF64.read(dataStream),
+ FfiConverterF64.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterF64.write(dataStream, value.dx);
+ FfiConverterF64.write(dataStream, value.dy);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterF64.computeSize(value.dx);
+ totalSize += FfiConverterF64.computeSize(value.dy);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterF64.checkType(value.dx);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".dx");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterF64.checkType(value.dy);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".dy");
+ }
+ throw e;
+ }
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterOptionalTypePoint extends FfiConverterArrayBuffer {
+ static checkType(value) {
+ if (value !== undefined && value !== null) {
+ FfiConverterTypePoint.checkType(value)
+ }
+ }
+
+ static read(dataStream) {
+ const code = dataStream.readUint8(0);
+ switch (code) {
+ case 0:
+ return null
+ case 1:
+ return FfiConverterTypePoint.read(dataStream)
+ default:
+ throw UniFFIError(`Unexpected code: ${code}`);
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === null || value === undefined) {
+ dataStream.writeUint8(0);
+ return;
+ }
+ dataStream.writeUint8(1);
+ FfiConverterTypePoint.write(dataStream, value)
+ }
+
+ static computeSize(value) {
+ if (value === null || value === undefined) {
+ return 1;
+ }
+ return 1 + FfiConverterTypePoint.computeSize(value)
+ }
+}
+
+
+
+
+
+export function translate(position,direction) {
+
+ const liftResult = (result) => FfiConverterTypePoint.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypePoint.checkType(position)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("position");
+ }
+ throw e;
+ }
+ try {
+ FfiConverterTypeVector.checkType(direction)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("direction");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 91, // sprites:sprites_3c8d_translate
+ FfiConverterTypePoint.lower(position),
+ FfiConverterTypeVector.lower(direction),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustTodolist.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustTodolist.sys.mjs
new file mode 100644
index 0000000000..f191cc7f6b
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustTodolist.sys.mjs
@@ -0,0 +1,925 @@
+// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
+// Trust me, you don't want to mess with it!
+
+import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs";
+
+
+
+// Objects intended to be used in the unit tests
+export var UnitTestObjs = {};
+
+// Write/Read data to/from an ArrayBuffer
+class ArrayBufferDataStream {
+ constructor(arrayBuffer) {
+ this.dataView = new DataView(arrayBuffer);
+ this.pos = 0;
+ }
+
+ readUint8() {
+ let rv = this.dataView.getUint8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeUint8(value) {
+ this.dataView.setUint8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readUint16() {
+ let rv = this.dataView.getUint16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeUint16(value) {
+ this.dataView.setUint16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readUint32() {
+ let rv = this.dataView.getUint32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeUint32(value) {
+ this.dataView.setUint32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readUint64() {
+ let rv = this.dataView.getBigUint64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeUint64(value) {
+ this.dataView.setBigUint64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+
+ readInt8() {
+ let rv = this.dataView.getInt8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeInt8(value) {
+ this.dataView.setInt8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readInt16() {
+ let rv = this.dataView.getInt16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeInt16(value) {
+ this.dataView.setInt16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readInt32() {
+ let rv = this.dataView.getInt32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeInt32(value) {
+ this.dataView.setInt32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readInt64() {
+ let rv = this.dataView.getBigInt64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeInt64(value) {
+ this.dataView.setBigInt64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+ readFloat32() {
+ let rv = this.dataView.getFloat32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeFloat32(value) {
+ this.dataView.setFloat32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readFloat64() {
+ let rv = this.dataView.getFloat64(this.pos);
+ this.pos += 8;
+ return rv;
+ }
+
+ writeFloat64(value) {
+ this.dataView.setFloat64(this.pos, value);
+ this.pos += 8;
+ }
+
+
+ writeString(value) {
+ const encoder = new TextEncoder();
+ // Note: in order to efficiently write this data, we first write the
+ // string data, reserving 4 bytes for the size.
+ const dest = new Uint8Array(this.dataView.buffer, this.pos + 4);
+ const encodeResult = encoder.encodeInto(value, dest);
+ if (encodeResult.read != value.length) {
+ throw new UniFFIError(
+ "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?"
+ );
+ }
+ const size = encodeResult.written;
+ // Next, go back and write the size before the string data
+ this.dataView.setUint32(this.pos, size);
+ // Finally, advance our position past both the size and string data
+ this.pos += size + 4;
+ }
+
+ readString() {
+ const decoder = new TextDecoder();
+ const size = this.readUint32();
+ const source = new Uint8Array(this.dataView.buffer, this.pos, size)
+ const value = decoder.decode(source);
+ this.pos += size;
+ return value;
+ }
+
+ // Reads a TodoList pointer from the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ readPointerTodoList() {
+ const pointerId = 6; // todolist:TodoList
+ const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ return res;
+ }
+
+ // Writes a TodoList pointer into the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ writePointerTodoList(value) {
+ const pointerId = 6; // todolist:TodoList
+ UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ }
+
+}
+
+function handleRustResult(result, liftCallback, liftErrCallback) {
+ switch (result.code) {
+ case "success":
+ return liftCallback(result.data);
+
+ case "error":
+ throw liftErrCallback(result.data);
+
+ case "internal-error":
+ let message = result.internalErrorMessage;
+ if (message) {
+ throw new UniFFIInternalError(message);
+ } else {
+ throw new UniFFIInternalError("Unknown error");
+ }
+
+ default:
+ throw new UniFFIError(`Unexpected status code: ${result.code}`);
+ }
+}
+
+class UniFFIError {
+ constructor(message) {
+ this.message = message;
+ }
+
+ toString() {
+ return `UniFFIError: ${this.message}`
+ }
+}
+
+class UniFFIInternalError extends UniFFIError {}
+
+// Base class for FFI converters
+class FfiConverter {
+ // throw `UniFFITypeError` if a value to be converted has an invalid type
+ static checkType(value) {
+ if (value === undefined ) {
+ throw new UniFFITypeError(`undefined`);
+ }
+ if (value === null ) {
+ throw new UniFFITypeError(`null`);
+ }
+ }
+}
+
+// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer
+class FfiConverterArrayBuffer extends FfiConverter {
+ static lift(buf) {
+ return this.read(new ArrayBufferDataStream(buf));
+ }
+
+ static lower(value) {
+ const buf = new ArrayBuffer(this.computeSize(value));
+ const dataStream = new ArrayBufferDataStream(buf);
+ this.write(dataStream, value);
+ return buf;
+ }
+}
+
+// Symbols that are used to ensure that Object constructors
+// can only be used with a proper UniFFI pointer
+const uniffiObjectPtr = Symbol("uniffiObjectPtr");
+const constructUniffiObject = Symbol("constructUniffiObject");
+UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr;
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterString extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (typeof value !== "string") {
+ throw new UniFFITypeError(`${value} is not a string`);
+ }
+ }
+
+ static lift(buf) {
+ const decoder = new TextDecoder();
+ const utf8Arr = new Uint8Array(buf);
+ return decoder.decode(utf8Arr);
+ }
+ static lower(value) {
+ const encoder = new TextEncoder();
+ return encoder.encode(value).buffer;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeString(value);
+ }
+
+ static read(dataStream) {
+ return dataStream.readString();
+ }
+
+ static computeSize(value) {
+ const encoder = new TextEncoder();
+ return 4 + encoder.encode(value).length
+ }
+}
+
+export class TodoList {
+ // Use `init` to instantiate this class.
+ // DO NOT USE THIS CONSTRUCTOR DIRECTLY
+ constructor(opts) {
+ if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
+ throw new UniFFIError("Attempting to construct an object using the JavaScript constructor directly" +
+ "Please use a UDL defined constructor, or the init function for the primary constructor")
+ }
+ if (!opts[constructUniffiObject] instanceof UniFFIPointer) {
+ throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
+ }
+ this[uniffiObjectPtr] = opts[constructUniffiObject];
+ }
+ /**
+ * An async constructor for TodoList.
+ *
+ * @returns {Promise<TodoList>}: A promise that resolves
+ * to a newly constructed TodoList
+ */
+ static init() {
+ const liftResult = (result) => FfiConverterTypeTodoList.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 92, // todolist:todolist_4b78_TodoList_new
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }}
+
+ addItem(todo) {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTodoError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterString.checkType(todo)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("todo");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 93, // todolist:todolist_4b78_TodoList_add_item
+ FfiConverterTypeTodoList.lower(this),
+ FfiConverterString.lower(todo),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ addEntry(entry) {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTodoError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterTypeTodoEntry.checkType(entry)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("entry");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 94, // todolist:todolist_4b78_TodoList_add_entry
+ FfiConverterTypeTodoList.lower(this),
+ FfiConverterTypeTodoEntry.lower(entry),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ getEntries() {
+ const liftResult = (result) => FfiConverterSequenceTypeTodoEntry.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 95, // todolist:todolist_4b78_TodoList_get_entries
+ FfiConverterTypeTodoList.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ getItems() {
+ const liftResult = (result) => FfiConverterSequencestring.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 96, // todolist:todolist_4b78_TodoList_get_items
+ FfiConverterTypeTodoList.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ addEntries(entries) {
+ const liftResult = (result) => undefined;
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterSequenceTypeTodoEntry.checkType(entries)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("entries");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 97, // todolist:todolist_4b78_TodoList_add_entries
+ FfiConverterTypeTodoList.lower(this),
+ FfiConverterSequenceTypeTodoEntry.lower(entries),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ addItems(items) {
+ const liftResult = (result) => undefined;
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterSequencestring.checkType(items)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("items");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 98, // todolist:todolist_4b78_TodoList_add_items
+ FfiConverterTypeTodoList.lower(this),
+ FfiConverterSequencestring.lower(items),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ getLastEntry() {
+ const liftResult = (result) => FfiConverterTypeTodoEntry.lift(result);
+ const liftError = (data) => FfiConverterTypeTodoError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 99, // todolist:todolist_4b78_TodoList_get_last_entry
+ FfiConverterTypeTodoList.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ getLast() {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = (data) => FfiConverterTypeTodoError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 100, // todolist:todolist_4b78_TodoList_get_last
+ FfiConverterTypeTodoList.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ getFirst() {
+ const liftResult = (result) => FfiConverterString.lift(result);
+ const liftError = (data) => FfiConverterTypeTodoError.lift(data);
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 101, // todolist:todolist_4b78_TodoList_get_first
+ FfiConverterTypeTodoList.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ clearItem(todo) {
+ const liftResult = (result) => undefined;
+ const liftError = (data) => FfiConverterTypeTodoError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterString.checkType(todo)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("todo");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 102, // todolist:todolist_4b78_TodoList_clear_item
+ FfiConverterTypeTodoList.lower(this),
+ FfiConverterString.lower(todo),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+ makeDefault() {
+ const liftResult = (result) => undefined;
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 103, // todolist:todolist_4b78_TodoList_make_default
+ FfiConverterTypeTodoList.lower(this),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ }
+
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeTodoList extends FfiConverter {
+ static lift(value) {
+ const opts = {};
+ opts[constructUniffiObject] = value;
+ return new TodoList(opts);
+ }
+
+ static lower(value) {
+ return value[uniffiObjectPtr];
+ }
+
+ static read(dataStream) {
+ return this.lift(dataStream.readPointerTodoList());
+ }
+
+ static write(dataStream, value) {
+ dataStream.writePointerTodoList(value[uniffiObjectPtr]);
+ }
+
+ static computeSize(value) {
+ return 8;
+ }
+}
+
+export class TodoEntry {
+ constructor(text) {
+ try {
+ FfiConverterString.checkType(text)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("text");
+ }
+ throw e;
+ }
+ this.text = text;
+ }
+ equals(other) {
+ return (
+ this.text == other.text
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeTodoEntry extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new TodoEntry(
+ FfiConverterString.read(dataStream)
+ );
+ }
+ static write(dataStream, value) {
+ FfiConverterString.write(dataStream, value.text);
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ totalSize += FfiConverterString.computeSize(value.text);
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ try {
+ FfiConverterString.checkType(value.text);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".text");
+ }
+ throw e;
+ }
+ }
+}
+
+
+
+export class TodoError extends Error {}
+
+
+export class TodoDoesNotExist extends TodoError {
+
+ constructor(message, ...params) {
+ super(...params);
+ this.message = message;
+ }
+ toString() {
+ return `TodoDoesNotExist: ${super.toString()}`
+ }
+}
+
+export class EmptyTodoList extends TodoError {
+
+ constructor(message, ...params) {
+ super(...params);
+ this.message = message;
+ }
+ toString() {
+ return `EmptyTodoList: ${super.toString()}`
+ }
+}
+
+export class DuplicateTodo extends TodoError {
+
+ constructor(message, ...params) {
+ super(...params);
+ this.message = message;
+ }
+ toString() {
+ return `DuplicateTodo: ${super.toString()}`
+ }
+}
+
+export class EmptyString extends TodoError {
+
+ constructor(message, ...params) {
+ super(...params);
+ this.message = message;
+ }
+ toString() {
+ return `EmptyString: ${super.toString()}`
+ }
+}
+
+export class DeligatedError extends TodoError {
+
+ constructor(message, ...params) {
+ super(...params);
+ this.message = message;
+ }
+ toString() {
+ return `DeligatedError: ${super.toString()}`
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterTypeTodoError extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ switch (dataStream.readInt32()) {
+ case 1:
+ return new TodoDoesNotExist(FfiConverterString.read(dataStream));
+ case 2:
+ return new EmptyTodoList(FfiConverterString.read(dataStream));
+ case 3:
+ return new DuplicateTodo(FfiConverterString.read(dataStream));
+ case 4:
+ return new EmptyString(FfiConverterString.read(dataStream));
+ case 5:
+ return new DeligatedError(FfiConverterString.read(dataStream));
+ default:
+ throw new Error("Unknown TodoError variant");
+ }
+ }
+ static computeSize(value) {
+ // Size of the Int indicating the variant
+ let totalSize = 4;
+ if (value instanceof TodoDoesNotExist) {
+ return totalSize;
+ }
+ if (value instanceof EmptyTodoList) {
+ return totalSize;
+ }
+ if (value instanceof DuplicateTodo) {
+ return totalSize;
+ }
+ if (value instanceof EmptyString) {
+ return totalSize;
+ }
+ if (value instanceof DeligatedError) {
+ return totalSize;
+ }
+ throw new Error("Unknown TodoError variant");
+ }
+ static write(dataStream, value) {
+ if (value instanceof TodoDoesNotExist) {
+ dataStream.writeInt32(1);
+ return;
+ }
+ if (value instanceof EmptyTodoList) {
+ dataStream.writeInt32(2);
+ return;
+ }
+ if (value instanceof DuplicateTodo) {
+ dataStream.writeInt32(3);
+ return;
+ }
+ if (value instanceof EmptyString) {
+ dataStream.writeInt32(4);
+ return;
+ }
+ if (value instanceof DeligatedError) {
+ dataStream.writeInt32(5);
+ return;
+ }
+ throw new Error("Unknown TodoError variant");
+ }
+
+ static errorClass = TodoError;
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterOptionalTypeTodoList extends FfiConverterArrayBuffer {
+ static checkType(value) {
+ if (value !== undefined && value !== null) {
+ FfiConverterTypeTodoList.checkType(value)
+ }
+ }
+
+ static read(dataStream) {
+ const code = dataStream.readUint8(0);
+ switch (code) {
+ case 0:
+ return null
+ case 1:
+ return FfiConverterTypeTodoList.read(dataStream)
+ default:
+ throw UniFFIError(`Unexpected code: ${code}`);
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === null || value === undefined) {
+ dataStream.writeUint8(0);
+ return;
+ }
+ dataStream.writeUint8(1);
+ FfiConverterTypeTodoList.write(dataStream, value)
+ }
+
+ static computeSize(value) {
+ if (value === null || value === undefined) {
+ return 1;
+ }
+ return 1 + FfiConverterTypeTodoList.computeSize(value)
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterSequencestring extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const arr = [];
+ for (let i = 0; i < len; i++) {
+ arr.push(FfiConverterString.read(dataStream));
+ }
+ return arr;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(value.length);
+ value.forEach((innerValue) => {
+ FfiConverterString.write(dataStream, innerValue);
+ })
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const innerValue of value) {
+ size += FfiConverterString.computeSize(innerValue);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ if (!Array.isArray(value)) {
+ throw new UniFFITypeError(`${value} is not an array`);
+ }
+ value.forEach((innerValue, idx) => {
+ try {
+ FfiConverterString.checkType(innerValue);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${idx}]`);
+ }
+ throw e;
+ }
+ })
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class FfiConverterSequenceTypeTodoEntry extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const arr = [];
+ for (let i = 0; i < len; i++) {
+ arr.push(FfiConverterTypeTodoEntry.read(dataStream));
+ }
+ return arr;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(value.length);
+ value.forEach((innerValue) => {
+ FfiConverterTypeTodoEntry.write(dataStream, innerValue);
+ })
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const innerValue of value) {
+ size += FfiConverterTypeTodoEntry.computeSize(innerValue);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ if (!Array.isArray(value)) {
+ throw new UniFFITypeError(`${value} is not an array`);
+ }
+ value.forEach((innerValue, idx) => {
+ try {
+ FfiConverterTypeTodoEntry.checkType(innerValue);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${idx}]`);
+ }
+ throw e;
+ }
+ })
+ }
+}
+
+
+
+
+
+export function getDefaultList() {
+
+ const liftResult = (result) => FfiConverterOptionalTypeTodoList.lift(result);
+ const liftError = null;
+ const functionCall = () => {
+ return UniFFIScaffolding.callAsync(
+ 104, // todolist:todolist_4b78_get_default_list
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function setDefaultList(list) {
+
+ const liftResult = (result) => undefined;
+ const liftError = null;
+ const functionCall = () => {
+ try {
+ FfiConverterTypeTodoList.checkType(list)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("list");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 105, // todolist:todolist_4b78_set_default_list
+ FfiConverterTypeTodoList.lower(list),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
+
+export function createEntryWith(todo) {
+
+ const liftResult = (result) => FfiConverterTypeTodoEntry.lift(result);
+ const liftError = (data) => FfiConverterTypeTodoError.lift(data);
+ const functionCall = () => {
+ try {
+ FfiConverterString.checkType(todo)
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("todo");
+ }
+ throw e;
+ }
+ return UniFFIScaffolding.callAsync(
+ 106, // todolist:todolist_4b78_create_entry_with
+ FfiConverterString.lower(todo),
+ )
+ }
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build
new file mode 100644
index 0000000000..704efd8a9d
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/moz.build
@@ -0,0 +1,24 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+FINAL_LIBRARY = "xul"
+
+components = [
+ "Arithmetic",
+ "CustomTypes",
+ "ExternalTypes",
+ "FixtureCallbacks",
+ "Geometry",
+ "Rondpoint",
+ "Sprites",
+ "Todolist",
+]
+
+EXTRA_JS_MODULES += [
+ "generated/Rust{}.sys.mjs".format(component) for component in components
+]
+
+XPCSHELL_TESTS_MANIFESTS += ["tests/xpcshell/xpcshell.ini"]
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_arithmetic.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_arithmetic.js
new file mode 100644
index 0000000000..a221abc39f
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_arithmetic.js
@@ -0,0 +1,48 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const Arithmetic = ChromeUtils.importESModule(
+ "resource://gre/modules/RustArithmetic.sys.mjs"
+);
+
+add_task(async function () {
+ Assert.ok(Arithmetic.IntegerOverflow);
+ Assert.equal(await Arithmetic.add(2, 4), 6);
+ Assert.equal(await Arithmetic.add(4, 8), 12);
+ // For other backends we would have this test:
+ // await Assert.rejects(
+ // Arithmetic.add(18446744073709551615, 1),
+ // Arithmetic.IntegerOverflow,
+ // "add() should throw IntegerOverflow")
+ //
+ // However, this doesn't work because JS number values are actually 64-bit
+ // floats, and that number is greater than the maximum "safe" integer.
+ //
+ // Instead, let's test that we reject numbers that are that big
+ await Assert.rejects(
+ Arithmetic.add(Number.MAX_SAFE_INTEGER + 1, 0),
+ /TypeError/,
+ "add() should throw TypeError when an input is > MAX_SAFE_INTEGER"
+ );
+
+ Assert.equal(await Arithmetic.sub(4, 2), 2);
+ Assert.equal(await Arithmetic.sub(8, 4), 4);
+ await Assert.rejects(
+ Arithmetic.sub(0, 1),
+ Arithmetic.IntegerOverflow,
+ "sub() should throw IntegerOverflow"
+ );
+
+ Assert.equal(await Arithmetic.div(8, 4), 2);
+ // Can't test this, because we don't allow Rust panics in FF
+ // Assert.rejects(
+ // Arithmetic.div(8, 0),
+ // (e) => Assert.equal(e, Arithmetic.UniFFIInternalError),
+ // "Divide by 0 should throw UniFFIInternalError")
+ //
+ Assert.ok(await Arithmetic.equal(2, 2));
+ Assert.ok(await Arithmetic.equal(4, 4));
+
+ Assert.ok(!(await Arithmetic.equal(2, 4)));
+ Assert.ok(!(await Arithmetic.equal(4, 8)));
+});
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_callbacks.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_callbacks.js
new file mode 100644
index 0000000000..67f0a167a8
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_callbacks.js
@@ -0,0 +1,47 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { logEvenNumbers, logEvenNumbersMainThread } = ChromeUtils.importESModule(
+ "resource://gre/modules/RustFixtureCallbacks.sys.mjs"
+);
+
+class Logger {
+ constructor() {
+ this.messages = [];
+ this.finishedPromise = new Promise((resolve, reject) => {
+ this.finishedResolve = resolve;
+ this.finishedReject = reject;
+ });
+ }
+
+ log(message) {
+ this.messages.push(message);
+ }
+
+ finished() {
+ this.finishedResolve(true);
+ }
+
+ async waitForFinish() {
+ // Set a timeout to avoid hanging the tests if the Rust code fails to call finished().
+ do_timeout(2000, () =>
+ this.finishedReject("Timeout waiting for finished()")
+ );
+ return this.finishedPromise;
+ }
+}
+
+add_task(async function testLogEvenNumbers() {
+ async function runTest(logEvenNumbersFunc) {
+ const logger = new Logger();
+ logEvenNumbersFunc(logger, [1, 1, 2, 3, 5, 8, 13]);
+ await logger.waitForFinish();
+ Assert.deepEqual(logger.messages, [
+ "Saw even number: 2",
+ "Saw even number: 8",
+ ]);
+ }
+
+ await runTest(logEvenNumbers);
+ await runTest(logEvenNumbersMainThread);
+});
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_custom_types.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_custom_types.js
new file mode 100644
index 0000000000..cd26467494
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_custom_types.js
@@ -0,0 +1,13 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const CustomTypes = ChromeUtils.importESModule(
+ "resource://gre/modules/RustCustomTypes.sys.mjs"
+);
+
+add_task(async function () {
+ // JS right now doesn't treat custom types as anything but it's native counterparts
+ let demo = await CustomTypes.getCustomTypesDemo();
+ Assert.equal(demo.url, "http://example.com/");
+ Assert.equal(demo.handle, 123);
+});
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_external_types.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_external_types.js
new file mode 100644
index 0000000000..e2f985cde7
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_external_types.js
@@ -0,0 +1,16 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const ExternalTypes = ChromeUtils.importESModule(
+ "resource://gre/modules/RustExternalTypes.sys.mjs"
+);
+
+add_task(async function () {
+ const line = new ExternalTypes.Line(
+ new ExternalTypes.Point(0, 0, "p1"),
+ new ExternalTypes.Point(2, 1, "p2")
+ );
+ Assert.equal(await ExternalTypes.gradient(line), 0.5);
+
+ Assert.equal(await ExternalTypes.gradient(null), 0.0);
+});
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_geometry.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_geometry.js
new file mode 100644
index 0000000000..f06ecd46aa
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_geometry.js
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const Geometry = ChromeUtils.importESModule(
+ "resource://gre/modules/RustGeometry.sys.mjs"
+);
+
+add_task(async function () {
+ const ln1 = new Geometry.Line(
+ new Geometry.Point(0, 0, "p1"),
+ new Geometry.Point(1, 2, "p2")
+ );
+ const ln2 = new Geometry.Line(
+ new Geometry.Point(1, 1, "p3"),
+ new Geometry.Point(2, 2, "p4")
+ );
+ const origin = new Geometry.Point(0, 0);
+ Assert.ok((await Geometry.intersection(ln1, ln2)).equals(origin));
+ Assert.deepEqual(await Geometry.intersection(ln1, ln2), origin);
+ Assert.strictEqual(await Geometry.intersection(ln1, ln1), null);
+});
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_rondpoint.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_rondpoint.js
new file mode 100644
index 0000000000..8c673b2e92
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_rondpoint.js
@@ -0,0 +1,311 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const Rondpoint = ChromeUtils.importESModule(
+ "resource://gre/modules/RustRondpoint.sys.mjs"
+);
+
+const {
+ Dictionnaire,
+ Enumeration,
+ copieDictionnaire,
+ copieEnumeration,
+ copieEnumerations,
+ copieCarte,
+ EnumerationAvecDonnees,
+ switcheroo,
+ Retourneur,
+ DictionnaireNombresSignes,
+ DictionnaireNombres,
+ Stringifier,
+ Optionneur,
+ OptionneurDictionnaire,
+} = Rondpoint;
+add_task(async function () {
+ const dico = new Dictionnaire(Enumeration.DEUX, true, 0, 1235);
+ const copyDico = await copieDictionnaire(dico);
+ Assert.deepEqual(dico, copyDico);
+
+ Assert.equal(await copieEnumeration(Enumeration.DEUX), Enumeration.DEUX);
+ Assert.deepEqual(
+ await copieEnumerations([Enumeration.UN, Enumeration.DEUX]),
+ [Enumeration.UN, Enumeration.DEUX]
+ );
+ const obj = {
+ 0: new EnumerationAvecDonnees.Zero(),
+ 1: new EnumerationAvecDonnees.Un(1),
+ 2: new EnumerationAvecDonnees.Deux(2, "deux"),
+ };
+
+ Assert.deepEqual(await copieCarte(obj), obj);
+
+ const zero = new EnumerationAvecDonnees.Zero();
+ const one = new EnumerationAvecDonnees.Un(1);
+ const two = new EnumerationAvecDonnees.Deux(2);
+ Assert.notEqual(zero, one);
+ Assert.notEqual(one, two);
+
+ Assert.deepEqual(zero, new EnumerationAvecDonnees.Zero());
+ Assert.deepEqual(one, new EnumerationAvecDonnees.Un(1));
+ Assert.notDeepEqual(one, new EnumerationAvecDonnees.Un(4));
+
+ Assert.ok(await switcheroo(false));
+ // Test the roundtrip across the FFI.
+ // This shows that the values we send come back in exactly the same state as we sent them.
+ // i.e. it shows that lowering from JS and lifting into rust is symmetrical with
+ // lowering from rust and lifting into JS.
+
+ const rt = await Retourneur.init();
+
+ const affirmAllerRetour = async (arr, fn, equalFn) => {
+ for (const member of arr) {
+ if (equalFn) {
+ equalFn(await fn(member), member);
+ } else {
+ Assert.equal(await fn(member), member);
+ }
+ }
+ };
+
+ // Booleans
+ await affirmAllerRetour([true, false], rt.identiqueBoolean.bind(rt));
+
+ // Bytes
+ await affirmAllerRetour([-128, 127], rt.identiqueI8.bind(rt));
+ await affirmAllerRetour([0, 0xff], rt.identiqueU8.bind(rt));
+
+ // Shorts
+ await affirmAllerRetour([-32768, 32767], rt.identiqueI16.bind(rt));
+ await affirmAllerRetour([0, 0xffff], rt.identiqueU16.bind(rt));
+
+ // Ints
+ await affirmAllerRetour(
+ [0, 1, -1, -2147483648, 2147483647],
+ rt.identiqueI32.bind(rt)
+ );
+ await affirmAllerRetour([0, 0xffffffff], rt.identiqueU32.bind(rt));
+
+ // Longs
+ // NOTE: we cannot represent greater than `Number.MAX_SAFE_INTEGER`
+ await affirmAllerRetour(
+ [0, 1, -1, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER],
+ rt.identiqueI64.bind(rt)
+ );
+ await affirmAllerRetour(
+ [0, Number.MAX_SAFE_INTEGER],
+ rt.identiqueU64.bind(rt)
+ );
+
+ // Floats
+ const equalFloats = (a, b) => Assert.ok(Math.abs(a - b) <= Number.EPSILON);
+ await affirmAllerRetour(
+ [0.0, 0.5, 0.25, 1.5],
+ rt.identiqueFloat.bind(rt),
+ equalFloats
+ );
+ // Some float value's precision gets messed up, an example is 3.22, 100.223, etc
+ // await affirmAllerRetour([0.0, 0.5, 0.25, 1.5, 100.223], rt.identiqueFloat.bind(rt), equalFloats);
+
+ // Double (although on the JS side doubles are limited since they are also represented by Number)
+ await affirmAllerRetour(
+ [0.0, 0.5, 0.25, 1.5],
+ rt.identiqueDouble.bind(rt),
+ equalFloats
+ );
+
+ // Strings
+ await affirmAllerRetour(
+ [
+ "",
+ "abc",
+ "null\u0000byte",
+ "été",
+ "ښي لاس ته لوستلو لوستل",
+ "😻emoji 👨‍👧‍👦multi-emoji, 🇨🇭a flag, a canal, panama",
+ ],
+ rt.identiqueString.bind(rt)
+ );
+
+ await affirmAllerRetour(
+ [-1, 0, 1].map(n => new DictionnaireNombresSignes(n, n, n, n)),
+ rt.identiqueNombresSignes.bind(rt),
+ (a, b) => Assert.deepEqual(a, b)
+ );
+
+ await affirmAllerRetour(
+ [0, 1].map(n => new DictionnaireNombres(n, n, n, n)),
+ rt.identiqueNombres.bind(rt),
+ (a, b) => Assert.deepEqual(a, b)
+ );
+
+ // Test one way across the FFI.
+ //
+ // We send one representation of a value to lib.rs, and it transforms it into another, a string.
+ // lib.rs sends the string back, and then we compare here in js.
+ //
+ // This shows that the values are transformed into strings the same way in both js and rust.
+ // i.e. if we assume that the string return works (we test this assumption elsewhere)
+ // we show that lowering from js and lifting into rust has values that both js and rust
+ // both stringify in the same way. i.e. the same values.
+ //
+ // If we roundtripping proves the symmetry of our lowering/lifting from here to rust, and lowering/lifting from rust to here,
+ // and this convinces us that lowering/lifting from here to rust is correct, then
+ // together, we've shown the correctness of the return leg.
+ const st = await Stringifier.init();
+
+ const affirmEnchaine = async (arr, fn) => {
+ for (const member of arr) {
+ Assert.equal(await fn(member), String(member));
+ }
+ };
+
+ // Booleans
+ await affirmEnchaine([true, false], st.toStringBoolean.bind(st));
+
+ // Bytes
+ await affirmEnchaine([-128, 127], st.toStringI8.bind(st));
+ await affirmEnchaine([0, 0xff], st.toStringU8.bind(st));
+
+ // Shorts
+ await affirmEnchaine([-32768, 32767], st.toStringI16.bind(st));
+ await affirmEnchaine([0, 0xffff], st.toStringU16.bind(st));
+
+ // Ints
+ await affirmEnchaine(
+ [0, 1, -1, -2147483648, 2147483647],
+ st.toStringI32.bind(st)
+ );
+ await affirmEnchaine([0, 0xffffffff], st.toStringU32.bind(st));
+
+ // Longs
+ // NOTE: we cannot represent greater than `Number.MAX_SAFE_INTEGER`
+ await affirmEnchaine(
+ [0, 1, -1, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER],
+ st.toStringI64.bind(st)
+ );
+ await affirmEnchaine([0, Number.MAX_SAFE_INTEGER], st.toStringU64.bind(st));
+
+ // Floats
+ await affirmEnchaine([0.0, 0.5, 0.25, 1.5], st.toStringFloat.bind(st));
+
+ // Doubles
+ await affirmEnchaine([0.0, 0.5, 0.25, 1.5], st.toStringDouble.bind(st));
+
+ // Prove to ourselves that default arguments are being used.
+ // Step 1: call the methods without arguments, and check against the UDL.
+ const op = await Optionneur.init();
+
+ Assert.equal(await op.sinonString(), "default");
+
+ Assert.ok(!(await op.sinonBoolean()));
+
+ Assert.deepEqual(await op.sinonSequence(), []);
+
+ Assert.equal(await op.sinonNull(), null);
+ Assert.equal(await op.sinonZero(), 0);
+
+ // decimal integers
+ Assert.equal(await op.sinonI8Dec(), -42);
+ Assert.equal(await op.sinonU8Dec(), 42);
+ Assert.equal(await op.sinonI16Dec(), 42);
+ Assert.equal(await op.sinonU16Dec(), 42);
+ Assert.equal(await op.sinonI32Dec(), 42);
+ Assert.equal(await op.sinonU32Dec(), 42);
+ Assert.equal(await op.sinonI64Dec(), 42);
+ Assert.equal(await op.sinonU64Dec(), 42);
+
+ // hexadecimal integers
+ Assert.equal(await op.sinonI8Hex(), -0x7f);
+ Assert.equal(await op.sinonU8Hex(), 0xff);
+ Assert.equal(await op.sinonI16Hex(), 0x7f);
+ Assert.equal(await op.sinonU16Hex(), 0xffff);
+ Assert.equal(await op.sinonI32Hex(), 0x7fffffff);
+ Assert.equal(await op.sinonU32Hex(), 0xffffffff);
+ // The following are too big to be represented by js `Number`
+ // Assert.equal(await op.sinonI64Hex(), 0x7fffffffffffffff);
+ // Assert.equal(await op.sinonU64Hex(), 0xffffffffffffffff);
+
+ // octal integers
+ Assert.equal(await op.sinonU32Oct(), 0o755);
+
+ // floats
+ Assert.equal(await op.sinonF32(), 42.0);
+ Assert.equal(await op.sinonF64(), 42.1);
+
+ // enums
+ Assert.equal(await op.sinonEnum(), Enumeration.TROIS);
+
+ // Step 2. Convince ourselves that if we pass something else, then that changes the output.
+ // We have shown something coming out of the sinon methods, but without eyeballing the Rust
+ // we can't be sure that the arguments will change the return value.
+
+ await affirmAllerRetour(["foo", "bar"], op.sinonString.bind(op));
+ await affirmAllerRetour([true, false], op.sinonBoolean.bind(op));
+ await affirmAllerRetour([["a", "b"], []], op.sinonSequence.bind(op), (a, b) =>
+ Assert.deepEqual(a, b)
+ );
+
+ // Optionals
+ await affirmAllerRetour(["0", "1"], op.sinonNull.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonZero.bind(op));
+
+ // integers
+ await affirmAllerRetour([0, 1], op.sinonU8Dec.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonI8Dec.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonU16Dec.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonI16Dec.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonU32Dec.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonI32Dec.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonU64Dec.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonI64Dec.bind(op));
+
+ await affirmAllerRetour([0, 1], op.sinonU8Hex.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonI8Hex.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonU16Hex.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonI16Hex.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonU32Hex.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonI32Hex.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonU64Hex.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonI64Hex.bind(op));
+ await affirmAllerRetour([0, 1], op.sinonU32Oct.bind(op));
+
+ // Floats
+ await affirmAllerRetour([0.0, 1.0], op.sinonF32.bind(op));
+ await affirmAllerRetour([0.0, 1.0], op.sinonF64.bind(op));
+
+ // enums
+ await affirmAllerRetour(
+ [Enumeration.UN, Enumeration.DEUX, Enumeration.TROIS],
+ op.sinonEnum.bind(op)
+ );
+
+ // Testing defaulting properties in record types.
+ const defaultes = new OptionneurDictionnaire();
+ const explicite = new OptionneurDictionnaire(
+ -8,
+ 8,
+ -16,
+ 0x10,
+ -32,
+ 32,
+ -64,
+ 64,
+ 4.0,
+ 8.0,
+ true,
+ "default",
+ [],
+ Enumeration.DEUX,
+ null
+ );
+
+ Assert.deepEqual(defaultes, explicite);
+
+ // …and makes sure they travel across and back the FFI.
+
+ await affirmAllerRetour(
+ [defaultes, explicite],
+ rt.identiqueOptionneurDictionnaire.bind(rt),
+ (a, b) => Assert.deepEqual(a, b)
+ );
+});
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_sprites.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_sprites.js
new file mode 100644
index 0000000000..3feb2fd34d
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_sprites.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const Sprites = ChromeUtils.importESModule(
+ "resource://gre/modules/RustSprites.sys.mjs"
+);
+
+add_task(async function () {
+ Assert.ok(Sprites.Sprite);
+
+ const sempty = await Sprites.Sprite.init(null);
+ Assert.deepEqual(await sempty.getPosition(), new Sprites.Point(0, 0));
+
+ const s = await Sprites.Sprite.init(new Sprites.Point(0, 1));
+ Assert.deepEqual(await s.getPosition(), new Sprites.Point(0, 1));
+
+ s.moveTo(new Sprites.Point(1, 2));
+ Assert.deepEqual(await s.getPosition(), new Sprites.Point(1, 2));
+
+ s.moveBy(new Sprites.Vector(-4, 2));
+ Assert.deepEqual(await s.getPosition(), new Sprites.Point(-3, 4));
+
+ const srel = await Sprites.Sprite.newRelativeTo(
+ new Sprites.Point(0, 1),
+ new Sprites.Vector(1, 1.5)
+ );
+ Assert.deepEqual(await srel.getPosition(), new Sprites.Point(1, 2.5));
+});
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_todolist.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_todolist.js
new file mode 100644
index 0000000000..dac26d2be1
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_todolist.js
@@ -0,0 +1,71 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const { TodoList, TodoEntry, getDefaultList, setDefaultList } =
+ ChromeUtils.importESModule("resource://gre/modules/RustTodolist.sys.mjs");
+
+add_task(async function () {
+ const todo = await TodoList.init();
+ const entry = new TodoEntry("Write bindings for strings in records");
+
+ await todo.addItem("Write JS bindings");
+ Assert.equal(await todo.getLast(), "Write JS bindings");
+
+ await todo.addItem("Write tests for bindings");
+ Assert.equal(await todo.getLast(), "Write tests for bindings");
+
+ await todo.addEntry(entry);
+ Assert.equal(await todo.getLast(), "Write bindings for strings in records");
+ Assert.equal(
+ (await todo.getLastEntry()).text,
+ "Write bindings for strings in records"
+ );
+ Assert.ok((await todo.getLastEntry()).equals(entry));
+
+ await todo.addItem(
+ "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣"
+ );
+ Assert.equal(
+ await todo.getLast(),
+ "Test Ünicode hàndling without an entry can't believe I didn't test this at first 🤣"
+ );
+
+ const entry2 = new TodoEntry(
+ "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣"
+ );
+ await todo.addEntry(entry2);
+ Assert.equal(
+ (await todo.getLastEntry()).text,
+ "Test Ünicode hàndling in an entry can't believe I didn't test this at first 🤣"
+ );
+
+ const todo2 = await TodoList.init();
+ Assert.notEqual(todo, todo2);
+ Assert.notStrictEqual(todo, todo2);
+
+ Assert.strictEqual(await getDefaultList(), null);
+
+ await setDefaultList(todo);
+ Assert.deepEqual(
+ await todo.getItems(),
+ await (await getDefaultList()).getItems()
+ );
+
+ todo2.makeDefault();
+ Assert.deepEqual(
+ await todo2.getItems(),
+ await (await getDefaultList()).getItems()
+ );
+
+ await todo.addItem("Test liveness after being demoted from default");
+ Assert.equal(
+ await todo.getLast(),
+ "Test liveness after being demoted from default"
+ );
+
+ todo2.addItem("Test shared state through local vs default reference");
+ Assert.equal(
+ await (await getDefaultList()).getLast(),
+ "Test shared state through local vs default reference"
+ );
+});
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_type_checking.js b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_type_checking.js
new file mode 100644
index 0000000000..bfeb07c82b
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_type_checking.js
@@ -0,0 +1,123 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const Arithmetic = ChromeUtils.importESModule(
+ "resource://gre/modules/RustArithmetic.sys.mjs"
+);
+const Geometry = ChromeUtils.importESModule(
+ "resource://gre/modules/RustGeometry.sys.mjs"
+);
+const TodoList = ChromeUtils.importESModule(
+ "resource://gre/modules/RustTodolist.sys.mjs"
+);
+const Rondpoint = ChromeUtils.importESModule(
+ "resource://gre/modules/RustRondpoint.sys.mjs"
+);
+const { UniFFITypeError } = ChromeUtils.importESModule(
+ "resource://gre/modules/UniFFI.sys.mjs"
+);
+
+add_task(async function testFunctionArguments() {
+ await Assert.rejects(
+ Arithmetic.add(2),
+ UniFFITypeError,
+ "add() call missing argument"
+ );
+ Assert.throws(
+ () => new Geometry.Point(0.0),
+ UniFFITypeError,
+ "Point constructor missing argument"
+ );
+});
+
+add_task(async function testObjectPointers() {
+ const todo = await TodoList.TodoList.init();
+ const stringifier = await Rondpoint.Stringifier.init();
+ await todo.getEntries(); // OK
+ todo[TodoList.UnitTestObjs.uniffiObjectPtr] =
+ stringifier[Rondpoint.UnitTestObjs.uniffiObjectPtr];
+
+ await Assert.rejects(
+ todo.getEntries(), // the pointer is incorrect, should throw
+ /Bad pointer type/,
+ "getEntries() with wrong pointer type"
+ );
+});
+
+add_task(async function testEnumTypeCheck() {
+ await Assert.rejects(
+ Rondpoint.copieEnumeration("invalid"), // Not an integer value
+ /e:/, // Ensure exception message includes the argument name
+ "copieEnumeration() with non-Enumeration value should throw"
+ );
+ await Assert.rejects(
+ Rondpoint.copieEnumeration(0), // Integer, but doesn't map to a variant
+ /e:/, // Ensure exception message includes the argument name
+ "copieEnumeration() with non-Enumeration value should throw"
+ );
+ await Assert.rejects(
+ Rondpoint.copieEnumeration(4), // Integer, but doesn't map to a variant
+ /e:/, // Ensure exception message includes the argument name
+ "copieEnumeration() with non-Enumeration value should throw"
+ );
+});
+
+add_task(async function testRecordTypeCheck() {
+ await Assert.rejects(
+ Geometry.gradient(123), // Not a Line object
+ UniFFITypeError,
+ "gradient with non-Line object should throw"
+ );
+
+ await Assert.rejects(
+ Geometry.gradient({
+ start: {
+ coordX: 0.0,
+ coordY: 0.0,
+ },
+ // missing the end field
+ }),
+ /ln.end/, // Ensure exception message includes the argument name
+ "gradient with Line object with missing end field should throw"
+ );
+});
+
+add_task(async function testOptionTypeCheck() {
+ const optionneur = await Rondpoint.Optionneur.init();
+ await Assert.rejects(
+ optionneur.sinonNull(0),
+ UniFFITypeError,
+ "sinonNull with non-string should throw"
+ );
+});
+
+add_task(async function testSequenceTypeCheck() {
+ const todo = await TodoList.TodoList.init();
+ await Assert.rejects(
+ todo.addEntries("not a list"),
+ UniFFITypeError,
+ "addEntries with non-list should throw"
+ );
+
+ await Assert.rejects(
+ todo.addEntries(["not TodoEntry"]),
+ /entries\[0]/,
+ "addEntries with non TodoEntry item should throw"
+ );
+});
+
+add_task(async function testMapTypeCheck() {
+ await Assert.rejects(
+ Rondpoint.copieCarte("not a map"),
+ UniFFITypeError,
+ "copieCarte with a non-map should throw"
+ );
+
+ await Assert.rejects(
+ Rondpoint.copieCarte({ x: 1 }),
+ /c\[x]/,
+ "copieCarte with a wrong value type should throw"
+ );
+
+ // TODO: test key types once we implement https://bugzilla.mozilla.org/show_bug.cgi?id=1809459
+});
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.ini b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.ini
new file mode 100644
index 0000000000..87d2b43489
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.ini
@@ -0,0 +1,9 @@
+[test_arithmetic.js]
+[test_callbacks.js]
+[test_geometry.js]
+[test_rondpoint.js]
+[test_sprites.js]
+[test_todolist.js]
+[test_type_checking.js]
+[test_custom_types.js]
+[test_external_types.js]
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/mach_commands.py b/toolkit/components/uniffi-bindgen-gecko-js/mach_commands.py
new file mode 100644
index 0000000000..68c2c3d58b
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/mach_commands.py
@@ -0,0 +1,92 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+import os
+import subprocess
+
+from mach.decorators import Command, SubCommand
+
+# IMPORTANT: Please Request review from a DOM peer before
+# committing to using UniFFI. There are other ways to consume Rust from
+# JavaScript that might fit your use case better.
+UDL_FILES = [
+ "third_party/rust/tabs/src/tabs.udl",
+]
+
+FIXTURE_UDL_FILES = [
+ "third_party/rust/uniffi-example-geometry/src/geometry.udl",
+ "third_party/rust/uniffi-example-arithmetic/src/arithmetic.udl",
+ "third_party/rust/uniffi-example-rondpoint/src/rondpoint.udl",
+ "third_party/rust/uniffi-example-sprites/src/sprites.udl",
+ "third_party/rust/uniffi-example-todolist/src/todolist.udl",
+ "toolkit/components/uniffi-fixture-callbacks/src/callbacks.udl",
+ "toolkit/components/uniffi-example-custom-types/src/custom-types.udl",
+ "toolkit/components/uniffi-fixture-external-types/src/external-types.udl",
+]
+CPP_PATH = "toolkit/components/uniffi-js/UniFFIGeneratedScaffolding.cpp"
+JS_DIR = "toolkit/components/uniffi-bindgen-gecko-js/components/generated"
+FIXTURE_CPP_PATH = "toolkit/components/uniffi-js/UniFFIFixtureScaffolding.cpp"
+FIXTURE_JS_DIR = "toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated"
+
+
+def build_uniffi_bindgen_gecko_js(command_context):
+ uniffi_root = crate_root(command_context)
+ print("Building uniffi-bindgen-gecko-js")
+ cmdline = [
+ "cargo",
+ "build",
+ "--release",
+ "--manifest-path",
+ os.path.join(command_context.topsrcdir, "Cargo.toml"),
+ "--package",
+ "uniffi-bindgen-gecko-js",
+ ]
+ subprocess.check_call(cmdline, cwd=uniffi_root)
+ print()
+ return os.path.join(
+ command_context.topsrcdir, "target", "release", "uniffi-bindgen-gecko-js"
+ )
+
+
+@Command(
+ "uniffi",
+ category="devenv",
+ description="Generate JS bindings using uniffi-bindgen-gecko-js",
+)
+def uniffi(command_context, *runargs, **lintargs):
+ """Run uniffi."""
+ command_context._sub_mach(["help", "uniffi"])
+ return 1
+
+
+@SubCommand(
+ "uniffi",
+ "generate",
+ description="Generate/regenerate bindings",
+)
+def generate_command(command_context):
+ binary_path = build_uniffi_bindgen_gecko_js(command_context)
+ cmdline = [
+ binary_path,
+ "--js-dir",
+ JS_DIR,
+ "--fixture-js-dir",
+ FIXTURE_JS_DIR,
+ "--cpp-path",
+ CPP_PATH,
+ "--fixture-cpp-path",
+ FIXTURE_CPP_PATH,
+ ]
+ if UDL_FILES:
+ cmdline += ["--udl-files"] + UDL_FILES
+ if FIXTURE_UDL_FILES:
+ cmdline += ["--fixture-udl-files"] + FIXTURE_UDL_FILES
+ subprocess.check_call(cmdline, cwd=command_context.topsrcdir)
+ return 0
+
+
+def crate_root(command_context):
+ return os.path.join(
+ command_context.topsrcdir, "toolkit", "components", "uniffi-bindgen-gecko-js"
+ )
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/ci_list.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/ci_list.rs
new file mode 100644
index 0000000000..8a6603aa7d
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/ci_list.rs
@@ -0,0 +1,193 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//! Manage the universe of ComponentInterfaces / Configs
+//!
+//! uniffi-bindgen-gecko-js is unique because it generates bindings over a set of UDL files rather
+//! than just one. This is because we want to generate the WebIDL statically rather than generate
+//! it. To accomplish that, each WebIDL function inputs an opaque integer id that identifies which
+//! version of it should run, for example `CallSync` inputs a function id. Operating on all UDL
+//! files at once simplifies the task of ensuring those ids are to be unique and consistent between
+//! the JS and c++ code.
+//!
+//! This module manages the list of ComponentInterface and the object ids.
+
+use crate::render::cpp::ComponentInterfaceCppExt;
+use crate::{Config, ConfigMap};
+use anyhow::{bail, Context, Result};
+use camino::Utf8PathBuf;
+use std::collections::{BTreeSet, HashMap, HashSet};
+use uniffi_bindgen::interface::{CallbackInterface, ComponentInterface, FfiFunction, Object};
+
+pub struct ComponentUniverse {
+ pub components: Vec<(ComponentInterface, Config)>,
+ pub fixture_components: Vec<(ComponentInterface, Config)>,
+}
+
+impl ComponentUniverse {
+ pub fn new(
+ udl_files: Vec<Utf8PathBuf>,
+ fixture_udl_files: Vec<Utf8PathBuf>,
+ config_map: ConfigMap,
+ ) -> Result<Self> {
+ let components = udl_files
+ .into_iter()
+ .map(|udl_file| parse_udl_file(udl_file, &config_map))
+ .collect::<Result<Vec<_>>>()?;
+ let fixture_components = fixture_udl_files
+ .into_iter()
+ .map(|udl_file| parse_udl_file(udl_file, &config_map))
+ .collect::<Result<Vec<_>>>()?;
+ let universe = Self {
+ components,
+ fixture_components,
+ };
+ universe.check_udl_namespaces_unique()?;
+ universe.check_callback_interfaces()?;
+ Ok(universe)
+ }
+
+ fn check_udl_namespaces_unique(&self) -> Result<()> {
+ let mut set = HashSet::new();
+ for ci in self.iter_cis() {
+ if !set.insert(ci.namespace()) {
+ bail!("UDL files have duplicate namespace: {}", ci.namespace());
+ }
+ }
+ Ok(())
+ }
+
+ fn check_callback_interfaces(&self) -> Result<()> {
+ // We don't currently support callback interfaces returning values or throwing errors.
+ for ci in self.iter_cis() {
+ for cbi in ci.callback_interface_definitions() {
+ for method in cbi.methods() {
+ if method.return_type().is_some() {
+ bail!("Callback interface method {}.{} throws an error, which is not yet supported", cbi.name(), method.name())
+ }
+ if method.throws_type().is_some() {
+ bail!("Callback interface method {}.{} returns a value, which is not yet supported", cbi.name(), method.name())
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+
+ pub fn iter_cis(&self) -> impl Iterator<Item = &ComponentInterface> {
+ self.components
+ .iter()
+ .chain(self.fixture_components.iter())
+ .map(|(ci, _)| ci)
+ }
+}
+
+fn parse_udl_file(
+ udl_file: Utf8PathBuf,
+ config_map: &ConfigMap,
+) -> Result<(ComponentInterface, Config)> {
+ let udl = std::fs::read_to_string(&udl_file).context("Error reading UDL file")?;
+ let ci = ComponentInterface::from_webidl(&udl).context("Failed to parse UDL")?;
+ let config = config_map.get(ci.namespace()).cloned().unwrap_or_default();
+ Ok((ci, config))
+}
+
+pub struct FunctionIds<'a> {
+ // Map (CI namespace, func name) -> Ids
+ map: HashMap<(&'a str, &'a str), usize>,
+}
+
+impl<'a> FunctionIds<'a> {
+ pub fn new(cis: &'a ComponentUniverse) -> Self {
+ Self {
+ map: cis
+ .iter_cis()
+ .flat_map(|ci| {
+ ci.exposed_functions()
+ .into_iter()
+ .map(move |f| (ci.namespace(), f.name()))
+ })
+ .enumerate()
+ .map(|(i, (namespace, name))| ((namespace, name), i))
+ // Sort using BTreeSet to guarantee the IDs remain stable across runs
+ .collect::<BTreeSet<_>>()
+ .into_iter()
+ .collect(),
+ }
+ }
+
+ pub fn get(&self, ci: &ComponentInterface, func: &FfiFunction) -> usize {
+ return *self.map.get(&(ci.namespace(), func.name())).unwrap();
+ }
+
+ pub fn name(&self, ci: &ComponentInterface, func: &FfiFunction) -> String {
+ format!("{}:{}", ci.namespace(), func.name())
+ }
+}
+
+pub struct ObjectIds<'a> {
+ // Map (CI namespace, object name) -> Ids
+ map: HashMap<(&'a str, &'a str), usize>,
+}
+
+impl<'a> ObjectIds<'a> {
+ pub fn new(cis: &'a ComponentUniverse) -> Self {
+ Self {
+ map: cis
+ .iter_cis()
+ .flat_map(|ci| {
+ ci.object_definitions()
+ .iter()
+ .map(move |o| (ci.namespace(), o.name()))
+ })
+ .enumerate()
+ .map(|(i, (namespace, name))| ((namespace, name), i))
+ // Sort using BTreeSet to guarantee the IDs remain stable across runs
+ .collect::<BTreeSet<_>>()
+ .into_iter()
+ .collect(),
+ }
+ }
+
+ pub fn get(&self, ci: &ComponentInterface, obj: &Object) -> usize {
+ return *self.map.get(&(ci.namespace(), obj.name())).unwrap();
+ }
+
+ pub fn name(&self, ci: &ComponentInterface, obj: &Object) -> String {
+ format!("{}:{}", ci.namespace(), obj.name())
+ }
+}
+
+pub struct CallbackIds<'a> {
+ // Map (CI namespace, callback name) -> Ids
+ map: HashMap<(&'a str, &'a str), usize>,
+}
+
+impl<'a> CallbackIds<'a> {
+ pub fn new(cis: &'a ComponentUniverse) -> Self {
+ Self {
+ map: cis
+ .iter_cis()
+ .flat_map(|ci| {
+ ci.callback_interface_definitions()
+ .iter()
+ .map(move |cb| (ci.namespace(), cb.name()))
+ })
+ .enumerate()
+ .map(|(i, (namespace, name))| ((namespace, name), i))
+ // Sort using BTreeSet to guarantee the IDs remain stable across runs
+ .collect::<BTreeSet<_>>()
+ .into_iter()
+ .collect(),
+ }
+ }
+
+ pub fn get(&self, ci: &ComponentInterface, cb: &CallbackInterface) -> usize {
+ return *self.map.get(&(ci.namespace(), cb.name())).unwrap();
+ }
+
+ pub fn name(&self, ci: &ComponentInterface, cb: &CallbackInterface) -> String {
+ format!("{}:{}", ci.namespace(), cb.name())
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/lib.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/lib.rs
new file mode 100644
index 0000000000..965ead26db
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/lib.rs
@@ -0,0 +1,158 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use anyhow::{Context, Result};
+use askama::Template;
+use camino::Utf8PathBuf;
+use clap::Parser;
+use serde::{Deserialize, Serialize};
+use std::collections::{HashMap, HashSet};
+use std::fs::File;
+use std::io::Write;
+use uniffi_bindgen::ComponentInterface;
+
+mod ci_list;
+mod render;
+
+use ci_list::{CallbackIds, ComponentUniverse, FunctionIds, ObjectIds};
+use render::cpp::CPPScaffoldingTemplate;
+use render::js::JSBindingsTemplate;
+
+#[derive(Debug, Parser)]
+#[clap(name = "uniffi-bindgen-gecko-js")]
+#[clap(version = clap::crate_version!())]
+#[clap(about = "JS bindings generator for Rust")]
+#[clap(propagate_version = true)]
+struct CliArgs {
+ // This is a really convoluted set of arguments, but we're only expecting to be called by
+ // `mach_commands.py`
+ #[clap(long, value_name = "FILE")]
+ js_dir: Utf8PathBuf,
+
+ #[clap(long, value_name = "FILE")]
+ fixture_js_dir: Utf8PathBuf,
+
+ #[clap(long, value_name = "FILE")]
+ cpp_path: Utf8PathBuf,
+
+ #[clap(long, value_name = "FILE")]
+ fixture_cpp_path: Utf8PathBuf,
+
+ #[clap(long, multiple_values = true, value_name = "FILES")]
+ udl_files: Vec<Utf8PathBuf>,
+
+ #[clap(long, multiple_values = true, value_name = "FILES")]
+ fixture_udl_files: Vec<Utf8PathBuf>,
+}
+
+/// Configuration for all components, read from `uniffi.toml`
+type ConfigMap = HashMap<String, Config>;
+
+/// Configuration for a single Component
+#[derive(Clone, Debug, Default, Deserialize, Serialize)]
+pub struct Config {
+ receiver_thread: ReceiverThreadConfig,
+}
+
+#[derive(Clone, Debug, Default, Deserialize, Serialize)]
+struct ReceiverThreadConfig {
+ #[serde(default)]
+ default: Option<String>,
+ #[serde(default)]
+ main: HashSet<String>,
+ #[serde(default)]
+ worker: HashSet<String>,
+}
+
+fn render(out_path: Utf8PathBuf, template: impl Template) -> Result<()> {
+ println!("rendering {}", out_path);
+ let contents = template.render()?;
+ let mut f =
+ File::create(&out_path).context(format!("Failed to create {:?}", out_path.file_name()))?;
+ write!(f, "{}\n", contents).context(format!("Failed to write to {}", out_path))
+}
+
+fn render_cpp(
+ path: Utf8PathBuf,
+ prefix: &str,
+ components: &Vec<(ComponentInterface, Config)>,
+ function_ids: &FunctionIds,
+ object_ids: &ObjectIds,
+ callback_ids: &CallbackIds,
+) -> Result<()> {
+ render(
+ path,
+ CPPScaffoldingTemplate {
+ prefix,
+ components,
+ function_ids,
+ object_ids,
+ callback_ids,
+ },
+ )
+}
+
+fn render_js(
+ out_dir: Utf8PathBuf,
+ components: &Vec<(ComponentInterface, Config)>,
+ function_ids: &FunctionIds,
+ object_ids: &ObjectIds,
+ callback_ids: &CallbackIds,
+) -> Result<()> {
+ for (ci, config) in components {
+ let template = JSBindingsTemplate {
+ ci,
+ config,
+ function_ids,
+ object_ids,
+ callback_ids,
+ };
+ let path = out_dir.join(template.js_module_name());
+ render(path, template)?;
+ }
+ Ok(())
+}
+
+pub fn run_main() -> Result<()> {
+ let args = CliArgs::parse();
+ let config_map: ConfigMap =
+ toml::from_str(include_str!("../config.toml")).expect("Error parsing config.toml");
+ let components = ComponentUniverse::new(args.udl_files, args.fixture_udl_files, config_map)?;
+ let function_ids = FunctionIds::new(&components);
+ let object_ids = ObjectIds::new(&components);
+ let callback_ids = CallbackIds::new(&components);
+
+ render_cpp(
+ args.cpp_path,
+ "UniFFI",
+ &components.components,
+ &function_ids,
+ &object_ids,
+ &callback_ids,
+ )?;
+ render_cpp(
+ args.fixture_cpp_path,
+ "UniFFIFixtures",
+ &components.fixture_components,
+ &function_ids,
+ &object_ids,
+ &callback_ids,
+ )?;
+ render_js(
+ args.js_dir,
+ &components.components,
+ &function_ids,
+ &object_ids,
+ &callback_ids,
+ )?;
+ render_js(
+ args.fixture_js_dir,
+ &components.fixture_components,
+ &function_ids,
+ &object_ids,
+ &callback_ids,
+ )?;
+
+ Ok(())
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/main.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/main.rs
new file mode 100644
index 0000000000..eefe72ba66
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/main.rs
@@ -0,0 +1,9 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use anyhow::Result;
+
+fn main() -> Result<()> {
+ uniffi_bindgen_gecko_js::run_main()
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs
new file mode 100644
index 0000000000..edbe4c7660
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs
@@ -0,0 +1,190 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use crate::{CallbackIds, Config, FunctionIds, ObjectIds};
+use askama::Template;
+use extend::ext;
+use heck::{ToShoutySnakeCase, ToUpperCamelCase};
+use std::collections::HashSet;
+use std::iter;
+use uniffi_bindgen::interface::{
+ CallbackInterface, ComponentInterface, FfiArgument, FfiFunction, FfiType, Object,
+};
+
+#[derive(Template)]
+#[template(path = "UniFFIScaffolding.cpp", escape = "none")]
+pub struct CPPScaffoldingTemplate<'a> {
+ // Prefix for each function name in. This is related to how we handle the test fixtures. For
+ // each function defined in the UniFFI namespace in UniFFI.webidl we:
+ // - Generate a function in to handle it using the real UDL files
+ // - Generate a different function in for handle it using the fixture UDL files
+ // - Have a hand-written stub function that always calls the first function and only calls
+ // the second function in if MOZ_UNIFFI_FIXTURES is defined.
+ pub prefix: &'a str,
+ pub components: &'a Vec<(ComponentInterface, Config)>,
+ pub function_ids: &'a FunctionIds<'a>,
+ pub object_ids: &'a ObjectIds<'a>,
+ pub callback_ids: &'a CallbackIds<'a>,
+}
+
+impl<'a> CPPScaffoldingTemplate<'a> {
+ fn has_any_objects(&self) -> bool {
+ self.components
+ .iter()
+ .any(|(ci, _)| ci.object_definitions().len() > 0)
+ }
+}
+
+// Define extension traits with methods used in our template code
+
+#[ext(name=ComponentInterfaceCppExt)]
+pub impl ComponentInterface {
+ // C++ pointer type name. This needs to be a valid C++ type name and unique across all UDL
+ // files.
+ fn pointer_type(&self, object: &Object) -> String {
+ self._pointer_type(object.name())
+ }
+
+ fn _pointer_type(&self, name: &str) -> String {
+ format!(
+ "k{}{}PointerType",
+ self.namespace().to_upper_camel_case(),
+ name.to_upper_camel_case()
+ )
+ }
+
+ // Iterate over all functions to expose via the UniFFIScaffolding class
+ //
+ // This is basically all the user functions, except we don't expose the free methods for
+ // objects. Freeing is handled by the UniFFIPointer class.
+ //
+ // Note: this function should return `impl Iterator<&FfiFunction>`, but that's not currently
+ // allowed for traits.
+ fn exposed_functions(&self) -> Vec<&FfiFunction> {
+ let excluded: HashSet<_> = self
+ .object_definitions()
+ .iter()
+ .map(|o| o.ffi_object_free().name())
+ .chain(
+ self.callback_interface_definitions()
+ .iter()
+ .map(|cbi| cbi.ffi_init_callback().name()),
+ )
+ .collect();
+ self.iter_user_ffi_function_definitions()
+ .filter(move |f| !excluded.contains(f.name()))
+ .collect()
+ }
+
+ // ScaffoldingConverter class
+ //
+ // This is used to convert types between the JS code and Rust
+ fn scaffolding_converter(&self, ffi_type: &FfiType) -> String {
+ match ffi_type {
+ FfiType::RustArcPtr(name) => {
+ format!("ScaffoldingObjectConverter<&{}>", self._pointer_type(name),)
+ }
+ _ => format!("ScaffoldingConverter<{}>", ffi_type.rust_type()),
+ }
+ }
+
+ // ScaffoldingCallHandler class
+ fn scaffolding_call_handler(&self, func: &FfiFunction) -> String {
+ let return_param = match func.return_type() {
+ Some(return_type) => self.scaffolding_converter(return_type),
+ None => "ScaffoldingConverter<void>".to_string(),
+ };
+ let all_params = iter::once(return_param)
+ .chain(
+ func.arguments()
+ .into_iter()
+ .map(|a| self.scaffolding_converter(&a.type_())),
+ )
+ .collect::<Vec<_>>()
+ .join(", ");
+ return format!("ScaffoldingCallHandler<{}>", all_params);
+ }
+}
+
+#[ext(name=FFIFunctionCppExt)]
+pub impl FfiFunction {
+ fn nm(&self) -> String {
+ self.name().to_upper_camel_case()
+ }
+
+ fn rust_name(&self) -> String {
+ self.name().to_string()
+ }
+
+ fn rust_return_type(&self) -> String {
+ match self.return_type() {
+ Some(t) => t.rust_type(),
+ None => "void".to_owned(),
+ }
+ }
+
+ fn rust_arg_list(&self) -> String {
+ let mut parts: Vec<String> = self.arguments().iter().map(|a| a.rust_type()).collect();
+ parts.push("RustCallStatus*".to_owned());
+ parts.join(", ")
+ }
+}
+
+#[ext(name=FFITypeCppExt)]
+pub impl FfiType {
+ // Type for the Rust scaffolding code
+ fn rust_type(&self) -> String {
+ match self {
+ FfiType::UInt8 => "uint8_t",
+ FfiType::Int8 => "int8_t",
+ FfiType::UInt16 => "uint16_t",
+ FfiType::Int16 => "int16_t",
+ FfiType::UInt32 => "uint32_t",
+ FfiType::Int32 => "int32_t",
+ FfiType::UInt64 => "uint64_t",
+ FfiType::Int64 => "int64_t",
+ FfiType::Float32 => "float",
+ FfiType::Float64 => "double",
+ FfiType::RustBuffer(_) => "RustBuffer",
+ FfiType::RustArcPtr(_) => "void *",
+ FfiType::ForeignCallback => "ForeignCallback",
+ FfiType::ForeignBytes => unimplemented!("ForeignBytes not supported"),
+ }
+ .to_owned()
+ }
+}
+
+#[ext(name=FFIArgumentCppExt)]
+pub impl FfiArgument {
+ fn rust_type(&self) -> String {
+ self.type_().rust_type()
+ }
+}
+
+#[ext(name=ObjectCppExt)]
+pub impl Object {
+ fn nm(&self) -> String {
+ self.name().to_upper_camel_case()
+ }
+}
+
+#[ext(name=CallbackInterfaceCppExt)]
+pub impl CallbackInterface {
+ fn nm(&self) -> String {
+ self.name().to_upper_camel_case()
+ }
+
+ /// Name of the static pointer to the JS callback handler
+ fn js_handler(&self) -> String {
+ format!("JS_CALLBACK_HANDLER_{}", self.name().to_shouty_snake_case())
+ }
+
+ /// Name of the C function handler
+ fn c_handler(&self, prefix: &str) -> String {
+ format!(
+ "{prefix}CallbackHandler{}",
+ self.name().to_upper_camel_case()
+ )
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs
new file mode 100644
index 0000000000..728be7db96
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs
@@ -0,0 +1,302 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use super::shared::*;
+use crate::{CallbackIds, Config, FunctionIds, ObjectIds};
+use askama::Template;
+use extend::ext;
+use heck::{ToLowerCamelCase, ToShoutySnakeCase, ToUpperCamelCase};
+use uniffi_bindgen::interface::{
+ Argument, CallbackInterface, ComponentInterface, Constructor, Enum, Error, Field, Function,
+ Literal, Method, Object, Radix, Record, Type,
+};
+
+fn arg_names(args: &[&Argument]) -> String {
+ args.iter()
+ .map(|arg| {
+ if let Some(default_value) = arg.default_value() {
+ format!("{} = {}", arg.nm(), default_value.render())
+ } else {
+ arg.nm()
+ }
+ })
+ .collect::<Vec<String>>()
+ .join(",")
+}
+
+fn render_enum_literal(typ: &Type, variant_name: &str) -> String {
+ if let Type::Enum(enum_name) = typ {
+ // TODO: This does not support complex enum literals yet.
+ return format!(
+ "{}.{}",
+ enum_name.to_upper_camel_case(),
+ variant_name.to_shouty_snake_case()
+ );
+ } else {
+ panic!("Rendering an enum literal on a type that is not an enum")
+ }
+}
+
+#[derive(Template)]
+#[template(path = "js/wrapper.sys.mjs", escape = "none")]
+pub struct JSBindingsTemplate<'a> {
+ pub ci: &'a ComponentInterface,
+ pub config: &'a Config,
+ pub function_ids: &'a FunctionIds<'a>,
+ pub object_ids: &'a ObjectIds<'a>,
+ pub callback_ids: &'a CallbackIds<'a>,
+}
+
+impl<'a> JSBindingsTemplate<'a> {
+ pub fn js_module_name(&self) -> String {
+ self.js_module_name_for_ci_namespace(self.ci.namespace())
+ }
+
+ fn external_type_module(&self, crate_name: &str) -> String {
+ format!(
+ "resource://gre/modules/{}",
+ self.js_module_name_for_crate_name(crate_name),
+ )
+ }
+
+ // TODO: Once https://phabricator.services.mozilla.com/D156116 is merged maybe the next two
+ // functions should use a map from the config file
+
+ fn js_module_name_for_ci_namespace(&self, namespace: &str) -> String {
+ // The plain namespace name is a bit too generic as a module name for m-c, so we
+ // prefix it with "Rust". Later we'll probably allow this to be customized.
+ format!("Rust{}.sys.mjs", namespace.to_upper_camel_case())
+ }
+
+ fn js_module_name_for_crate_name(&self, crate_name: &str) -> String {
+ let namespace = match crate_name {
+ "uniffi_geometry" => "geometry",
+ s => s,
+ };
+ self.js_module_name_for_ci_namespace(namespace)
+ }
+}
+
+// Define extension traits with methods used in our template code
+
+#[ext(name=LiteralJSExt)]
+pub impl Literal {
+ fn render(&self) -> String {
+ match self {
+ Literal::Boolean(inner) => inner.to_string(),
+ Literal::String(inner) => format!("\"{}\"", inner),
+ Literal::UInt(num, radix, _) => format!("{}", radix.render_num(num)),
+ Literal::Int(num, radix, _) => format!("{}", radix.render_num(num)),
+ Literal::Float(num, _) => num.clone(),
+ Literal::Enum(name, typ) => render_enum_literal(typ, name),
+ Literal::EmptyMap => "{}".to_string(),
+ Literal::EmptySequence => "[]".to_string(),
+ Literal::Null => "null".to_string(),
+ }
+ }
+}
+
+#[ext(name=RadixJSExt)]
+pub impl Radix {
+ fn render_num(
+ &self,
+ num: impl std::fmt::Display + std::fmt::LowerHex + std::fmt::Octal,
+ ) -> String {
+ match self {
+ Radix::Decimal => format!("{}", num),
+ Radix::Hexadecimal => format!("{:#x}", num),
+ Radix::Octal => format!("{:#o}", num),
+ }
+ }
+}
+
+#[ext(name=RecordJSExt)]
+pub impl Record {
+ fn nm(&self) -> String {
+ self.name().to_upper_camel_case()
+ }
+
+ fn constructor_field_list(&self) -> String {
+ self.fields()
+ .iter()
+ .map(|field| {
+ if let Some(default_value) = field.default_value() {
+ format!("{} = {}", field.nm(), default_value.render())
+ } else {
+ field.nm()
+ }
+ })
+ .collect::<Vec<String>>()
+ .join(",")
+ }
+}
+
+#[ext(name=CallbackInterfaceJSExt)]
+pub impl CallbackInterface {
+ fn nm(&self) -> String {
+ self.name().to_upper_camel_case()
+ }
+
+ fn handler(&self) -> String {
+ format!("callbackHandler{}", self.nm())
+ }
+}
+
+#[ext(name=FieldJSExt)]
+pub impl Field {
+ fn nm(&self) -> String {
+ self.name().to_lower_camel_case()
+ }
+
+ fn lower_fn(&self) -> String {
+ self.type_().lower_fn()
+ }
+
+ fn lift_fn(&self) -> String {
+ self.type_().lift_fn()
+ }
+
+ fn write_datastream_fn(&self) -> String {
+ self.type_().write_datastream_fn()
+ }
+
+ fn read_datastream_fn(&self) -> String {
+ self.type_().read_datastream_fn()
+ }
+
+ fn compute_size_fn(&self) -> String {
+ self.type_().compute_size_fn()
+ }
+
+ fn ffi_converter(&self) -> String {
+ self.type_().ffi_converter()
+ }
+}
+
+#[ext(name=ArgumentJSExt)]
+pub impl Argument {
+ fn nm(&self) -> String {
+ self.name().to_lower_camel_case()
+ }
+
+ fn lower_fn(&self) -> String {
+ self.type_().lower_fn()
+ }
+
+ fn lift_fn(&self) -> String {
+ self.type_().lift_fn()
+ }
+
+ fn write_datastream_fn(&self) -> String {
+ self.type_().write_datastream_fn()
+ }
+
+ fn read_datastream_fn(&self) -> String {
+ self.type_().read_datastream_fn()
+ }
+
+ fn compute_size_fn(&self) -> String {
+ self.type_().compute_size_fn()
+ }
+
+ fn ffi_converter(&self) -> String {
+ self.type_().ffi_converter()
+ }
+}
+
+#[ext(name=TypeJSExt)]
+pub impl Type {
+ // Render an expression to check if two instances of this type are equal
+ fn equals(&self, first: &str, second: &str) -> String {
+ match self {
+ Type::Record(_) => format!("{}.equals({})", first, second),
+ _ => format!("{} == {}", first, second),
+ }
+ }
+
+ fn lower_fn(&self) -> String {
+ format!("{}.lower", self.ffi_converter())
+ }
+
+ fn lift_fn(&self) -> String {
+ format!("{}.lift", self.ffi_converter())
+ }
+
+ fn write_datastream_fn(&self) -> String {
+ format!("{}.write", self.ffi_converter())
+ }
+
+ fn read_datastream_fn(&self) -> String {
+ format!("{}.read", self.ffi_converter())
+ }
+
+ fn compute_size_fn(&self) -> String {
+ format!("{}.computeSize", self.ffi_converter())
+ }
+
+ fn ffi_converter(&self) -> String {
+ format!(
+ "FfiConverter{}",
+ self.canonical_name().to_upper_camel_case()
+ )
+ }
+}
+
+#[ext(name=EnumJSExt)]
+pub impl Enum {
+ fn nm(&self) -> String {
+ self.name().to_upper_camel_case()
+ }
+}
+
+#[ext(name=FunctionJSExt)]
+pub impl Function {
+ fn arg_names(&self) -> String {
+ arg_names(self.arguments().as_slice())
+ }
+
+ fn nm(&self) -> String {
+ self.name().to_lower_camel_case()
+ }
+}
+
+#[ext(name=ErrorJSExt)]
+pub impl Error {
+ fn nm(&self) -> String {
+ self.name().to_upper_camel_case()
+ }
+}
+
+#[ext(name=ObjectJSExt)]
+pub impl Object {
+ fn nm(&self) -> String {
+ self.name().to_upper_camel_case()
+ }
+}
+
+#[ext(name=ConstructorJSExt)]
+pub impl Constructor {
+ fn nm(&self) -> String {
+ if self.is_primary_constructor() {
+ "init".to_string()
+ } else {
+ self.name().to_lower_camel_case()
+ }
+ }
+
+ fn arg_names(&self) -> String {
+ arg_names(&self.arguments().as_slice())
+ }
+}
+
+#[ext(name=MethodJSExt)]
+pub impl Method {
+ fn arg_names(&self) -> String {
+ arg_names(self.arguments().as_slice())
+ }
+
+ fn nm(&self) -> String {
+ self.name().to_lower_camel_case()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/mod.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/mod.rs
new file mode 100644
index 0000000000..f9ceeb9872
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/mod.rs
@@ -0,0 +1,7 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+pub mod cpp;
+pub mod js;
+pub mod shared;
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/render/shared.rs b/toolkit/components/uniffi-bindgen-gecko-js/src/render/shared.rs
new file mode 100644
index 0000000000..c356158715
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/shared.rs
@@ -0,0 +1,39 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/// Extension traits that are shared across multiple render targets
+use crate::Config;
+use extend::ext;
+use uniffi_bindgen::interface::{Function, Method, Object};
+
+fn is_async(config: &Config, spec: &str) -> bool {
+ if config.receiver_thread.main.contains(spec) {
+ false
+ } else if config.receiver_thread.worker.contains(spec) {
+ true
+ } else {
+ match &config.receiver_thread.default {
+ Some(t) => t != "main",
+ _ => true,
+ }
+ }
+}
+
+#[ext]
+pub impl Function {
+ fn is_async(&self, config: &Config) -> bool {
+ is_async(config, self.name())
+ }
+}
+
+#[ext]
+pub impl Object {
+ fn is_constructor_async(&self, config: &Config) -> bool {
+ is_async(config, self.name())
+ }
+
+ fn is_method_async(&self, method: &Method, config: &Config) -> bool {
+ is_async(config, &format!("{}.{}", self.name(), method.name()))
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp
new file mode 100644
index 0000000000..9fe981f206
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/UniFFIScaffolding.cpp
@@ -0,0 +1,155 @@
+// Generated by uniffi-bindgen-gecko-js. DO NOT EDIT.
+
+#include "nsString.h"
+#include "nsPrintfCString.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/dom/UniFFICallbacks.h"
+#include "mozilla/dom/UniFFIScaffolding.h"
+#include "mozilla/dom/ScaffoldingCall.h"
+
+namespace mozilla::uniffi {
+
+using dom::ArrayBuffer;
+using dom::AutoEntryScript;
+using dom::GlobalObject;
+using dom::RootedDictionary;
+using dom::Promise;
+using dom::ScaffoldingType;
+using dom::Sequence;
+using dom::UniFFICallbackHandler;
+using dom::UniFFIPointer;
+using dom::UniFFIScaffoldingCallResult;
+
+// Define scaffolding functions from UniFFI
+extern "C" {
+ {%- for (ci, config) in components %}
+ {%- for func in ci.iter_user_ffi_function_definitions() %}
+ {{ func.rust_return_type() }} {{ func.rust_name() }}({{ func.rust_arg_list() }});
+ {%- endfor %}
+ {%- endfor %}
+}
+
+// Define pointer types
+{%- for (ci, config) in components %}
+{%- for object in ci.object_definitions() %}
+{%- let pointer_type = ci.pointer_type(object) %}
+const static mozilla::uniffi::UniFFIPointerType {{ pointer_type }} {
+ "{{ "{}::{}"|format(ci.namespace(), object.name()) }}"_ns,
+ {{ object.ffi_object_free().rust_name() }}
+};
+{%- endfor %}
+{%- endfor %}
+
+// Define the data we need per-callback interface
+{%- for (ci, config) in components %}
+{%- for cbi in ci.callback_interface_definitions() %}
+MOZ_CAN_RUN_SCRIPT
+extern "C" int {{ cbi.c_handler(prefix) }}(uint64_t aHandle, uint32_t aMethod, RustBuffer aArgs, RustBuffer* aOutBuffer) {
+ // Currently, we only support "fire-and-forget" async callbacks. These are
+ // callbacks that run asynchronously without returning anything. The main
+ // use case for callbacks is logging, which fits very well with this model.
+ //
+ // So, here we simple queue the callback and return immediately.
+ mozilla::uniffi::QueueCallback({{ callback_ids.get(ci, cbi) }}, aHandle, aMethod, aArgs);
+ return CALLBACK_INTERFACE_SUCCESS;
+}
+static StaticRefPtr<dom::UniFFICallbackHandler> {{ cbi.js_handler() }};
+{%- endfor %}
+{%- endfor %}
+
+// Define a lookup function for our callback interface info
+Maybe<CallbackInterfaceInfo> {{ prefix }}GetCallbackInterfaceInfo(uint64_t aInterfaceId) {
+ switch(aInterfaceId) {
+ {%- for (ci, config) in components %}
+ {%- for cbi in ci.callback_interface_definitions() %}
+ case {{ callback_ids.get(ci, cbi) }}: { // {{ callback_ids.name(ci, cbi) }}
+ return Some(CallbackInterfaceInfo {
+ "{{ cbi.name() }}",
+ &{{ cbi.js_handler() }},
+ {{ cbi.c_handler(prefix) }},
+ {{ cbi.ffi_init_callback().name() }},
+ });
+ }
+ {%- endfor %}
+ {%- endfor %}
+
+ default:
+ return Nothing();
+ }
+}
+
+Maybe<already_AddRefed<Promise>> {{ prefix }}CallAsync(const GlobalObject& aGlobal, uint64_t aId, const Sequence<ScaffoldingType>& aArgs, ErrorResult& aError) {
+ switch (aId) {
+ {%- for (ci, config) in components %}
+ {%- for func in ci.exposed_functions() %}
+ case {{ function_ids.get(ci, func) }}: { // {{ function_ids.name(ci, func) }}
+ using CallHandler = {{ ci.scaffolding_call_handler(func) }};
+ return Some(CallHandler::CallAsync({{ func.rust_name() }}, aGlobal, aArgs, "{{ func.name() }}: "_ns, aError));
+ }
+ {%- endfor %}
+ {%- endfor %}
+ }
+ return Nothing();
+}
+
+bool {{ prefix }}CallSync(const GlobalObject& aGlobal, uint64_t aId, const Sequence<ScaffoldingType>& aArgs, RootedDictionary<UniFFIScaffoldingCallResult>& aReturnValue, ErrorResult& aError) {
+ switch (aId) {
+ {%- for (ci, config) in components %}
+ {%- for func in ci.exposed_functions() %}
+ case {{ function_ids.get(ci, func) }}: { // {{ function_ids.name(ci, func) }}
+ using CallHandler = {{ ci.scaffolding_call_handler(func) }};
+ CallHandler::CallSync({{ func.rust_name() }}, aGlobal, aArgs, aReturnValue, "{{ func.name() }}: "_ns, aError);
+ return true;
+ }
+ {%- endfor %}
+ {%- endfor %}
+ }
+ return false;
+}
+
+Maybe<already_AddRefed<UniFFIPointer>> {{ prefix }}ReadPointer(const GlobalObject& aGlobal, uint64_t aId, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) {
+ {%- if self.has_any_objects() %}
+ const UniFFIPointerType* type;
+ switch (aId) {
+ {%- for (ci, config) in components %}
+ {%- for object in ci.object_definitions() %}
+ case {{ object_ids.get(ci, object) }}: { // {{ object_ids.name(ci, object) }}
+ type = &{{ ci.pointer_type(object) }};
+ break;
+ }
+ {%- endfor %}
+ {%- endfor %}
+ default:
+ return Nothing();
+ }
+ return Some(UniFFIPointer::Read(aArrayBuff, aPosition, type, aError));
+ {%- else %}
+ return Nothing();
+ {%- endif %}
+}
+
+bool {{ prefix }}WritePointer(const GlobalObject& aGlobal, uint64_t aId, const UniFFIPointer& aPtr, const ArrayBuffer& aArrayBuff, long aPosition, ErrorResult& aError) {
+ {%- if self.has_any_objects() %}
+ const UniFFIPointerType* type;
+ switch (aId) {
+ {%- for (ci, config) in components %}
+ {%- for object in ci.object_definitions() %}
+ case {{ object_ids.get(ci, object) }}: { // {{ object_ids.name(ci, object) }}
+ type = &{{ ci.pointer_type(object) }};
+ break;
+ }
+ {%- endfor %}
+ {%- endfor %}
+ default:
+ return false;
+ }
+ aPtr.Write(aArrayBuff, aPosition, type, aError);
+ return true;
+ {%- else %}
+ return false;
+ {%- endif %}
+}
+
+} // namespace mozilla::uniffi
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Boolean.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Boolean.sys.mjs
new file mode 100644
index 0000000000..a38b6bdd94
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Boolean.sys.mjs
@@ -0,0 +1,22 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static computeSize() {
+ return 1;
+ }
+ static lift(value) {
+ return value == 1;
+ }
+ static lower(value) {
+ if (value) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint8(this.lower(value))
+ }
+ static read(dataStream) {
+ return this.lift(dataStream.readUint8())
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterface.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterface.sys.mjs
new file mode 100644
index 0000000000..0b24cbbe0b
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterface.sys.mjs
@@ -0,0 +1,24 @@
+{%- let cbi = ci.get_callback_interface_definition(name).unwrap() %}
+{#- See CallbackInterfaceRuntime.sys.mjs and CallbackInterfaceHandler.sys.mjs for the callback interface handler definition, referenced here as `{{ cbi.handler() }}` #}
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static lower(callbackObj) {
+ return {{ cbi.handler() }}.storeCallbackObj(callbackObj)
+ }
+
+ static lift(handleId) {
+ return {{ cbi.handler() }}.getCallbackObj(handleId)
+ }
+
+ static read(dataStream) {
+ return this.lift(dataStream.readInt64())
+ }
+
+ static write(dataStream, callbackObj) {
+ dataStream.writeInt64(this.lower(callbackObj))
+ }
+
+ static computeSize(callbackObj) {
+ return 8;
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterfaceHandler.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterfaceHandler.sys.mjs
new file mode 100644
index 0000000000..c062d64e0c
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterfaceHandler.sys.mjs
@@ -0,0 +1,19 @@
+const {{ cbi.handler() }} = new UniFFICallbackHandler(
+ "{{ callback_ids.name(ci, cbi) }}",
+ {{ callback_ids.get(ci, cbi) }},
+ [
+ {%- for method in cbi.methods() %}
+ new UniFFICallbackMethodHandler(
+ "{{ method.nm() }}",
+ [
+ {%- for arg in method.arguments() %}
+ {{ arg.ffi_converter() }},
+ {%- endfor %}
+ ],
+ ),
+ {%- endfor %}
+ ]
+);
+
+// Allow the shutdown-related functionality to be tested in the unit tests
+UnitTestObjs.{{ cbi.handler() }} = {{ cbi.handler() }};
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterfaceRuntime.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterfaceRuntime.sys.mjs
new file mode 100644
index 0000000000..a4d88136ab
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CallbackInterfaceRuntime.sys.mjs
@@ -0,0 +1,195 @@
+
+/**
+ * Handler for a single UniFFI CallbackInterface
+ *
+ * This class stores objects that implement a callback interface in a handle
+ * map, allowing them to be referenced by the Rust code using an integer
+ * handle.
+ *
+ * While the callback object is stored in the map, it allows the Rust code to
+ * call methods on the object using the callback object handle, a method id,
+ * and an ArrayBuffer packed with the method arguments.
+ *
+ * When the Rust code drops its reference, it sends a call with the methodId=0,
+ * which causes callback object to be removed from the map.
+ */
+class UniFFICallbackHandler {
+ #name;
+ #interfaceId;
+ #handleCounter;
+ #handleMap;
+ #methodHandlers;
+ #allowNewCallbacks
+
+ /**
+ * Create a UniFFICallbackHandler
+ * @param {string} name - Human-friendly name for this callback interface
+ * @param {int} interfaceId - Interface ID for this CallbackInterface.
+ * @param {UniFFICallbackMethodHandler[]} methodHandlers -- UniFFICallbackHandler for each method, in the same order as the UDL file
+ */
+ constructor(name, interfaceId, methodHandlers) {
+ this.#name = name;
+ this.#interfaceId = interfaceId;
+ this.#handleCounter = 0;
+ this.#handleMap = new Map();
+ this.#methodHandlers = methodHandlers;
+ this.#allowNewCallbacks = true;
+
+ UniFFIScaffolding.registerCallbackHandler(this.#interfaceId, this.invokeCallback.bind(this));
+ Services.obs.addObserver(this, "xpcom-shutdown");
+ }
+
+ /**
+ * Store a callback object in the handle map and return the handle
+ *
+ * @param {obj} callbackObj - Object that implements the callback interface
+ * @returns {int} - Handle for this callback object, this is what gets passed back to Rust.
+ */
+ storeCallbackObj(callbackObj) {
+ if (!this.#allowNewCallbacks) {
+ throw new UniFFIError(`No new callbacks allowed for ${this.#name}`);
+ }
+ const handle = this.#handleCounter;
+ this.#handleCounter += 1;
+ this.#handleMap.set(handle, new UniFFICallbackHandleMapEntry(callbackObj, Components.stack.caller.formattedStack.trim()));
+ return handle;
+ }
+
+ /**
+ * Get a previously stored callback object
+ *
+ * @param {int} handle - Callback object handle, returned from `storeCallbackObj()`
+ * @returns {obj} - Callback object
+ */
+ getCallbackObj(handle) {
+ return this.#handleMap.get(handle).callbackObj;
+ }
+
+ /**
+ * Set if new callbacks are allowed for this handler
+ *
+ * This is called with false during shutdown to ensure the callback maps don't
+ * prevent JS objects from being GCed.
+ */
+ setAllowNewCallbacks(allow) {
+ this.#allowNewCallbacks = allow
+ }
+
+ /**
+ * Check that no callbacks are currently registered
+ *
+ * If there are callbacks registered a UniFFIError will be thrown. This is
+ * called during shutdown to generate an alert if there are leaked callback
+ * interfaces.
+ */
+ assertNoRegisteredCallbacks() {
+ if (this.#handleMap.size > 0) {
+ const entry = this.#handleMap.values().next().value;
+ throw new UniFFIError(`UniFFI interface ${this.#name} has ${this.#handleMap.size} registered callbacks at xpcom-shutdown. This likely indicates a UniFFI callback leak.\nStack trace for the first leaked callback:\n${entry.stackTrace}.`);
+ }
+ }
+
+ /**
+ * Invoke a method on a stored callback object
+ * @param {int} handle - Object handle
+ * @param {int} methodId - Method identifier. This the 1-based index of
+ * the method from the UDL file. 0 is the special drop method, which
+ * removes the callback object from the handle map.
+ * @param {ArrayBuffer} argsArrayBuffer - Arguments to pass to the method, packed in an ArrayBuffer
+ */
+ invokeCallback(handle, methodId, argsArrayBuffer) {
+ try {
+ this.#invokeCallbackInner(handle, methodId, argsArrayBuffer);
+ } catch (e) {
+ console.error(`internal error invoking callback: ${e}`)
+ }
+ }
+
+ #invokeCallbackInner(handle, methodId, argsArrayBuffer) {
+ const callbackObj = this.getCallbackObj(handle);
+ if (callbackObj === undefined) {
+ throw new UniFFIError(`${this.#name}: invalid callback handle id: ${handle}`);
+ }
+
+ // Special-cased drop method, remove the object from the handle map and
+ // return an empty array buffer
+ if (methodId == 0) {
+ this.#handleMap.delete(handle);
+ return;
+ }
+
+ // Get the method data, converting from 1-based indexing
+ const methodHandler = this.#methodHandlers[methodId - 1];
+ if (methodHandler === undefined) {
+ throw new UniFFIError(`${this.#name}: invalid method id: ${methodId}`)
+ }
+
+ methodHandler.call(callbackObj, argsArrayBuffer);
+ }
+
+ /**
+ * xpcom-shutdown observer method
+ *
+ * This handles:
+ * - Deregistering ourselves as the UniFFI callback handler
+ * - Checks for any leftover stored callbacks which indicate memory leaks
+ */
+ observe(aSubject, aTopic, aData) {
+ if (aTopic == "xpcom-shutdown") {
+ try {
+ this.setAllowNewCallbacks(false);
+ this.assertNoRegisteredCallbacks();
+ UniFFIScaffolding.deregisterCallbackHandler(this.#interfaceId);
+ } catch (ex) {
+ console.error(`UniFFI Callback interface error during xpcom-shutdown: ${ex}`);
+ Cc["@mozilla.org/xpcom/debug;1"]
+ .getService(Ci.nsIDebug2)
+ .abort(ex.filename, ex.lineNumber);
+ }
+ }
+ }
+}
+
+/**
+ * Handles calling a single method for a callback interface
+ */
+class UniFFICallbackMethodHandler {
+ #name;
+ #argsConverters;
+
+ /**
+ * Create a UniFFICallbackMethodHandler
+
+ * @param {string} name -- Name of the method to call on the callback object
+ * @param {FfiConverter[]} argsConverters - FfiConverter for each argument type
+ */
+ constructor(name, argsConverters) {
+ this.#name = name;
+ this.#argsConverters = argsConverters;
+ }
+
+ /**
+ * Invoke the method
+ *
+ * @param {obj} callbackObj -- Object implementing the callback interface for this method
+ * @param {ArrayBuffer} argsArrayBuffer -- Arguments for the method, packed in an ArrayBuffer
+ */
+ call(callbackObj, argsArrayBuffer) {
+ const argsStream = new ArrayBufferDataStream(argsArrayBuffer);
+ const args = this.#argsConverters.map(converter => converter.read(argsStream));
+ callbackObj[this.#name](...args);
+ }
+}
+
+/**
+ * UniFFICallbackHandler.handleMap entry
+ *
+ * @property callbackObj - Callback object, this must implement the callback interface.
+ * @property {string} stackTrace - Stack trace from when the callback object was registered. This is used to proved extra context when debugging leaked callback objects.
+ */
+class UniFFICallbackHandleMapEntry {
+ constructor(callbackObj, stackTrace) {
+ this.callbackObj = callbackObj;
+ this.stackTrace = stackTrace
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CustomType.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CustomType.sys.mjs
new file mode 100644
index 0000000000..4ce4dc31af
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/CustomType.sys.mjs
@@ -0,0 +1,23 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static lift(buf) {
+ return {{ builtin.ffi_converter() }}.lift(buf);
+ }
+
+ static lower(buf) {
+ return {{ builtin.ffi_converter() }}.lower(buf);
+ }
+
+ static write(dataStream, value) {
+ {{ builtin.ffi_converter() }}.write(dataStream, value);
+ }
+
+ static read(buf) {
+ return {{ builtin.ffi_converter() }}.read(buf);
+ }
+
+ static computeSize(value) {
+ return {{ builtin.ffi_converter() }}.computeSize(value);
+ }
+}
+// TODO: We should also allow JS to customize the type eventually.
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Enum.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Enum.sys.mjs
new file mode 100644
index 0000000000..941784ed63
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Enum.sys.mjs
@@ -0,0 +1,115 @@
+{%- let enum_ = ci.get_enum_definition(name).unwrap() -%}
+
+{%- if enum_.is_flat() -%}
+
+export const {{ enum_.nm() }} = {
+ {%- for variant in enum_.variants() %}
+ {{ variant.name().to_shouty_snake_case() }}: {{loop.index}},
+ {%- endfor %}
+};
+
+Object.freeze({{ enum_.nm() }});
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ switch (dataStream.readInt32()) {
+ {%- for variant in enum_.variants() %}
+ case {{ loop.index }}:
+ return {{ enum_.nm() }}.{{ variant.name().to_shouty_snake_case() }}
+ {%- endfor %}
+ default:
+ return new Error("Unknown {{ enum_.nm() }} variant");
+ }
+ }
+
+ static write(dataStream, value) {
+ {%- for variant in enum_.variants() %}
+ if (value === {{ enum_.nm() }}.{{ variant.name().to_shouty_snake_case() }}) {
+ dataStream.writeInt32({{ loop.index }});
+ return;
+ }
+ {%- endfor %}
+ return new Error("Unknown {{ enum_.nm() }} variant");
+ }
+
+ static computeSize(value) {
+ return 4;
+ }
+
+ static checkType(value) {
+ if (!Number.isInteger(value) || value < 1 || value > {{ enum_.variants().len() }}) {
+ throw new UniFFITypeError(`${value} is not a valid value for {{ enum_.nm() }}`);
+ }
+ }
+}
+
+{%- else -%}
+
+export class {{ enum_.nm() }} {}
+{%- for variant in enum_.variants() %}
+{{enum_.nm()}}.{{variant.name().to_upper_camel_case() }} = class extends {{ enum_.nm() }}{
+ constructor(
+ {% for field in variant.fields() -%}
+ {{ field.nm() }}{%- if loop.last %}{%- else %}, {%- endif %}
+ {% endfor -%}
+ ) {
+ super();
+ {%- for field in variant.fields() %}
+ this.{{field.nm()}} = {{ field.nm() }};
+ {%- endfor %}
+ }
+}
+{%- endfor %}
+
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ switch (dataStream.readInt32()) {
+ {%- for variant in enum_.variants() %}
+ case {{ loop.index }}:
+ return new {{ enum_.nm() }}.{{ variant.name().to_upper_camel_case() }}(
+ {%- for field in variant.fields() %}
+ {{ field.ffi_converter() }}.read(dataStream){%- if loop.last %}{% else %}, {%- endif %}
+ {%- endfor %}
+ );
+ {%- endfor %}
+ default:
+ return new Error("Unknown {{ enum_.nm() }} variant");
+ }
+ }
+
+ static write(dataStream, value) {
+ {%- for variant in enum_.variants() %}
+ if (value instanceof {{enum_.nm()}}.{{ variant.name().to_upper_camel_case() }}) {
+ dataStream.writeInt32({{ loop.index }});
+ {%- for field in variant.fields() %}
+ {{ field.ffi_converter() }}.write(dataStream, value.{{ field.nm() }});
+ {%- endfor %}
+ return;
+ }
+ {%- endfor %}
+ return new Error("Unknown {{ enum_.nm() }} variant");
+ }
+
+ static computeSize(value) {
+ // Size of the Int indicating the variant
+ let totalSize = 4;
+ {%- for variant in enum_.variants() %}
+ if (value instanceof {{enum_.nm()}}.{{ variant.name().to_upper_camel_case() }}) {
+ {%- for field in variant.fields() %}
+ totalSize += {{ field.ffi_converter() }}.computeSize(value.{{ field.nm() }});
+ {%- endfor %}
+ return totalSize;
+ }
+ {%- endfor %}
+ return new Error("Unknown {{ enum_.nm() }} variant");
+ }
+
+ static checkType(value) {
+ if (!(value instanceof {{ enum_.nm() }})) {
+ throw new UniFFITypeError(`${value} is not a subclass instance of {{ enum_.nm() }}`);
+ }
+ }
+}
+
+{%- endif %}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Error.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Error.sys.mjs
new file mode 100644
index 0000000000..97b1d064d9
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Error.sys.mjs
@@ -0,0 +1,80 @@
+{%- let error = ci.get_error_definition(name).unwrap() %}
+{%- let string_type = Type::String %}
+{%- let string_ffi_converter = string_type.ffi_converter() %}
+
+export class {{ error.nm() }} extends Error {}
+{% for variant in error.variants() %}
+
+export class {{ variant.name().to_upper_camel_case() }} extends {{ error.nm() }} {
+{% if error.is_flat() %}
+ constructor(message, ...params) {
+ super(...params);
+ this.message = message;
+ }
+{%- else %}
+ constructor(
+ {% for field in variant.fields() -%}
+ {{field.nm()}},
+ {% endfor -%}
+ ...params
+ ) {
+ super(...params);
+ {%- for field in variant.fields() %}
+ this.{{field.nm()}} = {{ field.nm() }};
+ {%- endfor %}
+ }
+{%- endif %}
+ toString() {
+ return `{{ variant.name().to_upper_camel_case() }}: ${super.toString()}`
+ }
+}
+{%- endfor %}
+
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ switch (dataStream.readInt32()) {
+ {%- for variant in error.variants() %}
+ case {{ loop.index }}:
+ {%- if error.is_flat() %}
+ return new {{ variant.name().to_upper_camel_case() }}({{ string_ffi_converter }}.read(dataStream));
+ {%- else %}
+ return new {{ variant.name().to_upper_camel_case() }}(
+ {%- for field in variant.fields() %}
+ {{ field.ffi_converter() }}.read(dataStream){%- if loop.last %}{% else %}, {%- endif %}
+ {%- endfor %}
+ );
+ {%- endif %}
+ {%- endfor %}
+ default:
+ throw new Error("Unknown {{ error.nm() }} variant");
+ }
+ }
+ static computeSize(value) {
+ // Size of the Int indicating the variant
+ let totalSize = 4;
+ {%- for variant in error.variants() %}
+ if (value instanceof {{ variant.name().to_upper_camel_case() }}) {
+ {%- for field in variant.fields() %}
+ totalSize += {{ field.ffi_converter() }}.computeSize(value.{{ field.nm() }});
+ {%- endfor %}
+ return totalSize;
+ }
+ {%- endfor %}
+ throw new Error("Unknown {{ error.nm() }} variant");
+ }
+ static write(dataStream, value) {
+ {%- for variant in error.variants() %}
+ if (value instanceof {{ variant.name().to_upper_camel_case() }}) {
+ dataStream.writeInt32({{ loop.index }});
+ {%- for field in variant.fields() %}
+ {{ field.ffi_converter() }}.write(dataStream, value.{{ field.nm() }});
+ {%- endfor %}
+ return;
+ }
+ {%- endfor %}
+ throw new Error("Unknown {{ error.nm() }} variant");
+ }
+
+ static errorClass = {{ error.nm() }};
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/ExternalType.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/ExternalType.sys.mjs
new file mode 100644
index 0000000000..ebc658834b
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/ExternalType.sys.mjs
@@ -0,0 +1,7 @@
+import {
+ {{ ffi_converter }},
+ {{ name }},
+} from "{{ self.external_type_module(crate_name) }}";
+
+// Export the FFIConverter object to make external types work.
+export { {{ ffi_converter }}, {{ name }} };
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float32.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float32.sys.mjs
new file mode 100644
index 0000000000..1030efa226
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float32.sys.mjs
@@ -0,0 +1,18 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static computeSize() {
+ return 4;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeFloat32(value)
+ }
+ static read(dataStream) {
+ return dataStream.readFloat32()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float64.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float64.sys.mjs
new file mode 100644
index 0000000000..fc49046691
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Float64.sys.mjs
@@ -0,0 +1,18 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeFloat64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readFloat64()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Helpers.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Helpers.sys.mjs
new file mode 100644
index 0000000000..0daaa983ac
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Helpers.sys.mjs
@@ -0,0 +1,234 @@
+// Write/Read data to/from an ArrayBuffer
+class ArrayBufferDataStream {
+ constructor(arrayBuffer) {
+ this.dataView = new DataView(arrayBuffer);
+ this.pos = 0;
+ }
+
+ readUint8() {
+ let rv = this.dataView.getUint8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeUint8(value) {
+ this.dataView.setUint8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readUint16() {
+ let rv = this.dataView.getUint16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeUint16(value) {
+ this.dataView.setUint16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readUint32() {
+ let rv = this.dataView.getUint32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeUint32(value) {
+ this.dataView.setUint32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readUint64() {
+ let rv = this.dataView.getBigUint64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeUint64(value) {
+ this.dataView.setBigUint64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+
+ readInt8() {
+ let rv = this.dataView.getInt8(this.pos);
+ this.pos += 1;
+ return rv;
+ }
+
+ writeInt8(value) {
+ this.dataView.setInt8(this.pos, value);
+ this.pos += 1;
+ }
+
+ readInt16() {
+ let rv = this.dataView.getInt16(this.pos);
+ this.pos += 2;
+ return rv;
+ }
+
+ writeInt16(value) {
+ this.dataView.setInt16(this.pos, value);
+ this.pos += 2;
+ }
+
+ readInt32() {
+ let rv = this.dataView.getInt32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeInt32(value) {
+ this.dataView.setInt32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readInt64() {
+ let rv = this.dataView.getBigInt64(this.pos);
+ this.pos += 8;
+ return Number(rv);
+ }
+
+ writeInt64(value) {
+ this.dataView.setBigInt64(this.pos, BigInt(value));
+ this.pos += 8;
+ }
+
+ readFloat32() {
+ let rv = this.dataView.getFloat32(this.pos);
+ this.pos += 4;
+ return rv;
+ }
+
+ writeFloat32(value) {
+ this.dataView.setFloat32(this.pos, value);
+ this.pos += 4;
+ }
+
+ readFloat64() {
+ let rv = this.dataView.getFloat64(this.pos);
+ this.pos += 8;
+ return rv;
+ }
+
+ writeFloat64(value) {
+ this.dataView.setFloat64(this.pos, value);
+ this.pos += 8;
+ }
+
+
+ writeString(value) {
+ const encoder = new TextEncoder();
+ // Note: in order to efficiently write this data, we first write the
+ // string data, reserving 4 bytes for the size.
+ const dest = new Uint8Array(this.dataView.buffer, this.pos + 4);
+ const encodeResult = encoder.encodeInto(value, dest);
+ if (encodeResult.read != value.length) {
+ throw new UniFFIError(
+ "writeString: out of space when writing to ArrayBuffer. Did the computeSize() method returned the wrong result?"
+ );
+ }
+ const size = encodeResult.written;
+ // Next, go back and write the size before the string data
+ this.dataView.setUint32(this.pos, size);
+ // Finally, advance our position past both the size and string data
+ this.pos += size + 4;
+ }
+
+ readString() {
+ const decoder = new TextDecoder();
+ const size = this.readUint32();
+ const source = new Uint8Array(this.dataView.buffer, this.pos, size)
+ const value = decoder.decode(source);
+ this.pos += size;
+ return value;
+ }
+
+ {%- for object in ci.object_definitions() %}
+
+ // Reads a {{ object.nm() }} pointer from the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ readPointer{{ object.nm() }}() {
+ const pointerId = {{ object_ids.get(ci, object) }}; // {{ object_ids.name(ci, object) }}
+ const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ return res;
+ }
+
+ // Writes a {{ object.nm() }} pointer into the data stream
+ // UniFFI Pointers are **always** 8 bytes long. That is enforced
+ // by the C++ and Rust Scaffolding code.
+ writePointer{{ object.nm() }}(value) {
+ const pointerId = {{ object_ids.get(ci, object) }}; // {{ object_ids.name(ci, object) }}
+ UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos);
+ this.pos += 8;
+ }
+ {% endfor %}
+}
+
+function handleRustResult(result, liftCallback, liftErrCallback) {
+ switch (result.code) {
+ case "success":
+ return liftCallback(result.data);
+
+ case "error":
+ throw liftErrCallback(result.data);
+
+ case "internal-error":
+ let message = result.internalErrorMessage;
+ if (message) {
+ throw new UniFFIInternalError(message);
+ } else {
+ throw new UniFFIInternalError("Unknown error");
+ }
+
+ default:
+ throw new UniFFIError(`Unexpected status code: ${result.code}`);
+ }
+}
+
+class UniFFIError {
+ constructor(message) {
+ this.message = message;
+ }
+
+ toString() {
+ return `UniFFIError: ${this.message}`
+ }
+}
+
+class UniFFIInternalError extends UniFFIError {}
+
+// Base class for FFI converters
+class FfiConverter {
+ // throw `UniFFITypeError` if a value to be converted has an invalid type
+ static checkType(value) {
+ if (value === undefined ) {
+ throw new UniFFITypeError(`undefined`);
+ }
+ if (value === null ) {
+ throw new UniFFITypeError(`null`);
+ }
+ }
+}
+
+// Base class for FFI converters that lift/lower by reading/writing to an ArrayBuffer
+class FfiConverterArrayBuffer extends FfiConverter {
+ static lift(buf) {
+ return this.read(new ArrayBufferDataStream(buf));
+ }
+
+ static lower(value) {
+ const buf = new ArrayBuffer(this.computeSize(value));
+ const dataStream = new ArrayBufferDataStream(buf);
+ this.write(dataStream, value);
+ return buf;
+ }
+}
+
+// Symbols that are used to ensure that Object constructors
+// can only be used with a proper UniFFI pointer
+const uniffiObjectPtr = Symbol("uniffiObjectPtr");
+const constructUniffiObject = Symbol("constructUniffiObject");
+UnitTestObjs.uniffiObjectPtr = uniffiObjectPtr;
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int16.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int16.sys.mjs
new file mode 100644
index 0000000000..63c26bce8a
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int16.sys.mjs
@@ -0,0 +1,27 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < -32768 || value > 32767) {
+ throw new UniFFITypeError(`${value} exceeds the I16 bounds`);
+ }
+ }
+ static computeSize() {
+ return 2;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt16(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt16()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int32.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int32.sys.mjs
new file mode 100644
index 0000000000..502092eb16
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int32.sys.mjs
@@ -0,0 +1,27 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < -2147483648 || value > 2147483647) {
+ throw new UniFFITypeError(`${value} exceeds the I32 bounds`);
+ }
+ }
+ static computeSize() {
+ return 4;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt32(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt32()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int64.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int64.sys.mjs
new file mode 100644
index 0000000000..d56296712d
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int64.sys.mjs
@@ -0,0 +1,24 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isSafeInteger(value)) {
+ throw new UniFFITypeError(`${value} exceeds the safe integer bounds`);
+ }
+ }
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt64()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int8.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int8.sys.mjs
new file mode 100644
index 0000000000..63e543b1fa
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Int8.sys.mjs
@@ -0,0 +1,27 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < -128 || value > 127) {
+ throw new UniFFITypeError(`${value} exceeds the I8 bounds`);
+ }
+ }
+ static computeSize() {
+ return 1;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeInt8(value)
+ }
+ static read(dataStream) {
+ return dataStream.readInt8()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Map.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Map.sys.mjs
new file mode 100644
index 0000000000..5b6e6dc172
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Map.sys.mjs
@@ -0,0 +1,54 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const map = {};
+ for (let i = 0; i < len; i++) {
+ const key = {{ key_type.ffi_converter() }}.read(dataStream);
+ const value = {{ value_type.ffi_converter() }}.read(dataStream);
+ map[key] = value;
+ }
+
+ return map;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(Object.keys(value).length);
+ for (const key in value) {
+ {{ key_type.ffi_converter() }}.write(dataStream, key);
+ {{ value_type.ffi_converter() }}.write(dataStream, value[key]);
+ }
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const key in value) {
+ size += {{ key_type.ffi_converter() }}.computeSize(key);
+ size += {{ value_type.ffi_converter() }}.computeSize(value[key]);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ for (const key in value) {
+ try {
+ {{ key_type.ffi_converter() }}.checkType(key);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("(key)");
+ }
+ throw e;
+ }
+
+ try {
+ {{ value_type.ffi_converter() }}.checkType(value[key]);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${key}]`);
+ }
+ throw e;
+ }
+ }
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.sys.mjs
new file mode 100644
index 0000000000..e03291089e
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Object.sys.mjs
@@ -0,0 +1,68 @@
+{%- let object = ci.get_object_definition(name).unwrap() -%}
+export class {{ object.nm() }} {
+ // Use `init` to instantiate this class.
+ // DO NOT USE THIS CONSTRUCTOR DIRECTLY
+ constructor(opts) {
+ if (!Object.prototype.hasOwnProperty.call(opts, constructUniffiObject)) {
+ throw new UniFFIError("Attempting to construct an object using the JavaScript constructor directly" +
+ "Please use a UDL defined constructor, or the init function for the primary constructor")
+ }
+ if (!opts[constructUniffiObject] instanceof UniFFIPointer) {
+ throw new UniFFIError("Attempting to create a UniFFI object with a pointer that is not an instance of UniFFIPointer")
+ }
+ this[uniffiObjectPtr] = opts[constructUniffiObject];
+ }
+
+ {%- for cons in object.constructors() %}
+ {%- if object.is_constructor_async(config) %}
+ /**
+ * An async constructor for {{ object.nm() }}.
+ *
+ * @returns {Promise<{{ object.nm() }}>}: A promise that resolves
+ * to a newly constructed {{ object.nm() }}
+ */
+ {%- else %}
+ /**
+ * A constructor for {{ object.nm() }}.
+ *
+ * @returns { {{ object.nm() }} }
+ */
+ {%- endif %}
+ static {{ cons.nm() }}({{cons.arg_names()}}) {
+ {%- call js::call_constructor(cons, type_, object.is_constructor_async(config)) -%}
+ }
+ {%- endfor %}
+
+ {%- for meth in object.methods() %}
+
+ {{ meth.nm() }}({{ meth.arg_names() }}) {
+ {%- call js::call_method(meth, type_, object.is_method_async(meth, config)) %}
+ }
+ {%- endfor %}
+
+}
+
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static lift(value) {
+ const opts = {};
+ opts[constructUniffiObject] = value;
+ return new {{ object.nm() }}(opts);
+ }
+
+ static lower(value) {
+ return value[uniffiObjectPtr];
+ }
+
+ static read(dataStream) {
+ return this.lift(dataStream.readPointer{{ object.nm() }}());
+ }
+
+ static write(dataStream, value) {
+ dataStream.writePointer{{ object.nm() }}(value[uniffiObjectPtr]);
+ }
+
+ static computeSize(value) {
+ return 8;
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Optional.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Optional.sys.mjs
new file mode 100644
index 0000000000..a37e04abe5
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Optional.sys.mjs
@@ -0,0 +1,36 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverterArrayBuffer {
+ static checkType(value) {
+ if (value !== undefined && value !== null) {
+ {{ inner.ffi_converter() }}.checkType(value)
+ }
+ }
+
+ static read(dataStream) {
+ const code = dataStream.readUint8(0);
+ switch (code) {
+ case 0:
+ return null
+ case 1:
+ return {{ inner.ffi_converter() }}.read(dataStream)
+ default:
+ throw UniFFIError(`Unexpected code: ${code}`);
+ }
+ }
+
+ static write(dataStream, value) {
+ if (value === null || value === undefined) {
+ dataStream.writeUint8(0);
+ return;
+ }
+ dataStream.writeUint8(1);
+ {{ inner.ffi_converter() }}.write(dataStream, value)
+ }
+
+ static computeSize(value) {
+ if (value === null || value === undefined) {
+ return 1;
+ }
+ return 1 + {{ inner.ffi_converter() }}.computeSize(value)
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Record.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Record.sys.mjs
new file mode 100644
index 0000000000..0dbb0e5800
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Record.sys.mjs
@@ -0,0 +1,65 @@
+{%- let record = ci.get_record_definition(name).unwrap() -%}
+export class {{ record.nm() }} {
+ constructor({{ record.constructor_field_list() }}) {
+ {%- for field in record.fields() %}
+ try {
+ {{ field.ffi_converter() }}.checkType({{ field.nm() }})
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("{{ field.nm() }}");
+ }
+ throw e;
+ }
+ {%- endfor %}
+
+ {%- for field in record.fields() %}
+ this.{{field.nm()}} = {{ field.nm() }};
+ {%- endfor %}
+ }
+ equals(other) {
+ return (
+ {%- for field in record.fields() %}
+ {{ field.type_().equals("this.{}"|format(field.nm()), "other.{}"|format(field.nm())) }}{% if !loop.last %} &&{% endif %}
+ {%- endfor %}
+ )
+ }
+}
+
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ return new {{record.nm()}}(
+ {%- for field in record.fields() %}
+ {{ field.read_datastream_fn() }}(dataStream)
+ {%- if !loop.last %}, {% endif %}
+ {%- endfor %}
+ );
+ }
+ static write(dataStream, value) {
+ {%- for field in record.fields() %}
+ {{ field.write_datastream_fn() }}(dataStream, value.{{field.nm()}});
+ {%- endfor %}
+ }
+
+ static computeSize(value) {
+ let totalSize = 0;
+ {%- for field in record.fields() %}
+ totalSize += {{ field.ffi_converter() }}.computeSize(value.{{ field.nm() }});
+ {%- endfor %}
+ return totalSize
+ }
+
+ static checkType(value) {
+ super.checkType(value);
+ {%- for field in record.fields() %}
+ try {
+ {{ field.ffi_converter() }}.checkType(value.{{ field.nm() }});
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(".{{ field.nm() }}");
+ }
+ throw e;
+ }
+ {%- endfor %}
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Sequence.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Sequence.sys.mjs
new file mode 100644
index 0000000000..4b4c078670
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Sequence.sys.mjs
@@ -0,0 +1,43 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverterArrayBuffer {
+ static read(dataStream) {
+ const len = dataStream.readInt32();
+ const arr = [];
+ for (let i = 0; i < len; i++) {
+ arr.push({{ inner.ffi_converter() }}.read(dataStream));
+ }
+ return arr;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeInt32(value.length);
+ value.forEach((innerValue) => {
+ {{ inner.ffi_converter() }}.write(dataStream, innerValue);
+ })
+ }
+
+ static computeSize(value) {
+ // The size of the length
+ let size = 4;
+ for (const innerValue of value) {
+ size += {{ inner.ffi_converter() }}.computeSize(innerValue);
+ }
+ return size;
+ }
+
+ static checkType(value) {
+ if (!Array.isArray(value)) {
+ throw new UniFFITypeError(`${value} is not an array`);
+ }
+ value.forEach((innerValue, idx) => {
+ try {
+ {{ inner.ffi_converter() }}.checkType(innerValue);
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart(`[${idx}]`);
+ }
+ throw e;
+ }
+ })
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/String.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/String.sys.mjs
new file mode 100644
index 0000000000..d016e3f21b
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/String.sys.mjs
@@ -0,0 +1,32 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (typeof value !== "string") {
+ throw new UniFFITypeError(`${value} is not a string`);
+ }
+ }
+
+ static lift(buf) {
+ const decoder = new TextDecoder();
+ const utf8Arr = new Uint8Array(buf);
+ return decoder.decode(utf8Arr);
+ }
+ static lower(value) {
+ const encoder = new TextEncoder();
+ return encoder.encode(value).buffer;
+ }
+
+ static write(dataStream, value) {
+ dataStream.writeString(value);
+ }
+
+ static read(dataStream) {
+ return dataStream.readString();
+ }
+
+ static computeSize(value) {
+ const encoder = new TextEncoder();
+ return 4 + encoder.encode(value).length
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/TopLevelFunctions.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/TopLevelFunctions.sys.mjs
new file mode 100644
index 0000000000..601eb74d7c
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/TopLevelFunctions.sys.mjs
@@ -0,0 +1,6 @@
+{%- for func in ci.function_definitions() %}
+
+export function {{ func.nm() }}({{ func.arg_names() }}) {
+{% call js::call_scaffolding_function(func) %}
+}
+{%- endfor %}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Types.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Types.sys.mjs
new file mode 100644
index 0000000000..d17748420c
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Types.sys.mjs
@@ -0,0 +1,89 @@
+{%- if !ci.callback_interface_definitions().is_empty() %}
+{%- include "CallbackInterfaceRuntime.sys.mjs" %}
+
+{% endif %}
+
+{%- for type_ in ci.iter_types() %}
+{%- let ffi_converter = type_.ffi_converter() %}
+{%- match type_ %}
+
+{%- when Type::Boolean %}
+{%- include "Boolean.sys.mjs" %}
+
+{%- when Type::UInt8 %}
+{%- include "UInt8.sys.mjs" %}
+
+{%- when Type::UInt16 %}
+{%- include "UInt16.sys.mjs" %}
+
+{%- when Type::UInt32 %}
+{%- include "UInt32.sys.mjs" %}
+
+{%- when Type::UInt64 %}
+{%- include "UInt64.sys.mjs" %}
+
+{%- when Type::Int8 %}
+{%- include "Int8.sys.mjs" %}
+
+{%- when Type::Int16 %}
+{%- include "Int16.sys.mjs" %}
+
+{%- when Type::Int32 %}
+{%- include "Int32.sys.mjs" %}
+
+{%- when Type::Int64 %}
+{%- include "Int64.sys.mjs" %}
+
+{%- when Type::Float32 %}
+{%- include "Float32.sys.mjs" %}
+
+{%- when Type::Float64 %}
+{%- include "Float64.sys.mjs" %}
+
+{%- when Type::Record with (name) %}
+{%- include "Record.sys.mjs" %}
+
+{%- when Type::Optional with (inner) %}
+{%- include "Optional.sys.mjs" %}
+
+{%- when Type::String %}
+{%- include "String.sys.mjs" %}
+
+{%- when Type::Sequence with (inner) %}
+{%- include "Sequence.sys.mjs" %}
+
+{%- when Type::Map with (key_type, value_type) %}
+{%- include "Map.sys.mjs" %}
+
+{%- when Type::Error with (name) %}
+{%- include "Error.sys.mjs" %}
+
+{%- when Type::Enum with (name) %}
+{%- include "Enum.sys.mjs" %}
+
+{%- when Type::Object with (name) %}
+{%- include "Object.sys.mjs" %}
+
+{%- when Type::Custom with { name, builtin } %}
+{%- include "CustomType.sys.mjs" %}
+
+{%- when Type::External with { name, crate_name } %}
+{%- include "ExternalType.sys.mjs" %}
+
+{%- when Type::CallbackInterface with (name) %}
+{%- include "CallbackInterface.sys.mjs" %}
+
+{%- else %}
+{#- TODO implement the other types #}
+
+{%- endmatch %}
+
+{% endfor %}
+
+{%- if !ci.callback_interface_definitions().is_empty() %}
+// Define callback interface handlers, this must come after the type loop since they reference the FfiConverters defined above.
+
+{% for cbi in ci.callback_interface_definitions() %}
+{%- include "CallbackInterfaceHandler.sys.mjs" %}
+{% endfor %}
+{% endif %}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt16.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt16.sys.mjs
new file mode 100644
index 0000000000..569d6d2ebd
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt16.sys.mjs
@@ -0,0 +1,27 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < 0 || value > 65535) {
+ throw new UniFFITypeError(`${value} exceeds the U16 bounds`);
+ }
+ }
+ static computeSize() {
+ return 2;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint16(value)
+ }
+ static read(dataStream) {
+ return dataStream.readUint16()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt32.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt32.sys.mjs
new file mode 100644
index 0000000000..cfeffb1ecb
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt32.sys.mjs
@@ -0,0 +1,27 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < 0 || value > 4294967295) {
+ throw new UniFFITypeError(`${value} exceeds the U32 bounds`);
+ }
+ }
+ static computeSize() {
+ return 4;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint32(value)
+ }
+ static read(dataStream) {
+ return dataStream.readUint32()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt64.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt64.sys.mjs
new file mode 100644
index 0000000000..a62a0b7e6c
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt64.sys.mjs
@@ -0,0 +1,27 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isSafeInteger(value)) {
+ throw new UniFFITypeError(`${value} exceeds the safe integer bounds`);
+ }
+ if (value < 0) {
+ throw new UniFFITypeError(`${value} exceeds the U64 bounds`);
+ }
+ }
+ static computeSize() {
+ return 8;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint64(value)
+ }
+ static read(dataStream) {
+ return dataStream.readUint64()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt8.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt8.sys.mjs
new file mode 100644
index 0000000000..2f08aeee1b
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/UInt8.sys.mjs
@@ -0,0 +1,27 @@
+// Export the FFIConverter object to make external types work.
+export class {{ ffi_converter }} extends FfiConverter {
+ static checkType(value) {
+ super.checkType(value);
+ if (!Number.isInteger(value)) {
+ throw new UniFFITypeError(`${value} is not an integer`);
+ }
+ if (value < 0 || value > 256) {
+ throw new UniFFITypeError(`${value} exceeds the U8 bounds`);
+ }
+ }
+ static computeSize() {
+ return 1;
+ }
+ static lift(value) {
+ return value;
+ }
+ static lower(value) {
+ return value;
+ }
+ static write(dataStream, value) {
+ dataStream.writeUint8(value)
+ }
+ static read(dataStream) {
+ return dataStream.readUint8()
+ }
+}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/macros.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/macros.sys.mjs
new file mode 100644
index 0000000000..efec33e4e6
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/macros.sys.mjs
@@ -0,0 +1,62 @@
+{%- macro call_scaffolding_function(func) %}
+{%- call _call_scaffolding_function(func, func.return_type(), "", func.is_async(config)) -%}
+{%- endmacro %}
+
+{%- macro call_constructor(cons, object_type, is_async) %}
+{%- call _call_scaffolding_function(cons, Some(object_type), "", is_async) -%}
+{%- endmacro %}
+
+{%- macro call_method(method, object_type, is_async) %}
+{%- call _call_scaffolding_function(method, method.return_type(), object_type.ffi_converter(), is_async) -%}
+{%- endmacro %}
+
+{%- macro _call_scaffolding_function(func, return_type, receiver_ffi_converter, is_async) %}
+ {%- match return_type %}
+ {%- when Some with (return_type) %}
+ const liftResult = (result) => {{ return_type.ffi_converter() }}.lift(result);
+ {%- else %}
+ const liftResult = (result) => undefined;
+ {%- endmatch %}
+ {%- match func.throws_type() %}
+ {%- when Some with (err_type) %}
+ const liftError = (data) => {{ err_type.ffi_converter() }}.lift(data);
+ {%- else %}
+ const liftError = null;
+ {%- endmatch %}
+ const functionCall = () => {
+ {%- for arg in func.arguments() %}
+ try {
+ {{ arg.ffi_converter() }}.checkType({{ arg.nm() }})
+ } catch (e) {
+ if (e instanceof UniFFITypeError) {
+ e.addItemDescriptionPart("{{ arg.nm() }}");
+ }
+ throw e;
+ }
+ {%- endfor %}
+
+ {%- if is_async %}
+ return UniFFIScaffolding.callAsync(
+ {%- else %}
+ return UniFFIScaffolding.callSync(
+ {%- endif %}
+ {{ function_ids.get(ci, func.ffi_func()) }}, // {{ function_ids.name(ci, func.ffi_func()) }}
+ {%- if receiver_ffi_converter != "" %}
+ {{ receiver_ffi_converter }}.lower(this),
+ {%- endif %}
+ {%- for arg in func.arguments() %}
+ {{ arg.lower_fn() }}({{ arg.nm() }}),
+ {%- endfor %}
+ )
+ }
+
+ {%- if is_async %}
+ try {
+ return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
+ } catch (error) {
+ return Promise.reject(error)
+ }
+ {%- else %}
+ return handleRustResult(functionCall(), liftResult, liftError);
+ {%- endif %}
+{%- endmacro %}
diff --git a/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/wrapper.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/wrapper.sys.mjs
new file mode 100644
index 0000000000..0c33c05e4f
--- /dev/null
+++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/wrapper.sys.mjs
@@ -0,0 +1,15 @@
+// This file was autogenerated by the `uniffi-bindgen-gecko-js` crate.
+// Trust me, you don't want to mess with it!
+
+import { UniFFITypeError } from "resource://gre/modules/UniFFI.sys.mjs";
+
+{% import "macros.sys.mjs" as js %}
+
+// Objects intended to be used in the unit tests
+export var UnitTestObjs = {};
+
+{% include "Helpers.sys.mjs" %}
+
+{% include "Types.sys.mjs" %}
+
+{% include "TopLevelFunctions.sys.mjs" %}