diff options
Diffstat (limited to 'toolkit/components/uniffi-bindgen-gecko-js')
68 files changed, 16009 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..32232c64b9 --- /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.12", default-features = false, features = ["config"] } +clap = { version = "4", default-features = false, features = ["std", "derive", "cargo"] } +extend = "1.1" +heck = "0.4" +uniffi = { workspace = true } +uniffi_bindgen = "0.25" +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/RustRemoteSettings.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRemoteSettings.sys.mjs new file mode 100644 index 0000000000..ab35fbb1e7 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustRemoteSettings.sys.mjs @@ -0,0 +1,1216 @@ +// 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 RemoteSettings pointer from the data stream + // UniFFI Pointers are **always** 8 bytes long. That is enforced + // by the C++ and Rust Scaffolding code. + readPointerRemoteSettings() { + const pointerId = 0; // remote_settings:RemoteSettings + const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos); + this.pos += 8; + return res; + } + + // Writes a RemoteSettings pointer into the data stream + // UniFFI Pointers are **always** 8 bytes long. That is enforced + // by the C++ and Rust Scaffolding code. + writePointerRemoteSettings(value) { + const pointerId = 0; // remote_settings:RemoteSettings + 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 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 RemoteSettings { + // 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]; + } + /** + * A constructor for RemoteSettings. + * + * @returns { RemoteSettings } + */ + static init(remoteSettingsConfig) { + const liftResult = (result) => FfiConverterTypeRemoteSettings.lift(result); + const liftError = (data) => FfiConverterTypeRemoteSettingsError.lift(data); + const functionCall = () => { + try { + FfiConverterTypeRemoteSettingsConfig.checkType(remoteSettingsConfig) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("remoteSettingsConfig"); + } + throw e; + } + return UniFFIScaffolding.callSync( + 0, // remote_settings:uniffi_remote_settings_fn_constructor_remotesettings_new + FfiConverterTypeRemoteSettingsConfig.lower(remoteSettingsConfig), + ) + } + return handleRustResult(functionCall(), liftResult, liftError);} + + downloadAttachmentToPath(attachmentId,path) { + const liftResult = (result) => undefined; + const liftError = (data) => FfiConverterTypeRemoteSettingsError.lift(data); + const functionCall = () => { + try { + FfiConverterString.checkType(attachmentId) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("attachmentId"); + } + throw e; + } + try { + FfiConverterString.checkType(path) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("path"); + } + throw e; + } + return UniFFIScaffolding.callAsync( + 1, // remote_settings:uniffi_remote_settings_fn_method_remotesettings_download_attachment_to_path + FfiConverterTypeRemoteSettings.lower(this), + FfiConverterString.lower(attachmentId), + FfiConverterString.lower(path), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } + } + + getRecords() { + const liftResult = (result) => FfiConverterTypeRemoteSettingsResponse.lift(result); + const liftError = (data) => FfiConverterTypeRemoteSettingsError.lift(data); + const functionCall = () => { + return UniFFIScaffolding.callAsync( + 2, // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records + FfiConverterTypeRemoteSettings.lower(this), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } + } + + getRecordsSince(timestamp) { + const liftResult = (result) => FfiConverterTypeRemoteSettingsResponse.lift(result); + const liftError = (data) => FfiConverterTypeRemoteSettingsError.lift(data); + const functionCall = () => { + try { + FfiConverterU64.checkType(timestamp) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("timestamp"); + } + throw e; + } + return UniFFIScaffolding.callAsync( + 3, // remote_settings:uniffi_remote_settings_fn_method_remotesettings_get_records_since + FfiConverterTypeRemoteSettings.lower(this), + FfiConverterU64.lower(timestamp), + ) + } + 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 FfiConverterTypeRemoteSettings extends FfiConverter { + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new RemoteSettings(opts); + } + + static lower(value) { + return value[uniffiObjectPtr]; + } + + static read(dataStream) { + return this.lift(dataStream.readPointerRemoteSettings()); + } + + static write(dataStream, value) { + dataStream.writePointerRemoteSettings(value[uniffiObjectPtr]); + } + + static computeSize(value) { + return 8; + } +} + +export class Attachment { + constructor({ filename, mimetype, location, hash, size } = {}) { + try { + FfiConverterString.checkType(filename) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("filename"); + } + throw e; + } + try { + FfiConverterString.checkType(mimetype) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("mimetype"); + } + throw e; + } + try { + FfiConverterString.checkType(location) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("location"); + } + throw e; + } + try { + FfiConverterString.checkType(hash) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("hash"); + } + throw e; + } + try { + FfiConverterU64.checkType(size) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("size"); + } + throw e; + } + this.filename = filename; + this.mimetype = mimetype; + this.location = location; + this.hash = hash; + this.size = size; + } + equals(other) { + return ( + this.filename == other.filename && + this.mimetype == other.mimetype && + this.location == other.location && + this.hash == other.hash && + this.size == other.size + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeAttachment extends FfiConverterArrayBuffer { + static read(dataStream) { + return new Attachment({ + filename: FfiConverterString.read(dataStream), + mimetype: FfiConverterString.read(dataStream), + location: FfiConverterString.read(dataStream), + hash: FfiConverterString.read(dataStream), + size: FfiConverterU64.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterString.write(dataStream, value.filename); + FfiConverterString.write(dataStream, value.mimetype); + FfiConverterString.write(dataStream, value.location); + FfiConverterString.write(dataStream, value.hash); + FfiConverterU64.write(dataStream, value.size); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterString.computeSize(value.filename); + totalSize += FfiConverterString.computeSize(value.mimetype); + totalSize += FfiConverterString.computeSize(value.location); + totalSize += FfiConverterString.computeSize(value.hash); + totalSize += FfiConverterU64.computeSize(value.size); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof Attachment)) { + throw new TypeError(`Expected 'Attachment', found '${typeof value}'`); + } + try { + FfiConverterString.checkType(value.filename); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".filename"); + } + throw e; + } + try { + FfiConverterString.checkType(value.mimetype); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".mimetype"); + } + throw e; + } + try { + FfiConverterString.checkType(value.location); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".location"); + } + throw e; + } + try { + FfiConverterString.checkType(value.hash); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".hash"); + } + throw e; + } + try { + FfiConverterU64.checkType(value.size); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".size"); + } + throw e; + } + } +} + +export class RemoteSettingsConfig { + constructor({ collectionName, bucketName = null, serverUrl = null } = {}) { + try { + FfiConverterString.checkType(collectionName) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("collectionName"); + } + throw e; + } + try { + FfiConverterOptionalstring.checkType(bucketName) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("bucketName"); + } + throw e; + } + try { + FfiConverterOptionalstring.checkType(serverUrl) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("serverUrl"); + } + throw e; + } + this.collectionName = collectionName; + this.bucketName = bucketName; + this.serverUrl = serverUrl; + } + equals(other) { + return ( + this.collectionName == other.collectionName && + this.bucketName == other.bucketName && + this.serverUrl == other.serverUrl + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeRemoteSettingsConfig extends FfiConverterArrayBuffer { + static read(dataStream) { + return new RemoteSettingsConfig({ + collectionName: FfiConverterString.read(dataStream), + bucketName: FfiConverterOptionalstring.read(dataStream), + serverUrl: FfiConverterOptionalstring.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterString.write(dataStream, value.collectionName); + FfiConverterOptionalstring.write(dataStream, value.bucketName); + FfiConverterOptionalstring.write(dataStream, value.serverUrl); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterString.computeSize(value.collectionName); + totalSize += FfiConverterOptionalstring.computeSize(value.bucketName); + totalSize += FfiConverterOptionalstring.computeSize(value.serverUrl); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof RemoteSettingsConfig)) { + throw new TypeError(`Expected 'RemoteSettingsConfig', found '${typeof value}'`); + } + try { + FfiConverterString.checkType(value.collectionName); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".collectionName"); + } + throw e; + } + try { + FfiConverterOptionalstring.checkType(value.bucketName); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".bucketName"); + } + throw e; + } + try { + FfiConverterOptionalstring.checkType(value.serverUrl); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".serverUrl"); + } + throw e; + } + } +} + +export class RemoteSettingsRecord { + constructor({ id, lastModified, deleted, attachment, fields } = {}) { + try { + FfiConverterString.checkType(id) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("id"); + } + throw e; + } + try { + FfiConverterU64.checkType(lastModified) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("lastModified"); + } + throw e; + } + try { + FfiConverterBool.checkType(deleted) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("deleted"); + } + throw e; + } + try { + FfiConverterOptionalTypeAttachment.checkType(attachment) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("attachment"); + } + throw e; + } + try { + FfiConverterTypeRsJsonObject.checkType(fields) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("fields"); + } + throw e; + } + this.id = id; + this.lastModified = lastModified; + this.deleted = deleted; + this.attachment = attachment; + this.fields = fields; + } + equals(other) { + return ( + this.id == other.id && + this.lastModified == other.lastModified && + this.deleted == other.deleted && + this.attachment == other.attachment && + this.fields == other.fields + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeRemoteSettingsRecord extends FfiConverterArrayBuffer { + static read(dataStream) { + return new RemoteSettingsRecord({ + id: FfiConverterString.read(dataStream), + lastModified: FfiConverterU64.read(dataStream), + deleted: FfiConverterBool.read(dataStream), + attachment: FfiConverterOptionalTypeAttachment.read(dataStream), + fields: FfiConverterTypeRsJsonObject.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterString.write(dataStream, value.id); + FfiConverterU64.write(dataStream, value.lastModified); + FfiConverterBool.write(dataStream, value.deleted); + FfiConverterOptionalTypeAttachment.write(dataStream, value.attachment); + FfiConverterTypeRsJsonObject.write(dataStream, value.fields); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterString.computeSize(value.id); + totalSize += FfiConverterU64.computeSize(value.lastModified); + totalSize += FfiConverterBool.computeSize(value.deleted); + totalSize += FfiConverterOptionalTypeAttachment.computeSize(value.attachment); + totalSize += FfiConverterTypeRsJsonObject.computeSize(value.fields); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof RemoteSettingsRecord)) { + throw new TypeError(`Expected 'RemoteSettingsRecord', found '${typeof value}'`); + } + try { + FfiConverterString.checkType(value.id); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".id"); + } + throw e; + } + try { + FfiConverterU64.checkType(value.lastModified); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".lastModified"); + } + throw e; + } + try { + FfiConverterBool.checkType(value.deleted); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".deleted"); + } + throw e; + } + try { + FfiConverterOptionalTypeAttachment.checkType(value.attachment); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".attachment"); + } + throw e; + } + try { + FfiConverterTypeRsJsonObject.checkType(value.fields); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".fields"); + } + throw e; + } + } +} + +export class RemoteSettingsResponse { + constructor({ records, lastModified } = {}) { + try { + FfiConverterSequenceTypeRemoteSettingsRecord.checkType(records) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("records"); + } + throw e; + } + try { + FfiConverterU64.checkType(lastModified) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("lastModified"); + } + throw e; + } + this.records = records; + this.lastModified = lastModified; + } + equals(other) { + return ( + this.records == other.records && + this.lastModified == other.lastModified + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeRemoteSettingsResponse extends FfiConverterArrayBuffer { + static read(dataStream) { + return new RemoteSettingsResponse({ + records: FfiConverterSequenceTypeRemoteSettingsRecord.read(dataStream), + lastModified: FfiConverterU64.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterSequenceTypeRemoteSettingsRecord.write(dataStream, value.records); + FfiConverterU64.write(dataStream, value.lastModified); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterSequenceTypeRemoteSettingsRecord.computeSize(value.records); + totalSize += FfiConverterU64.computeSize(value.lastModified); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof RemoteSettingsResponse)) { + throw new TypeError(`Expected 'RemoteSettingsResponse', found '${typeof value}'`); + } + try { + FfiConverterSequenceTypeRemoteSettingsRecord.checkType(value.records); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".records"); + } + throw e; + } + try { + FfiConverterU64.checkType(value.lastModified); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".lastModified"); + } + throw e; + } + } +} + + + + +export class RemoteSettingsError extends Error {} + + +export class JsonError extends RemoteSettingsError { + + constructor(message, ...params) { + super(...params); + this.message = message; + } + toString() { + return `JsonError: ${super.toString()}` + } +} + +export class FileError extends RemoteSettingsError { + + constructor(message, ...params) { + super(...params); + this.message = message; + } + toString() { + return `FileError: ${super.toString()}` + } +} + +export class RequestError extends RemoteSettingsError { + + constructor(message, ...params) { + super(...params); + this.message = message; + } + toString() { + return `RequestError: ${super.toString()}` + } +} + +export class UrlParsingError extends RemoteSettingsError { + + constructor(message, ...params) { + super(...params); + this.message = message; + } + toString() { + return `UrlParsingError: ${super.toString()}` + } +} + +export class BackoffError extends RemoteSettingsError { + + constructor(message, ...params) { + super(...params); + this.message = message; + } + toString() { + return `BackoffError: ${super.toString()}` + } +} + +export class ResponseError extends RemoteSettingsError { + + constructor(message, ...params) { + super(...params); + this.message = message; + } + toString() { + return `ResponseError: ${super.toString()}` + } +} + +export class AttachmentsUnsupportedError extends RemoteSettingsError { + + constructor(message, ...params) { + super(...params); + this.message = message; + } + toString() { + return `AttachmentsUnsupportedError: ${super.toString()}` + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeRemoteSettingsError extends FfiConverterArrayBuffer { + static read(dataStream) { + switch (dataStream.readInt32()) { + case 1: + return new JsonError(FfiConverterString.read(dataStream)); + case 2: + return new FileError(FfiConverterString.read(dataStream)); + case 3: + return new RequestError(FfiConverterString.read(dataStream)); + case 4: + return new UrlParsingError(FfiConverterString.read(dataStream)); + case 5: + return new BackoffError(FfiConverterString.read(dataStream)); + case 6: + return new ResponseError(FfiConverterString.read(dataStream)); + case 7: + return new AttachmentsUnsupportedError(FfiConverterString.read(dataStream)); + default: + throw new Error("Unknown RemoteSettingsError variant"); + } + } + static computeSize(value) { + // Size of the Int indicating the variant + let totalSize = 4; + if (value instanceof JsonError) { + return totalSize; + } + if (value instanceof FileError) { + return totalSize; + } + if (value instanceof RequestError) { + return totalSize; + } + if (value instanceof UrlParsingError) { + return totalSize; + } + if (value instanceof BackoffError) { + return totalSize; + } + if (value instanceof ResponseError) { + return totalSize; + } + if (value instanceof AttachmentsUnsupportedError) { + return totalSize; + } + throw new Error("Unknown RemoteSettingsError variant"); + } + static write(dataStream, value) { + if (value instanceof JsonError) { + dataStream.writeInt32(1); + return; + } + if (value instanceof FileError) { + dataStream.writeInt32(2); + return; + } + if (value instanceof RequestError) { + dataStream.writeInt32(3); + return; + } + if (value instanceof UrlParsingError) { + dataStream.writeInt32(4); + return; + } + if (value instanceof BackoffError) { + dataStream.writeInt32(5); + return; + } + if (value instanceof ResponseError) { + dataStream.writeInt32(6); + return; + } + if (value instanceof AttachmentsUnsupportedError) { + dataStream.writeInt32(7); + return; + } + throw new Error("Unknown RemoteSettingsError variant"); + } + + static errorClass = RemoteSettingsError; +} + +// 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 FfiConverterOptionalTypeAttachment extends FfiConverterArrayBuffer { + static checkType(value) { + if (value !== undefined && value !== null) { + FfiConverterTypeAttachment.checkType(value) + } + } + + static read(dataStream) { + const code = dataStream.readUint8(0); + switch (code) { + case 0: + return null + case 1: + return FfiConverterTypeAttachment.read(dataStream) + default: + throw UniFFIError(`Unexpected code: ${code}`); + } + } + + static write(dataStream, value) { + if (value === null || value === undefined) { + dataStream.writeUint8(0); + return; + } + dataStream.writeUint8(1); + FfiConverterTypeAttachment.write(dataStream, value) + } + + static computeSize(value) { + if (value === null || value === undefined) { + return 1; + } + return 1 + FfiConverterTypeAttachment.computeSize(value) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterSequenceTypeRemoteSettingsRecord extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push(FfiConverterTypeRemoteSettingsRecord.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + FfiConverterTypeRemoteSettingsRecord.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += FfiConverterTypeRemoteSettingsRecord.computeSize(innerValue); + } + return size; + } + + static checkType(value) { + if (!Array.isArray(value)) { + throw new UniFFITypeError(`${value} is not an array`); + } + value.forEach((innerValue, idx) => { + try { + FfiConverterTypeRemoteSettingsRecord.checkType(innerValue); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(`[${idx}]`); + } + throw e; + } + }) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeRsJsonObject 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/generated/RustSuggest.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs new file mode 100644 index 0000000000..ff9507c520 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSuggest.sys.mjs @@ -0,0 +1,1991 @@ +// 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 SuggestStore pointer from the data stream + // UniFFI Pointers are **always** 8 bytes long. That is enforced + // by the C++ and Rust Scaffolding code. + readPointerSuggestStore() { + const pointerId = 1; // suggest:SuggestStore + const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos); + this.pos += 8; + return res; + } + + // Writes a SuggestStore pointer into the data stream + // UniFFI Pointers are **always** 8 bytes long. That is enforced + // by the C++ and Rust Scaffolding code. + writePointerSuggestStore(value) { + const pointerId = 1; // suggest:SuggestStore + UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos); + this.pos += 8; + } + + + // Reads a SuggestStoreBuilder pointer from the data stream + // UniFFI Pointers are **always** 8 bytes long. That is enforced + // by the C++ and Rust Scaffolding code. + readPointerSuggestStoreBuilder() { + const pointerId = 2; // suggest:SuggestStoreBuilder + const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos); + this.pos += 8; + return res; + } + + // Writes a SuggestStoreBuilder pointer into the data stream + // UniFFI Pointers are **always** 8 bytes long. That is enforced + // by the C++ and Rust Scaffolding code. + writePointerSuggestStoreBuilder(value) { + const pointerId = 2; // suggest:SuggestStoreBuilder + 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 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 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 SuggestStore { + // 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]; + } + /** + * A constructor for SuggestStore. + * + * @returns { SuggestStore } + */ + static init(path,settingsConfig = null) { + const liftResult = (result) => FfiConverterTypeSuggestStore.lift(result); + const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); + const functionCall = () => { + try { + FfiConverterString.checkType(path) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("path"); + } + throw e; + } + try { + FfiConverterOptionalTypeRemoteSettingsConfig.checkType(settingsConfig) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("settingsConfig"); + } + throw e; + } + return UniFFIScaffolding.callSync( + 4, // suggest:uniffi_suggest_fn_constructor_suggeststore_new + FfiConverterString.lower(path), + FfiConverterOptionalTypeRemoteSettingsConfig.lower(settingsConfig), + ) + } + return handleRustResult(functionCall(), liftResult, liftError);} + + clear() { + const liftResult = (result) => undefined; + const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); + const functionCall = () => { + return UniFFIScaffolding.callAsync( + 5, // suggest:uniffi_suggest_fn_method_suggeststore_clear + FfiConverterTypeSuggestStore.lower(this), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } + } + + fetchGlobalConfig() { + const liftResult = (result) => FfiConverterTypeSuggestGlobalConfig.lift(result); + const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); + const functionCall = () => { + return UniFFIScaffolding.callAsync( + 6, // suggest:uniffi_suggest_fn_method_suggeststore_fetch_global_config + FfiConverterTypeSuggestStore.lower(this), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } + } + + fetchProviderConfig(provider) { + const liftResult = (result) => FfiConverterOptionalTypeSuggestProviderConfig.lift(result); + const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); + const functionCall = () => { + try { + FfiConverterTypeSuggestionProvider.checkType(provider) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("provider"); + } + throw e; + } + return UniFFIScaffolding.callAsync( + 7, // suggest:uniffi_suggest_fn_method_suggeststore_fetch_provider_config + FfiConverterTypeSuggestStore.lower(this), + FfiConverterTypeSuggestionProvider.lower(provider), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } + } + + ingest(constraints) { + const liftResult = (result) => undefined; + const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); + const functionCall = () => { + try { + FfiConverterTypeSuggestIngestionConstraints.checkType(constraints) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("constraints"); + } + throw e; + } + return UniFFIScaffolding.callAsync( + 8, // suggest:uniffi_suggest_fn_method_suggeststore_ingest + FfiConverterTypeSuggestStore.lower(this), + FfiConverterTypeSuggestIngestionConstraints.lower(constraints), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } + } + + interrupt() { + const liftResult = (result) => undefined; + const liftError = null; + const functionCall = () => { + return UniFFIScaffolding.callSync( + 9, // suggest:uniffi_suggest_fn_method_suggeststore_interrupt + FfiConverterTypeSuggestStore.lower(this), + ) + } + return handleRustResult(functionCall(), liftResult, liftError); + } + + query(query) { + const liftResult = (result) => FfiConverterSequenceTypeSuggestion.lift(result); + const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); + const functionCall = () => { + try { + FfiConverterTypeSuggestionQuery.checkType(query) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("query"); + } + throw e; + } + return UniFFIScaffolding.callAsync( + 10, // suggest:uniffi_suggest_fn_method_suggeststore_query + FfiConverterTypeSuggestStore.lower(this), + FfiConverterTypeSuggestionQuery.lower(query), + ) + } + 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 FfiConverterTypeSuggestStore extends FfiConverter { + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new SuggestStore(opts); + } + + static lower(value) { + return value[uniffiObjectPtr]; + } + + static read(dataStream) { + return this.lift(dataStream.readPointerSuggestStore()); + } + + static write(dataStream, value) { + dataStream.writePointerSuggestStore(value[uniffiObjectPtr]); + } + + static computeSize(value) { + return 8; + } +} + +export class SuggestStoreBuilder { + // 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 SuggestStoreBuilder. + * + * @returns {Promise<SuggestStoreBuilder>}: A promise that resolves + * to a newly constructed SuggestStoreBuilder + */ + static init() { + const liftResult = (result) => FfiConverterTypeSuggestStoreBuilder.lift(result); + const liftError = null; + const functionCall = () => { + return UniFFIScaffolding.callAsync( + 11, // suggest:uniffi_suggest_fn_constructor_suggeststorebuilder_new + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + }} + + build() { + const liftResult = (result) => FfiConverterTypeSuggestStore.lift(result); + const liftError = (data) => FfiConverterTypeSuggestApiError.lift(data); + const functionCall = () => { + return UniFFIScaffolding.callAsync( + 12, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_build + FfiConverterTypeSuggestStoreBuilder.lower(this), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } + } + + cachePath(path) { + const liftResult = (result) => FfiConverterTypeSuggestStoreBuilder.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( + 13, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_cache_path + FfiConverterTypeSuggestStoreBuilder.lower(this), + FfiConverterString.lower(path), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } + } + + dataPath(path) { + const liftResult = (result) => FfiConverterTypeSuggestStoreBuilder.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( + 14, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_data_path + FfiConverterTypeSuggestStoreBuilder.lower(this), + FfiConverterString.lower(path), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } + } + + remoteSettingsConfig(config) { + const liftResult = (result) => FfiConverterTypeSuggestStoreBuilder.lift(result); + const liftError = null; + const functionCall = () => { + try { + FfiConverterTypeRemoteSettingsConfig.checkType(config) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("config"); + } + throw e; + } + return UniFFIScaffolding.callAsync( + 15, // suggest:uniffi_suggest_fn_method_suggeststorebuilder_remote_settings_config + FfiConverterTypeSuggestStoreBuilder.lower(this), + FfiConverterTypeRemoteSettingsConfig.lower(config), + ) + } + 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 FfiConverterTypeSuggestStoreBuilder extends FfiConverter { + static lift(value) { + const opts = {}; + opts[constructUniffiObject] = value; + return new SuggestStoreBuilder(opts); + } + + static lower(value) { + return value[uniffiObjectPtr]; + } + + static read(dataStream) { + return this.lift(dataStream.readPointerSuggestStoreBuilder()); + } + + static write(dataStream, value) { + dataStream.writePointerSuggestStoreBuilder(value[uniffiObjectPtr]); + } + + static computeSize(value) { + return 8; + } +} + +export class SuggestGlobalConfig { + constructor({ showLessFrequentlyCap } = {}) { + try { + FfiConverterI32.checkType(showLessFrequentlyCap) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("showLessFrequentlyCap"); + } + throw e; + } + this.showLessFrequentlyCap = showLessFrequentlyCap; + } + equals(other) { + return ( + this.showLessFrequentlyCap == other.showLessFrequentlyCap + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeSuggestGlobalConfig extends FfiConverterArrayBuffer { + static read(dataStream) { + return new SuggestGlobalConfig({ + showLessFrequentlyCap: FfiConverterI32.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterI32.write(dataStream, value.showLessFrequentlyCap); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterI32.computeSize(value.showLessFrequentlyCap); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof SuggestGlobalConfig)) { + throw new TypeError(`Expected 'SuggestGlobalConfig', found '${typeof value}'`); + } + try { + FfiConverterI32.checkType(value.showLessFrequentlyCap); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".showLessFrequentlyCap"); + } + throw e; + } + } +} + +export class SuggestIngestionConstraints { + constructor({ maxSuggestions = null } = {}) { + try { + FfiConverterOptionalu64.checkType(maxSuggestions) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("maxSuggestions"); + } + throw e; + } + this.maxSuggestions = maxSuggestions; + } + equals(other) { + return ( + this.maxSuggestions == other.maxSuggestions + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeSuggestIngestionConstraints extends FfiConverterArrayBuffer { + static read(dataStream) { + return new SuggestIngestionConstraints({ + maxSuggestions: FfiConverterOptionalu64.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterOptionalu64.write(dataStream, value.maxSuggestions); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterOptionalu64.computeSize(value.maxSuggestions); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof SuggestIngestionConstraints)) { + throw new TypeError(`Expected 'SuggestIngestionConstraints', found '${typeof value}'`); + } + try { + FfiConverterOptionalu64.checkType(value.maxSuggestions); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".maxSuggestions"); + } + throw e; + } + } +} + +export class SuggestionQuery { + constructor({ keyword, providers, limit = null } = {}) { + try { + FfiConverterString.checkType(keyword) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("keyword"); + } + throw e; + } + try { + FfiConverterSequenceTypeSuggestionProvider.checkType(providers) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("providers"); + } + throw e; + } + try { + FfiConverterOptionali32.checkType(limit) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("limit"); + } + throw e; + } + this.keyword = keyword; + this.providers = providers; + this.limit = limit; + } + equals(other) { + return ( + this.keyword == other.keyword && + this.providers == other.providers && + this.limit == other.limit + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeSuggestionQuery extends FfiConverterArrayBuffer { + static read(dataStream) { + return new SuggestionQuery({ + keyword: FfiConverterString.read(dataStream), + providers: FfiConverterSequenceTypeSuggestionProvider.read(dataStream), + limit: FfiConverterOptionali32.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterString.write(dataStream, value.keyword); + FfiConverterSequenceTypeSuggestionProvider.write(dataStream, value.providers); + FfiConverterOptionali32.write(dataStream, value.limit); + } + + static computeSize(value) { + let totalSize = 0; + totalSize += FfiConverterString.computeSize(value.keyword); + totalSize += FfiConverterSequenceTypeSuggestionProvider.computeSize(value.providers); + totalSize += FfiConverterOptionali32.computeSize(value.limit); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof SuggestionQuery)) { + throw new TypeError(`Expected 'SuggestionQuery', found '${typeof value}'`); + } + try { + FfiConverterString.checkType(value.keyword); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".keyword"); + } + throw e; + } + try { + FfiConverterSequenceTypeSuggestionProvider.checkType(value.providers); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".providers"); + } + throw e; + } + try { + FfiConverterOptionali32.checkType(value.limit); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".limit"); + } + throw e; + } + } +} + + + + +export class SuggestApiError extends Error {} + + +export class Interrupted extends SuggestApiError { + + constructor( + ...params + ) { + super(...params); + } + toString() { + return `Interrupted: ${super.toString()}` + } +} + +export class Backoff extends SuggestApiError { + + constructor( + seconds, + ...params + ) { + super(...params); + this.seconds = seconds; + } + toString() { + return `Backoff: ${super.toString()}` + } +} + +export class Network extends SuggestApiError { + + constructor( + reason, + ...params + ) { + super(...params); + this.reason = reason; + } + toString() { + return `Network: ${super.toString()}` + } +} + +export class Other extends SuggestApiError { + + constructor( + reason, + ...params + ) { + super(...params); + this.reason = reason; + } + toString() { + return `Other: ${super.toString()}` + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeSuggestApiError extends FfiConverterArrayBuffer { + static read(dataStream) { + switch (dataStream.readInt32()) { + case 1: + return new Interrupted( + ); + case 2: + return new Backoff( + FfiConverterU64.read(dataStream) + ); + case 3: + return new Network( + FfiConverterString.read(dataStream) + ); + case 4: + return new Other( + FfiConverterString.read(dataStream) + ); + default: + throw new Error("Unknown SuggestApiError variant"); + } + } + static computeSize(value) { + // Size of the Int indicating the variant + let totalSize = 4; + if (value instanceof Interrupted) { + return totalSize; + } + if (value instanceof Backoff) { + totalSize += FfiConverterU64.computeSize(value.seconds); + return totalSize; + } + if (value instanceof Network) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + if (value instanceof Other) { + totalSize += FfiConverterString.computeSize(value.reason); + return totalSize; + } + throw new Error("Unknown SuggestApiError variant"); + } + static write(dataStream, value) { + if (value instanceof Interrupted) { + dataStream.writeInt32(1); + return; + } + if (value instanceof Backoff) { + dataStream.writeInt32(2); + FfiConverterU64.write(dataStream, value.seconds); + return; + } + if (value instanceof Network) { + dataStream.writeInt32(3); + FfiConverterString.write(dataStream, value.reason); + return; + } + if (value instanceof Other) { + dataStream.writeInt32(4); + FfiConverterString.write(dataStream, value.reason); + return; + } + throw new Error("Unknown SuggestApiError variant"); + } + + static errorClass = SuggestApiError; +} + + +export class SuggestProviderConfig {} +SuggestProviderConfig.Weather = class extends SuggestProviderConfig{ + constructor( + minKeywordLength + ) { + super(); + this.minKeywordLength = minKeywordLength; + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeSuggestProviderConfig extends FfiConverterArrayBuffer { + static read(dataStream) { + switch (dataStream.readInt32()) { + case 1: + return new SuggestProviderConfig.Weather( + FfiConverterI32.read(dataStream) + ); + default: + return new Error("Unknown SuggestProviderConfig variant"); + } + } + + static write(dataStream, value) { + if (value instanceof SuggestProviderConfig.Weather) { + dataStream.writeInt32(1); + FfiConverterI32.write(dataStream, value.minKeywordLength); + return; + } + return new Error("Unknown SuggestProviderConfig variant"); + } + + static computeSize(value) { + // Size of the Int indicating the variant + let totalSize = 4; + if (value instanceof SuggestProviderConfig.Weather) { + totalSize += FfiConverterI32.computeSize(value.minKeywordLength); + return totalSize; + } + return new Error("Unknown SuggestProviderConfig variant"); + } + + static checkType(value) { + if (!(value instanceof SuggestProviderConfig)) { + throw new UniFFITypeError(`${value} is not a subclass instance of SuggestProviderConfig`); + } + } +} + + + +export class Suggestion {} +Suggestion.Amp = class extends Suggestion{ + constructor( + title, + url, + rawUrl, + icon, + fullKeyword, + blockId, + advertiser, + iabCategory, + impressionUrl, + clickUrl, + rawClickUrl, + score + ) { + super(); + this.title = title; + this.url = url; + this.rawUrl = rawUrl; + this.icon = icon; + this.fullKeyword = fullKeyword; + this.blockId = blockId; + this.advertiser = advertiser; + this.iabCategory = iabCategory; + this.impressionUrl = impressionUrl; + this.clickUrl = clickUrl; + this.rawClickUrl = rawClickUrl; + this.score = score; + } +} +Suggestion.Pocket = class extends Suggestion{ + constructor( + title, + url, + score, + isTopPick + ) { + super(); + this.title = title; + this.url = url; + this.score = score; + this.isTopPick = isTopPick; + } +} +Suggestion.Wikipedia = class extends Suggestion{ + constructor( + title, + url, + icon, + fullKeyword + ) { + super(); + this.title = title; + this.url = url; + this.icon = icon; + this.fullKeyword = fullKeyword; + } +} +Suggestion.Amo = class extends Suggestion{ + constructor( + title, + url, + iconUrl, + description, + rating, + numberOfRatings, + guid, + score + ) { + super(); + this.title = title; + this.url = url; + this.iconUrl = iconUrl; + this.description = description; + this.rating = rating; + this.numberOfRatings = numberOfRatings; + this.guid = guid; + this.score = score; + } +} +Suggestion.Yelp = class extends Suggestion{ + constructor( + url, + title, + icon, + score, + hasLocationSign, + subjectExactMatch, + locationParam + ) { + super(); + this.url = url; + this.title = title; + this.icon = icon; + this.score = score; + this.hasLocationSign = hasLocationSign; + this.subjectExactMatch = subjectExactMatch; + this.locationParam = locationParam; + } +} +Suggestion.Mdn = class extends Suggestion{ + constructor( + title, + url, + description, + score + ) { + super(); + this.title = title; + this.url = url; + this.description = description; + this.score = score; + } +} +Suggestion.Weather = class extends Suggestion{ + constructor( + score + ) { + super(); + this.score = score; + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeSuggestion extends FfiConverterArrayBuffer { + static read(dataStream) { + switch (dataStream.readInt32()) { + case 1: + return new Suggestion.Amp( + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterOptionalSequenceu8.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterI64.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterF64.read(dataStream) + ); + case 2: + return new Suggestion.Pocket( + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterF64.read(dataStream), + FfiConverterBool.read(dataStream) + ); + case 3: + return new Suggestion.Wikipedia( + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterOptionalSequenceu8.read(dataStream), + FfiConverterString.read(dataStream) + ); + case 4: + return new Suggestion.Amo( + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterOptionalstring.read(dataStream), + FfiConverterI64.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterF64.read(dataStream) + ); + case 5: + return new Suggestion.Yelp( + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterOptionalSequenceu8.read(dataStream), + FfiConverterF64.read(dataStream), + FfiConverterBool.read(dataStream), + FfiConverterBool.read(dataStream), + FfiConverterString.read(dataStream) + ); + case 6: + return new Suggestion.Mdn( + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterString.read(dataStream), + FfiConverterF64.read(dataStream) + ); + case 7: + return new Suggestion.Weather( + FfiConverterF64.read(dataStream) + ); + default: + return new Error("Unknown Suggestion variant"); + } + } + + static write(dataStream, value) { + if (value instanceof Suggestion.Amp) { + dataStream.writeInt32(1); + FfiConverterString.write(dataStream, value.title); + FfiConverterString.write(dataStream, value.url); + FfiConverterString.write(dataStream, value.rawUrl); + FfiConverterOptionalSequenceu8.write(dataStream, value.icon); + FfiConverterString.write(dataStream, value.fullKeyword); + FfiConverterI64.write(dataStream, value.blockId); + FfiConverterString.write(dataStream, value.advertiser); + FfiConverterString.write(dataStream, value.iabCategory); + FfiConverterString.write(dataStream, value.impressionUrl); + FfiConverterString.write(dataStream, value.clickUrl); + FfiConverterString.write(dataStream, value.rawClickUrl); + FfiConverterF64.write(dataStream, value.score); + return; + } + if (value instanceof Suggestion.Pocket) { + dataStream.writeInt32(2); + FfiConverterString.write(dataStream, value.title); + FfiConverterString.write(dataStream, value.url); + FfiConverterF64.write(dataStream, value.score); + FfiConverterBool.write(dataStream, value.isTopPick); + return; + } + if (value instanceof Suggestion.Wikipedia) { + dataStream.writeInt32(3); + FfiConverterString.write(dataStream, value.title); + FfiConverterString.write(dataStream, value.url); + FfiConverterOptionalSequenceu8.write(dataStream, value.icon); + FfiConverterString.write(dataStream, value.fullKeyword); + return; + } + if (value instanceof Suggestion.Amo) { + dataStream.writeInt32(4); + FfiConverterString.write(dataStream, value.title); + FfiConverterString.write(dataStream, value.url); + FfiConverterString.write(dataStream, value.iconUrl); + FfiConverterString.write(dataStream, value.description); + FfiConverterOptionalstring.write(dataStream, value.rating); + FfiConverterI64.write(dataStream, value.numberOfRatings); + FfiConverterString.write(dataStream, value.guid); + FfiConverterF64.write(dataStream, value.score); + return; + } + if (value instanceof Suggestion.Yelp) { + dataStream.writeInt32(5); + FfiConverterString.write(dataStream, value.url); + FfiConverterString.write(dataStream, value.title); + FfiConverterOptionalSequenceu8.write(dataStream, value.icon); + FfiConverterF64.write(dataStream, value.score); + FfiConverterBool.write(dataStream, value.hasLocationSign); + FfiConverterBool.write(dataStream, value.subjectExactMatch); + FfiConverterString.write(dataStream, value.locationParam); + return; + } + if (value instanceof Suggestion.Mdn) { + dataStream.writeInt32(6); + FfiConverterString.write(dataStream, value.title); + FfiConverterString.write(dataStream, value.url); + FfiConverterString.write(dataStream, value.description); + FfiConverterF64.write(dataStream, value.score); + return; + } + if (value instanceof Suggestion.Weather) { + dataStream.writeInt32(7); + FfiConverterF64.write(dataStream, value.score); + return; + } + return new Error("Unknown Suggestion variant"); + } + + static computeSize(value) { + // Size of the Int indicating the variant + let totalSize = 4; + if (value instanceof Suggestion.Amp) { + totalSize += FfiConverterString.computeSize(value.title); + totalSize += FfiConverterString.computeSize(value.url); + totalSize += FfiConverterString.computeSize(value.rawUrl); + totalSize += FfiConverterOptionalSequenceu8.computeSize(value.icon); + totalSize += FfiConverterString.computeSize(value.fullKeyword); + totalSize += FfiConverterI64.computeSize(value.blockId); + totalSize += FfiConverterString.computeSize(value.advertiser); + totalSize += FfiConverterString.computeSize(value.iabCategory); + totalSize += FfiConverterString.computeSize(value.impressionUrl); + totalSize += FfiConverterString.computeSize(value.clickUrl); + totalSize += FfiConverterString.computeSize(value.rawClickUrl); + totalSize += FfiConverterF64.computeSize(value.score); + return totalSize; + } + if (value instanceof Suggestion.Pocket) { + totalSize += FfiConverterString.computeSize(value.title); + totalSize += FfiConverterString.computeSize(value.url); + totalSize += FfiConverterF64.computeSize(value.score); + totalSize += FfiConverterBool.computeSize(value.isTopPick); + return totalSize; + } + if (value instanceof Suggestion.Wikipedia) { + totalSize += FfiConverterString.computeSize(value.title); + totalSize += FfiConverterString.computeSize(value.url); + totalSize += FfiConverterOptionalSequenceu8.computeSize(value.icon); + totalSize += FfiConverterString.computeSize(value.fullKeyword); + return totalSize; + } + if (value instanceof Suggestion.Amo) { + totalSize += FfiConverterString.computeSize(value.title); + totalSize += FfiConverterString.computeSize(value.url); + totalSize += FfiConverterString.computeSize(value.iconUrl); + totalSize += FfiConverterString.computeSize(value.description); + totalSize += FfiConverterOptionalstring.computeSize(value.rating); + totalSize += FfiConverterI64.computeSize(value.numberOfRatings); + totalSize += FfiConverterString.computeSize(value.guid); + totalSize += FfiConverterF64.computeSize(value.score); + return totalSize; + } + if (value instanceof Suggestion.Yelp) { + totalSize += FfiConverterString.computeSize(value.url); + totalSize += FfiConverterString.computeSize(value.title); + totalSize += FfiConverterOptionalSequenceu8.computeSize(value.icon); + totalSize += FfiConverterF64.computeSize(value.score); + totalSize += FfiConverterBool.computeSize(value.hasLocationSign); + totalSize += FfiConverterBool.computeSize(value.subjectExactMatch); + totalSize += FfiConverterString.computeSize(value.locationParam); + return totalSize; + } + if (value instanceof Suggestion.Mdn) { + totalSize += FfiConverterString.computeSize(value.title); + totalSize += FfiConverterString.computeSize(value.url); + totalSize += FfiConverterString.computeSize(value.description); + totalSize += FfiConverterF64.computeSize(value.score); + return totalSize; + } + if (value instanceof Suggestion.Weather) { + totalSize += FfiConverterF64.computeSize(value.score); + return totalSize; + } + return new Error("Unknown Suggestion variant"); + } + + static checkType(value) { + if (!(value instanceof Suggestion)) { + throw new UniFFITypeError(`${value} is not a subclass instance of Suggestion`); + } + } +} + + + +export const SuggestionProvider = { + AMP: 1, + POCKET: 2, + WIKIPEDIA: 3, + AMO: 4, + YELP: 5, + MDN: 6, + WEATHER: 7, + AMP_MOBILE: 8, +}; + +Object.freeze(SuggestionProvider); +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeSuggestionProvider extends FfiConverterArrayBuffer { + static read(dataStream) { + switch (dataStream.readInt32()) { + case 1: + return SuggestionProvider.AMP + case 2: + return SuggestionProvider.POCKET + case 3: + return SuggestionProvider.WIKIPEDIA + case 4: + return SuggestionProvider.AMO + case 5: + return SuggestionProvider.YELP + case 6: + return SuggestionProvider.MDN + case 7: + return SuggestionProvider.WEATHER + case 8: + return SuggestionProvider.AMP_MOBILE + default: + return new Error("Unknown SuggestionProvider variant"); + } + } + + static write(dataStream, value) { + if (value === SuggestionProvider.AMP) { + dataStream.writeInt32(1); + return; + } + if (value === SuggestionProvider.POCKET) { + dataStream.writeInt32(2); + return; + } + if (value === SuggestionProvider.WIKIPEDIA) { + dataStream.writeInt32(3); + return; + } + if (value === SuggestionProvider.AMO) { + dataStream.writeInt32(4); + return; + } + if (value === SuggestionProvider.YELP) { + dataStream.writeInt32(5); + return; + } + if (value === SuggestionProvider.MDN) { + dataStream.writeInt32(6); + return; + } + if (value === SuggestionProvider.WEATHER) { + dataStream.writeInt32(7); + return; + } + if (value === SuggestionProvider.AMP_MOBILE) { + dataStream.writeInt32(8); + return; + } + return new Error("Unknown SuggestionProvider variant"); + } + + static computeSize(value) { + return 4; + } + + static checkType(value) { + if (!Number.isInteger(value) || value < 1 || value > 8) { + throw new UniFFITypeError(`${value} is not a valid value for SuggestionProvider`); + } + } +} + + +// 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 FfiConverterOptionalu64 extends FfiConverterArrayBuffer { + static checkType(value) { + if (value !== undefined && value !== null) { + FfiConverterU64.checkType(value) + } + } + + static read(dataStream) { + const code = dataStream.readUint8(0); + switch (code) { + case 0: + return null + case 1: + return FfiConverterU64.read(dataStream) + default: + throw UniFFIError(`Unexpected code: ${code}`); + } + } + + static write(dataStream, value) { + if (value === null || value === undefined) { + dataStream.writeUint8(0); + return; + } + dataStream.writeUint8(1); + FfiConverterU64.write(dataStream, value) + } + + static computeSize(value) { + if (value === null || value === undefined) { + return 1; + } + return 1 + FfiConverterU64.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 FfiConverterOptionalTypeSuggestProviderConfig extends FfiConverterArrayBuffer { + static checkType(value) { + if (value !== undefined && value !== null) { + FfiConverterTypeSuggestProviderConfig.checkType(value) + } + } + + static read(dataStream) { + const code = dataStream.readUint8(0); + switch (code) { + case 0: + return null + case 1: + return FfiConverterTypeSuggestProviderConfig.read(dataStream) + default: + throw UniFFIError(`Unexpected code: ${code}`); + } + } + + static write(dataStream, value) { + if (value === null || value === undefined) { + dataStream.writeUint8(0); + return; + } + dataStream.writeUint8(1); + FfiConverterTypeSuggestProviderConfig.write(dataStream, value) + } + + static computeSize(value) { + if (value === null || value === undefined) { + return 1; + } + return 1 + FfiConverterTypeSuggestProviderConfig.computeSize(value) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterOptionalSequenceu8 extends FfiConverterArrayBuffer { + static checkType(value) { + if (value !== undefined && value !== null) { + FfiConverterSequenceu8.checkType(value) + } + } + + static read(dataStream) { + const code = dataStream.readUint8(0); + switch (code) { + case 0: + return null + case 1: + return FfiConverterSequenceu8.read(dataStream) + default: + throw UniFFIError(`Unexpected code: ${code}`); + } + } + + static write(dataStream, value) { + if (value === null || value === undefined) { + dataStream.writeUint8(0); + return; + } + dataStream.writeUint8(1); + FfiConverterSequenceu8.write(dataStream, value) + } + + static computeSize(value) { + if (value === null || value === undefined) { + return 1; + } + return 1 + FfiConverterSequenceu8.computeSize(value) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterOptionalTypeRemoteSettingsConfig extends FfiConverterArrayBuffer { + static checkType(value) { + if (value !== undefined && value !== null) { + FfiConverterTypeRemoteSettingsConfig.checkType(value) + } + } + + static read(dataStream) { + const code = dataStream.readUint8(0); + switch (code) { + case 0: + return null + case 1: + return FfiConverterTypeRemoteSettingsConfig.read(dataStream) + default: + throw UniFFIError(`Unexpected code: ${code}`); + } + } + + static write(dataStream, value) { + if (value === null || value === undefined) { + dataStream.writeUint8(0); + return; + } + dataStream.writeUint8(1); + FfiConverterTypeRemoteSettingsConfig.write(dataStream, value) + } + + static computeSize(value) { + if (value === null || value === undefined) { + return 1; + } + return 1 + FfiConverterTypeRemoteSettingsConfig.computeSize(value) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterSequenceu8 extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push(FfiConverterU8.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + FfiConverterU8.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += FfiConverterU8.computeSize(innerValue); + } + return size; + } + + static checkType(value) { + if (!Array.isArray(value)) { + throw new UniFFITypeError(`${value} is not an array`); + } + value.forEach((innerValue, idx) => { + try { + FfiConverterU8.checkType(innerValue); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(`[${idx}]`); + } + throw e; + } + }) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterSequenceTypeSuggestion extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push(FfiConverterTypeSuggestion.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + FfiConverterTypeSuggestion.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += FfiConverterTypeSuggestion.computeSize(innerValue); + } + return size; + } + + static checkType(value) { + if (!Array.isArray(value)) { + throw new UniFFITypeError(`${value} is not an array`); + } + value.forEach((innerValue, idx) => { + try { + FfiConverterTypeSuggestion.checkType(innerValue); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(`[${idx}]`); + } + throw e; + } + }) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterSequenceTypeSuggestionProvider extends FfiConverterArrayBuffer { + static read(dataStream) { + const len = dataStream.readInt32(); + const arr = []; + for (let i = 0; i < len; i++) { + arr.push(FfiConverterTypeSuggestionProvider.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + FfiConverterTypeSuggestionProvider.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += FfiConverterTypeSuggestionProvider.computeSize(innerValue); + } + return size; + } + + static checkType(value) { + if (!Array.isArray(value)) { + throw new UniFFITypeError(`${value} is not an array`); + } + value.forEach((innerValue, idx) => { + try { + FfiConverterTypeSuggestionProvider.checkType(innerValue); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(`[${idx}]`); + } + throw e; + } + }) + } +} + +import { + FfiConverterTypeRemoteSettingsConfig, + RemoteSettingsConfig, +} from "resource://gre/modules/RustRemoteSettings.sys.mjs"; + +// Export the FFIConverter object to make external types work. +export { FfiConverterTypeRemoteSettingsConfig, RemoteSettingsConfig }; + + + + + +export function rawSuggestionUrlMatches(rawUrl,url) { + + const liftResult = (result) => FfiConverterBool.lift(result); + const liftError = null; + const functionCall = () => { + try { + FfiConverterString.checkType(rawUrl) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("rawUrl"); + } + throw e; + } + try { + FfiConverterString.checkType(url) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("url"); + } + throw e; + } + return UniFFIScaffolding.callSync( + 16, // suggest:uniffi_suggest_fn_func_raw_suggestion_url_matches + FfiConverterString.lower(rawUrl), + FfiConverterString.lower(url), + ) + } + return handleRustResult(functionCall(), liftResult, liftError); +} diff --git a/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSync15.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSync15.sys.mjs new file mode 100644 index 0000000000..fb9b06bfa7 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustSync15.sys.mjs @@ -0,0 +1,331 @@ +// 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 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 const DeviceType = { + DESKTOP: 1, + MOBILE: 2, + TABLET: 3, + VR: 4, + TV: 5, + UNKNOWN: 6, +}; + +Object.freeze(DeviceType); +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeDeviceType extends FfiConverterArrayBuffer { + static read(dataStream) { + switch (dataStream.readInt32()) { + case 1: + return DeviceType.DESKTOP + case 2: + return DeviceType.MOBILE + case 3: + return DeviceType.TABLET + case 4: + return DeviceType.VR + case 5: + return DeviceType.TV + case 6: + return DeviceType.UNKNOWN + default: + return new Error("Unknown DeviceType variant"); + } + } + + static write(dataStream, value) { + if (value === DeviceType.DESKTOP) { + dataStream.writeInt32(1); + return; + } + if (value === DeviceType.MOBILE) { + dataStream.writeInt32(2); + return; + } + if (value === DeviceType.TABLET) { + dataStream.writeInt32(3); + return; + } + if (value === DeviceType.VR) { + dataStream.writeInt32(4); + return; + } + if (value === DeviceType.TV) { + dataStream.writeInt32(5); + return; + } + if (value === DeviceType.UNKNOWN) { + dataStream.writeInt32(6); + return; + } + return new Error("Unknown DeviceType 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 DeviceType`); + } + } +} + + + + + 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..614d7fb95b --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/components/generated/RustTabs.sys.mjs @@ -0,0 +1,1416 @@ +// 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 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 = 3; // 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 = 3; // tabs:TabsBridgedEngine + UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos); + this.pos += 8; + } + + + // 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 = 4; // 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 = 4; // tabs:TabsStore + 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 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 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]; + } + + apply() { + const liftResult = (result) => FfiConverterSequencestring.lift(result); + const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); + const functionCall = () => { + return UniFFIScaffolding.callAsync( + 17, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_apply + 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( + 18, // tabs:uniffi_tabs_fn_method_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) + } + } + + lastSync() { + const liftResult = (result) => FfiConverterI64.lift(result); + const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); + const functionCall = () => { + return UniFFIScaffolding.callAsync( + 19, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_last_sync + FfiConverterTypeTabsBridgedEngine.lower(this), + ) + } + 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( + 20, // tabs:uniffi_tabs_fn_method_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) + } + } + + reset() { + const liftResult = (result) => undefined; + const liftError = (data) => FfiConverterTypeTabsApiError.lift(data); + const functionCall = () => { + return UniFFIScaffolding.callAsync( + 21, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset + 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( + 22, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_reset_sync_id + 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( + 23, // tabs:uniffi_tabs_fn_method_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) + } + } + + 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( + 24, // tabs:uniffi_tabs_fn_method_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) + } + } + + 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( + 25, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_store_incoming + FfiConverterTypeTabsBridgedEngine.lower(this), + FfiConverterSequencestring.lower(incomingEnvelopesAsJson), + ) + } + 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( + 26, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_finished + FfiConverterTypeTabsBridgedEngine.lower(this), + ) + } + 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( + 27, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_id + FfiConverterTypeTabsBridgedEngine.lower(this), + ) + } + 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( + 28, // tabs:uniffi_tabs_fn_method_tabsbridgedengine_sync_started + 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( + 29, // tabs:uniffi_tabs_fn_method_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( + 30, // tabs:uniffi_tabs_fn_constructor_tabsstore_new + FfiConverterString.lower(path), + ) + } + 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( + 31, // tabs:uniffi_tabs_fn_method_tabsstore_bridged_engine + FfiConverterTypeTabsStore.lower(this), + ) + } + 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( + 32, // tabs:uniffi_tabs_fn_method_tabsstore_get_all + FfiConverterTypeTabsStore.lower(this), + ) + } + 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( + 33, // tabs:uniffi_tabs_fn_method_tabsstore_register_with_sync_manager + 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( + 34, // tabs:uniffi_tabs_fn_method_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) + } + } + +} + +// 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 { + FfiConverterTypeDeviceType.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({ + clientId: FfiConverterString.read(dataStream), + clientName: FfiConverterString.read(dataStream), + deviceType: FfiConverterTypeDeviceType.read(dataStream), + lastModified: FfiConverterI64.read(dataStream), + remoteTabs: FfiConverterSequenceTypeRemoteTabRecord.read(dataStream), + }); + } + static write(dataStream, value) { + FfiConverterString.write(dataStream, value.clientId); + FfiConverterString.write(dataStream, value.clientName); + FfiConverterTypeDeviceType.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 += FfiConverterTypeDeviceType.computeSize(value.deviceType); + totalSize += FfiConverterI64.computeSize(value.lastModified); + totalSize += FfiConverterSequenceTypeRemoteTabRecord.computeSize(value.remoteTabs); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof ClientRemoteTabs)) { + throw new TypeError(`Expected 'ClientRemoteTabs', found '${typeof 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 { + FfiConverterTypeDeviceType.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, inactive = false } = {}) { + 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; + } + try { + FfiConverterBool.checkType(inactive) + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart("inactive"); + } + throw e; + } + this.title = title; + this.urlHistory = urlHistory; + this.icon = icon; + this.lastUsed = lastUsed; + this.inactive = inactive; + } + equals(other) { + return ( + this.title == other.title && + this.urlHistory == other.urlHistory && + this.icon == other.icon && + this.lastUsed == other.lastUsed && + this.inactive == other.inactive + ) + } +} + +// Export the FFIConverter object to make external types work. +export class FfiConverterTypeRemoteTabRecord extends FfiConverterArrayBuffer { + static read(dataStream) { + return new RemoteTabRecord({ + title: FfiConverterString.read(dataStream), + urlHistory: FfiConverterSequencestring.read(dataStream), + icon: FfiConverterOptionalstring.read(dataStream), + lastUsed: FfiConverterI64.read(dataStream), + inactive: FfiConverterBool.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); + FfiConverterBool.write(dataStream, value.inactive); + } + + 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); + totalSize += FfiConverterBool.computeSize(value.inactive); + return totalSize + } + + static checkType(value) { + super.checkType(value); + if (!(value instanceof RemoteTabRecord)) { + throw new TypeError(`Expected 'RemoteTabRecord', found '${typeof 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; + } + try { + FfiConverterBool.checkType(value.inactive); + } catch (e) { + if (e instanceof UniFFITypeError) { + e.addItemDescriptionPart(".inactive"); + } + throw e; + } + } +} + + + + +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; + } + }) + } +} + +import { + FfiConverterTypeDeviceType, + DeviceType, +} from "resource://gre/modules/RustSync15.sys.mjs"; + +// Export the FFIConverter object to make external types work. +export { FfiConverterTypeDeviceType, DeviceType }; + +// 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..107745a4b8 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/components/moz.build @@ -0,0 +1,15 @@ +# -*- 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/RustRemoteSettings.sys.mjs", + "generated/RustSuggest.sys.mjs", + "generated/RustSync15.sys.mjs", + "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..d59b2a69e1 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/config.toml @@ -0,0 +1,86 @@ +# Configure UniFFI sources +# +# Each key is the UDL namespace of the component. +# +# +# 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. + +# TODO: Upgrade the TOML crate and switch to array of tables syntax. + +[sync15] +crate_name = "sync15" +udl_file = "third_party/rust/sync15/src/sync15.udl" + +[tabs] +crate_name = "tabs" +udl_file = "third_party/rust/tabs/src/tabs.udl" + +[suggest] +crate_name = "suggest" +udl_file = "third_party/rust/suggest/src/suggest.udl" + +[suggest.receiver_thread] +default = "worker" +main = [ + "raw_suggestion_url_matches", + "SuggestStore", + "SuggestStore.interrupt", +] + +[remote_settings] +crate_name = "remote_settings" +udl_file = "third_party/rust/remote_settings/src/remote_settings.udl" + +[remote_settings.receiver_thread] +default = "worker" +main = [ + "RemoteSettings", +] + +[geometry] +crate_name = "uniffi_geometry" +udl_file = "third_party/rust/uniffi-example-geometry/src/geometry.udl" +fixture = true + +[arithmetic] +crate_name = "arithmetical" +udl_file = "third_party/rust/uniffi-example-arithmetic/src/arithmetic.udl" +fixture = true + +[rondpoint] +crate_name = "uniffi_rondpoint" +udl_file = "third_party/rust/uniffi-example-rondpoint/src/rondpoint.udl" +fixture = true + +[sprites] +crate_name = "uniffi_sprites" +udl_file = "third_party/rust/uniffi-example-sprites/src/sprites.udl" +fixture = true + +[todolist] +crate_name = "uniffi_todolist" +udl_file = "third_party/rust/uniffi-example-todolist/src/todolist.udl" +fixture = true + +[fixture_callbacks] +crate_name = "uniffi_fixture_callbacks" +udl_file = "toolkit/components/uniffi-fixture-callbacks/src/callbacks.udl" +fixture = true + +[fixture_callbacks.receiver_thread] +default = "worker" +main = [ + "log_even_numbers_main_thread", +] + +[custom_types] +crate_name = "uniffi_custom_types" +udl_file = "toolkit/components/uniffi-example-custom-types/src/custom-types.udl" +fixture = true + +[external_types] +crate_name = "uniffi_fixture_external_types" +udl_file = "toolkit/components/uniffi-fixture-external-types/src/external-types.udl" +fixture = true 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..1790f0effa --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustArithmetic.sys.mjs @@ -0,0 +1,492 @@ +// 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( + 35, // arithmetic:uniffi_arithmetical_fn_func_add + 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( + 36, // arithmetic:uniffi_arithmetical_fn_func_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( + 37, // arithmetic:uniffi_arithmetical_fn_func_equal + 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( + 38, // arithmetic:uniffi_arithmetical_fn_func_sub + 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..286c046fa6 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustCustomTypes.sys.mjs @@ -0,0 +1,467 @@ +// 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({ + url: FfiConverterTypeUrl.read(dataStream), + handle: 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); + if (!(value instanceof CustomTypesDemo)) { + throw new TypeError(`Expected 'CustomTypesDemo', found '${typeof 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( + 39, // custom_types:uniffi_uniffi_custom_types_fn_func_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..c01b1a58b3 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustExternalTypes.sys.mjs @@ -0,0 +1,427 @@ +// 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) + } +} + +// 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) + } +} + +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( + 40, // external_types:uniffi_uniffi_fixture_external_types_fn_func_gradient + FfiConverterOptionalTypeLine.lower(value), + ) + } + 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( + 41, // external_types:uniffi_uniffi_fixture_external_types_fn_func_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/RustFixtureCallbacks.sys.mjs b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustFixtureCallbacks.sys.mjs new file mode 100644 index 0000000000..75fe81a458 --- /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 FfiConverterTypeLogger 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 { + FfiConverterTypeLogger.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( + 42, // fixture_callbacks:uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers + FfiConverterTypeLogger.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 { + FfiConverterTypeLogger.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( + 43, // fixture_callbacks:uniffi_uniffi_fixture_callbacks_fn_func_log_even_numbers_main_thread + FfiConverterTypeLogger.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..1a7ebb287a --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustGeometry.sys.mjs @@ -0,0 +1,520 @@ +// 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({ + start: FfiConverterTypePoint.read(dataStream), + end: 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); + if (!(value instanceof Line)) { + throw new TypeError(`Expected 'Line', found '${typeof 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({ + coordX: FfiConverterF64.read(dataStream), + coordY: 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); + if (!(value instanceof Point)) { + throw new TypeError(`Expected 'Point', found '${typeof 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( + 44, // geometry:uniffi_uniffi_geometry_fn_func_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( + 45, // geometry:uniffi_uniffi_geometry_fn_func_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..1edb7ec608 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustRondpoint.sys.mjs @@ -0,0 +1,3384 @@ +// 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 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 = 5; // 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 = 5; // rondpoint:Optionneur + UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos); + this.pos += 8; + } + + + // 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 = 6; // 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 = 6; // 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 = 7; // 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 = 7; // rondpoint:Stringifier + 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( + 46, // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_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( + 47, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_boolean + FfiConverterTypeOptionneur.lower(this), + FfiConverterBool.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( + 48, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_enum + FfiConverterTypeOptionneur.lower(this), + FfiConverterTypeEnumeration.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( + 49, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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( + 50, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_f64 + FfiConverterTypeOptionneur.lower(this), + FfiConverterF64.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( + 51, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 52, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 53, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 54, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 55, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 56, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 57, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 58, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_null + FfiConverterTypeOptionneur.lower(this), + FfiConverterOptionalstring.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( + 60, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_sequence + FfiConverterTypeOptionneur.lower(this), + FfiConverterSequencestring.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( + 61, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_string + FfiConverterTypeOptionneur.lower(this), + FfiConverterString.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( + 62, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 63, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 64, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 65, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 66, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 68, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 69, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 70, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 71, // rondpoint:uniffi_uniffi_rondpoint_fn_method_optionneur_sinon_zero + FfiConverterTypeOptionneur.lower(this), + FfiConverterOptionali32.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( + 72, // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_retourneur_new + ) + } + 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( + 73, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_boolean + FfiConverterTypeRetourneur.lower(this), + FfiConverterBool.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( + 74, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_double + FfiConverterTypeRetourneur.lower(this), + FfiConverterF64.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( + 75, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_float + FfiConverterTypeRetourneur.lower(this), + FfiConverterF32.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( + 76, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i16 + FfiConverterTypeRetourneur.lower(this), + FfiConverterI16.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( + 77, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i32 + FfiConverterTypeRetourneur.lower(this), + FfiConverterI32.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( + 78, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i64 + FfiConverterTypeRetourneur.lower(this), + FfiConverterI64.lower(value), + ) + } + 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( + 79, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_i8 + FfiConverterTypeRetourneur.lower(this), + FfiConverterI8.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( + 80, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_nombres + FfiConverterTypeRetourneur.lower(this), + FfiConverterTypeDictionnaireNombres.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( + 81, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 82, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 83, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_string + FfiConverterTypeRetourneur.lower(this), + FfiConverterString.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( + 84, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u16 + FfiConverterTypeRetourneur.lower(this), + FfiConverterU16.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( + 85, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u32 + FfiConverterTypeRetourneur.lower(this), + FfiConverterU32.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( + 86, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u64 + FfiConverterTypeRetourneur.lower(this), + FfiConverterU64.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( + 87, // rondpoint:uniffi_uniffi_rondpoint_fn_method_retourneur_identique_u8 + FfiConverterTypeRetourneur.lower(this), + FfiConverterU8.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( + 88, // rondpoint:uniffi_uniffi_rondpoint_fn_constructor_stringifier_new + ) + } + 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( + 89, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 90, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 91, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 92, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 93, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 94, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 95, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 96, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 97, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 98, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 99, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + + 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( + 100, // rondpoint:uniffi_uniffi_rondpoint_fn_method_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) + } + } + +} + +// 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({ + un: FfiConverterTypeEnumeration.read(dataStream), + deux: FfiConverterBool.read(dataStream), + petitNombre: FfiConverterU8.read(dataStream), + grosNombre: 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); + if (!(value instanceof Dictionnaire)) { + throw new TypeError(`Expected 'Dictionnaire', found '${typeof 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({ + petitNombre: FfiConverterU8.read(dataStream), + courtNombre: FfiConverterU16.read(dataStream), + nombreSimple: FfiConverterU32.read(dataStream), + grosNombre: 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); + if (!(value instanceof DictionnaireNombres)) { + throw new TypeError(`Expected 'DictionnaireNombres', found '${typeof 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({ + petitNombre: FfiConverterI8.read(dataStream), + courtNombre: FfiConverterI16.read(dataStream), + nombreSimple: FfiConverterI32.read(dataStream), + grosNombre: 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); + if (!(value instanceof DictionnaireNombresSignes)) { + throw new TypeError(`Expected 'DictionnaireNombresSignes', found '${typeof 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({ + i8Var: FfiConverterI8.read(dataStream), + u8Var: FfiConverterU8.read(dataStream), + i16Var: FfiConverterI16.read(dataStream), + u16Var: FfiConverterU16.read(dataStream), + i32Var: FfiConverterI32.read(dataStream), + u32Var: FfiConverterU32.read(dataStream), + i64Var: FfiConverterI64.read(dataStream), + u64Var: FfiConverterU64.read(dataStream), + floatVar: FfiConverterF32.read(dataStream), + doubleVar: FfiConverterF64.read(dataStream), + booleanVar: FfiConverterBool.read(dataStream), + stringVar: FfiConverterString.read(dataStream), + listVar: FfiConverterSequencestring.read(dataStream), + enumerationVar: FfiConverterTypeEnumeration.read(dataStream), + dictionnaireVar: 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); + if (!(value instanceof OptionneurDictionnaire)) { + throw new TypeError(`Expected 'OptionneurDictionnaire', found '${typeof 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({ + minusculeMajusculeField: 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); + if (!(value instanceof MinusculeMajusculeDict)) { + throw new TypeError(`Expected 'MinusculeMajusculeDict', found '${typeof 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 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( + 101, // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_carte + FfiConverterMapStringTypeEnumerationAvecDonnees.lower(c), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } +} + +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( + 102, // rondpoint:uniffi_uniffi_rondpoint_fn_func_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( + 103, // rondpoint:uniffi_uniffi_rondpoint_fn_func_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( + 104, // rondpoint:uniffi_uniffi_rondpoint_fn_func_copie_enumerations + FfiConverterSequenceTypeEnumeration.lower(e), + ) + } + 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( + 105, // rondpoint:uniffi_uniffi_rondpoint_fn_func_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..b404af06b1 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustSprites.sys.mjs @@ -0,0 +1,687 @@ +// 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 = 8; // 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 = 8; // 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( + 106, // sprites:uniffi_uniffi_sprites_fn_constructor_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( + 107, // sprites:uniffi_uniffi_sprites_fn_constructor_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( + 108, // sprites:uniffi_uniffi_sprites_fn_method_sprite_get_position + FfiConverterTypeSprite.lower(this), + ) + } + 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( + 109, // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_by + FfiConverterTypeSprite.lower(this), + FfiConverterTypeVector.lower(direction), + ) + } + 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( + 110, // sprites:uniffi_uniffi_sprites_fn_method_sprite_move_to + FfiConverterTypeSprite.lower(this), + FfiConverterTypePoint.lower(position), + ) + } + 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({ + x: FfiConverterF64.read(dataStream), + y: 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); + if (!(value instanceof Point)) { + throw new TypeError(`Expected 'Point', found '${typeof 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({ + dx: FfiConverterF64.read(dataStream), + dy: 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); + if (!(value instanceof Vector)) { + throw new TypeError(`Expected 'Vector', found '${typeof 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( + 111, // sprites:uniffi_uniffi_sprites_fn_func_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..59996b78fa --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/generated/RustTodolist.sys.mjs @@ -0,0 +1,929 @@ +// 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 = 9; // 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 = 9; // 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( + 112, // todolist:uniffi_uniffi_todolist_fn_constructor_todolist_new + ) + } + 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( + 113, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entries + FfiConverterTypeTodoList.lower(this), + FfiConverterSequenceTypeTodoEntry.lower(entries), + ) + } + 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( + 114, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_entry + FfiConverterTypeTodoList.lower(this), + FfiConverterTypeTodoEntry.lower(entry), + ) + } + 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( + 115, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_item + FfiConverterTypeTodoList.lower(this), + FfiConverterString.lower(todo), + ) + } + 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( + 116, // todolist:uniffi_uniffi_todolist_fn_method_todolist_add_items + FfiConverterTypeTodoList.lower(this), + FfiConverterSequencestring.lower(items), + ) + } + 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( + 117, // todolist:uniffi_uniffi_todolist_fn_method_todolist_clear_item + FfiConverterTypeTodoList.lower(this), + FfiConverterString.lower(todo), + ) + } + 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( + 118, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_entries + 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( + 119, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_first + 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( + 120, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_items + 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( + 121, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last + FfiConverterTypeTodoList.lower(this), + ) + } + 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( + 122, // todolist:uniffi_uniffi_todolist_fn_method_todolist_get_last_entry + FfiConverterTypeTodoList.lower(this), + ) + } + 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( + 123, // todolist:uniffi_uniffi_todolist_fn_method_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({ + text: 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); + if (!(value instanceof TodoEntry)) { + throw new TypeError(`Expected 'TodoEntry', found '${typeof 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 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( + 124, // todolist:uniffi_uniffi_todolist_fn_func_create_entry_with + FfiConverterString.lower(todo), + ) + } + try { + return functionCall().then((result) => handleRustResult(result, liftResult, liftError)); + } catch (error) { + return Promise.reject(error) + } +} + +export function getDefaultList() { + + const liftResult = (result) => FfiConverterOptionalTypeTodoList.lift(result); + const liftError = null; + const functionCall = () => { + return UniFFIScaffolding.callAsync( + 125, // todolist:uniffi_uniffi_todolist_fn_func_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( + 126, // todolist:uniffi_uniffi_todolist_fn_func_set_default_list + FfiConverterTypeTodoList.lower(list), + ) + } + 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..d5ff2d7cb6 --- /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.toml"] 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..cdb552e4ef --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/test_geometry.js @@ -0,0 +1,29 @@ +/* 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({ coord_x: 0, coord_y: 0 }), + new Geometry.Point({ coord_x: 1, coord_y: 2 }) + ); + const ln2 = new Geometry.Line( + new Geometry.Point({ coord_x: 1, coord_y: 1 }), + new Geometry.Point({ coord_x: 2, coord_y: 2 }) + ); + const origin = new Geometry.Point({ coord_x: 0, coord_y: 0 }); + Assert.ok( + (await Geometry.intersection({ start: ln1, end: ln2 })).equals(origin) + ); + Assert.deepEqual( + await Geometry.intersection({ start: ln1, end: ln2 }), + origin + ); + Assert.strictEqual( + await Geometry.intersection({ start: ln1, end: 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.toml b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.toml new file mode 100644 index 0000000000..76814ff199 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/fixtures/tests/xpcshell/xpcshell.toml @@ -0,0 +1,19 @@ +[DEFAULT] + +["test_arithmetic.js"] + +["test_callbacks.js"] + +["test_custom_types.js"] + +["test_external_types.js"] + +["test_geometry.js"] + +["test_rondpoint.js"] + +["test_sprites.js"] + +["test_todolist.js"] + +["test_type_checking.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..95584e705c --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/mach_commands.py @@ -0,0 +1,71 @@ +# 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 + +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, + ] + 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..e79283cd57 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/ci_list.rs @@ -0,0 +1,198 @@ +/* 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(config_map: ConfigMap) -> Result<Self> { + let universe = Self { + components: parse_udl_files(&config_map, false)?, + fixture_components: parse_udl_files(&config_map, true)?, + }; + 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_files( + config_map: &ConfigMap, + fixture: bool, +) -> Result<Vec<(ComponentInterface, Config)>> { + // Sort config entries to ensure consistent output + let mut entries: Vec<_> = config_map.iter().collect(); + entries.sort_by_key(|(key, _)| *key); + entries + .into_iter() + .filter_map(|(_, config)| { + if config.fixture == fixture { + Some(parse_udl_file(&config).map(|ci| (ci, config.clone()))) + } else { + None + } + }) + .collect() +} + +fn parse_udl_file(config: &Config) -> Result<ComponentInterface> { + let udl_file = Utf8PathBuf::from(&config.udl_file); + let udl = std::fs::read_to_string(udl_file) + .context(format!("Error reading UDL file '{}'", config.udl_file))?; + ComponentInterface::from_webidl(&udl, &config.crate_name) + .context(format!("Failed to parse UDL '{}'", config.udl_file)) +} + +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..32b7cb438b --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/lib.rs @@ -0,0 +1,157 @@ +/* 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, +} + +/// 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 { + crate_name: String, + udl_file: String, + #[serde(default)] + fixture: bool, + #[serde(default)] + 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(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..685c3c2bf3 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/cpp.rs @@ -0,0 +1,199 @@ +/* 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"), + FfiType::ForeignExecutorHandle => unimplemented!("ForeignExecutorHandle not supported"), + FfiType::ForeignExecutorCallback => { + unimplemented!("ForeignExecutorCallback not supported") + } + FfiType::RustFutureHandle + | FfiType::RustFutureContinuationCallback + | FfiType::RustFutureContinuationData => { + unimplemented!("Rust async functions 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..efd7b42456 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/js.rs @@ -0,0 +1,333 @@ +/* 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, AsType, CallbackInterface, ComponentInterface, Constructor, Enum, 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 { name, .. } = typ { + // TODO: This does not support complex enum literals yet. + return format!( + "{}.{}", + 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 { + let o = 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(", "); + format!("{{ {o} }}") + } +} + +#[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.as_type().lower_fn() + } + + fn lift_fn(&self) -> String { + self.as_type().lift_fn() + } + + fn write_datastream_fn(&self) -> String { + self.as_type().write_datastream_fn() + } + + fn read_datastream_fn(&self) -> String { + self.as_type().read_datastream_fn() + } + + fn compute_size_fn(&self) -> String { + self.as_type().compute_size_fn() + } + + fn ffi_converter(&self) -> String { + self.as_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.as_type().lower_fn() + } + + fn lift_fn(&self) -> String { + self.as_type().lift_fn() + } + + fn write_datastream_fn(&self) -> String { + self.as_type().write_datastream_fn() + } + + fn read_datastream_fn(&self) -> String { + self.as_type().read_datastream_fn() + } + + fn compute_size_fn(&self) -> String { + self.as_type().compute_size_fn() + } + + fn ffi_converter(&self) -> String { + self.as_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 canonical_name(&self) -> String { + match self { + Type::Int8 => "i8".into(), + Type::UInt8 => "u8".into(), + Type::Int16 => "i16".into(), + Type::UInt16 => "u16".into(), + Type::Int32 => "i32".into(), + Type::UInt32 => "u32".into(), + Type::Int64 => "i64".into(), + Type::UInt64 => "u64".into(), + Type::Float32 => "f32".into(), + Type::Float64 => "f64".into(), + Type::String => "string".into(), + Type::Bytes => "bytes".into(), + Type::Boolean => "bool".into(), + Type::Object { name, .. } + | Type::Enum { name, .. } + | Type::Record { name, .. } + | Type::CallbackInterface { name, .. } => format!("Type{name}"), + Type::Timestamp => "Timestamp".into(), + Type::Duration => "Duration".into(), + Type::ForeignExecutor => "ForeignExecutor".into(), + Type::Optional { inner_type } => format!("Optional{}", inner_type.canonical_name()), + Type::Sequence { inner_type } => format!("Sequence{}", inner_type.canonical_name()), + Type::Map { + key_type, + value_type, + } => format!( + "Map{}{}", + key_type.canonical_name().to_upper_camel_case(), + value_type.canonical_name().to_upper_camel_case() + ), + Type::External { name, .. } | Type::Custom { name, .. } => format!("Type{name}"), + } + } + + 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=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..7b2d2e19ad --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/render/shared.rs @@ -0,0 +1,43 @@ +/* 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}; + +/// Check if a JS function should be async. +/// +/// `uniffi-bindgen-gecko-js` has special async handling. Many non-async Rust functions end up +/// being async in js +fn is_js_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_js_async(&self, config: &Config) -> bool { + is_js_async(config, self.name()) + } +} + +#[ext] +pub impl Object { + fn is_constructor_async(&self, config: &Config) -> bool { + is_js_async(config, self.name()) + } + + fn is_method_async(&self, method: &Method, config: &Config) -> bool { + is_js_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..5c4ed8c2f5 --- /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, const uint8_t* aArgsData, int32_t aArgsLen, 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, aArgsData, aArgsLen); + 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..f7716ac6d8 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Enum.sys.mjs @@ -0,0 +1,113 @@ +{%- 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..b140d908da --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Error.sys.mjs @@ -0,0 +1,79 @@ +{%- 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..4661b23bf6 --- /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(module_path) }}"; + +// 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..836ea81b89 --- /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_type.ffi_converter() }}.checkType(value) + } + } + + static read(dataStream) { + const code = dataStream.readUint8(0); + switch (code) { + case 0: + return null + case 1: + return {{ inner_type.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_type.ffi_converter() }}.write(dataStream, value) + } + + static computeSize(value) { + if (value === null || value === undefined) { + return 1; + } + return 1 + {{ inner_type.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..2f54160b9e --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Record.sys.mjs @@ -0,0 +1,67 @@ +{%- 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.as_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.nm() }}: {{ field.read_datastream_fn() }}(dataStream), + {%- 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); + if (!(value instanceof {{ record.nm() }})) { + throw new TypeError(`Expected '{{ record.nm() }}', found '${typeof 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..4c1034a182 --- /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_type.ffi_converter() }}.read(dataStream)); + } + return arr; + } + + static write(dataStream, value) { + dataStream.writeInt32(value.length); + value.forEach((innerValue) => { + {{ inner_type.ffi_converter() }}.write(dataStream, innerValue); + }) + } + + static computeSize(value) { + // The size of the length + let size = 4; + for (const innerValue of value) { + size += {{ inner_type.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_type.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..a5dfd9c0c7 --- /dev/null +++ b/toolkit/components/uniffi-bindgen-gecko-js/src/templates/js/Types.sys.mjs @@ -0,0 +1,94 @@ +{%- 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 { name, module_path } %} +{%- include "Record.sys.mjs" %} + +{%- when Type::Optional { inner_type } %} +{%- include "Optional.sys.mjs" %} + +{%- when Type::String %} +{%- include "String.sys.mjs" %} + +{%- when Type::Sequence { inner_type } %} +{%- include "Sequence.sys.mjs" %} + +{%- when Type::Map { key_type, value_type } %} +{%- include "Map.sys.mjs" %} + +{%- when Type::Enum { name, module_path } %} +{%- let e = ci.get_enum_definition(name).unwrap() %} +{# For enums, there are either an error *or* an enum, they can't be both. #} +{%- if ci.is_name_used_as_error(name) %} +{%- let error = e %} +{%- include "Error.sys.mjs" %} +{%- else %} +{%- let enum_ = e %} +{%- include "Enum.sys.mjs" %} +{% endif %} + +{%- when Type::Object { name, imp, module_path } %} +{%- include "Object.sys.mjs" %} + +{%- when Type::Custom { name, builtin, module_path } %} +{%- include "CustomType.sys.mjs" %} + +{%- when Type::External { name, module_path, kind, namespace, tagged } %} +{%- include "ExternalType.sys.mjs" %} + +{%- when Type::CallbackInterface { name, module_path } %} +{%- 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..d0dfed6c85 --- /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_js_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" %} |