// 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;
    }

    readBytes() {
      const size = this.readInt32();
      const bytes = new Uint8Array(this.dataView.buffer, this.pos, size);
      this.pos += size;
      return bytes
    }

    writeBytes(uint8Array) {
      this.writeUint32(uint8Array.length);
      value.forEach((elt) => {
        dataStream.writeUint8(elt);
      })
    }

    // Reads a WebExtStorageBridgedEngine pointer from the data stream
    // UniFFI Pointers are **always** 8 bytes long. That is enforced
    // by the C++ and Rust Scaffolding code.
    readPointerWebExtStorageBridgedEngine() {
        const pointerId = 9; // webextstorage:WebExtStorageBridgedEngine
        const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos);
        this.pos += 8;
        return res;
    }

    // Writes a WebExtStorageBridgedEngine pointer into the data stream
    // UniFFI Pointers are **always** 8 bytes long. That is enforced
    // by the C++ and Rust Scaffolding code.
    writePointerWebExtStorageBridgedEngine(value) {
        const pointerId = 9; // webextstorage:WebExtStorageBridgedEngine
        UniFFIScaffolding.writePointer(pointerId, value, this.dataView.buffer, this.pos);
        this.pos += 8;
    }
    

    // Reads a WebExtStorageStore pointer from the data stream
    // UniFFI Pointers are **always** 8 bytes long. That is enforced
    // by the C++ and Rust Scaffolding code.
    readPointerWebExtStorageStore() {
        const pointerId = 10; // webextstorage:WebExtStorageStore
        const res = UniFFIScaffolding.readPointer(pointerId, this.dataView.buffer, this.pos);
        this.pos += 8;
        return res;
    }

    // Writes a WebExtStorageStore pointer into the data stream
    // UniFFI Pointers are **always** 8 bytes long. That is enforced
    // by the C++ and Rust Scaffolding code.
    writePointerWebExtStorageStore(value) {
        const pointerId = 10; // webextstorage:WebExtStorageStore
        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":
            if (result.data) {
                throw new UniFFIInternalError(FfiConverterString.lift(result.data));
            } 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 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
    }
}

/**
 * WebExtStorageBridgedEngine
 */
export class WebExtStorageBridgedEngine {
    // 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
     * @returns {Array.<string>}
     */
    apply() {
        const liftResult = (result) => FfiConverterSequencestring.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                69, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_apply
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * ensureCurrentSyncId
     * @returns {string}
     */
    ensureCurrentSyncId(newSyncId) {
        const liftResult = (result) => FfiConverterString.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterString.checkType(newSyncId)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("newSyncId");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                70, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_ensure_current_sync_id
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
                FfiConverterString.lower(newSyncId),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * lastSync
     * @returns {number}
     */
    lastSync() {
        const liftResult = (result) => FfiConverterI64.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                71, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_last_sync
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * prepareForSync
     */
    prepareForSync(clientData) {
        const liftResult = (result) => undefined;
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterString.checkType(clientData)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("clientData");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                72, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_prepare_for_sync
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
                FfiConverterString.lower(clientData),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * reset
     */
    reset() {
        const liftResult = (result) => undefined;
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                73, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * resetSyncId
     * @returns {string}
     */
    resetSyncId() {
        const liftResult = (result) => FfiConverterString.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                74, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_reset_sync_id
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * setLastSync
     */
    setLastSync(lastSync) {
        const liftResult = (result) => undefined;
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterI64.checkType(lastSync)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("lastSync");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                75, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_last_sync
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
                FfiConverterI64.lower(lastSync),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * setUploaded
     */
    setUploaded(serverModifiedMillis,guids) {
        const liftResult = (result) => undefined;
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterI64.checkType(serverModifiedMillis)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("serverModifiedMillis");
                }
                throw e;
            }
            try {
                FfiConverterSequenceTypeGuid.checkType(guids)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("guids");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                76, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_set_uploaded
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
                FfiConverterI64.lower(serverModifiedMillis),
                FfiConverterSequenceTypeGuid.lower(guids),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * storeIncoming
     */
    storeIncoming(incoming) {
        const liftResult = (result) => undefined;
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterSequencestring.checkType(incoming)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("incoming");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                77, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_store_incoming
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
                FfiConverterSequencestring.lower(incoming),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * syncFinished
     */
    syncFinished() {
        const liftResult = (result) => undefined;
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                78, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_finished
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * syncId
     * @returns {?string}
     */
    syncId() {
        const liftResult = (result) => FfiConverterOptionalstring.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                79, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_id
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * syncStarted
     */
    syncStarted() {
        const liftResult = (result) => undefined;
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                80, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_sync_started
                FfiConverterTypeWebExtStorageBridgedEngine.lower(this),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * wipe
     */
    wipe() {
        const liftResult = (result) => undefined;
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                81, // webextstorage:uniffi_webext_storage_fn_method_webextstoragebridgedengine_wipe
                FfiConverterTypeWebExtStorageBridgedEngine.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 FfiConverterTypeWebExtStorageBridgedEngine extends FfiConverter {
    static lift(value) {
        const opts = {};
        opts[constructUniffiObject] = value;
        return new WebExtStorageBridgedEngine(opts);
    }

    static lower(value) {
        const ptr = value[uniffiObjectPtr];
        if (!(ptr instanceof UniFFIPointer)) {
            throw new UniFFITypeError("Object is not a 'WebExtStorageBridgedEngine' instance");
        }
        return ptr;
    }

    static read(dataStream) {
        return this.lift(dataStream.readPointerWebExtStorageBridgedEngine());
    }

    static write(dataStream, value) {
        dataStream.writePointerWebExtStorageBridgedEngine(value[uniffiObjectPtr]);
    }

    static computeSize(value) {
        return 8;
    }
}

/**
 * WebExtStorageStore
 */
export class WebExtStorageStore {
    // 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];
    }
    /**
     * init
     * @returns {WebExtStorageStore}
     */
    static init(path) {
        const liftResult = (result) => FfiConverterTypeWebExtStorageStore.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterString.checkType(path)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("path");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                90, // webextstorage:uniffi_webext_storage_fn_constructor_webextstoragestore_new
                FfiConverterString.lower(path),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }}

    /**
     * bridgedEngine
     * @returns {WebExtStorageBridgedEngine}
     */
    bridgedEngine() {
        const liftResult = (result) => FfiConverterTypeWebExtStorageBridgedEngine.lift(result);
        const liftError = null;
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                82, // webextstorage:uniffi_webext_storage_fn_method_webextstoragestore_bridged_engine
                FfiConverterTypeWebExtStorageStore.lower(this),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * clear
     * @returns {StorageChanges}
     */
    clear(extId) {
        const liftResult = (result) => FfiConverterTypeStorageChanges.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterString.checkType(extId)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("extId");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                83, // webextstorage:uniffi_webext_storage_fn_method_webextstoragestore_clear
                FfiConverterTypeWebExtStorageStore.lower(this),
                FfiConverterString.lower(extId),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * close
     */
    close() {
        const liftResult = (result) => undefined;
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                84, // webextstorage:uniffi_webext_storage_fn_method_webextstoragestore_close
                FfiConverterTypeWebExtStorageStore.lower(this),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * get
     * @returns {JsonValue}
     */
    get(extId,keys) {
        const liftResult = (result) => FfiConverterTypeJsonValue.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterString.checkType(extId)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("extId");
                }
                throw e;
            }
            try {
                FfiConverterTypeJsonValue.checkType(keys)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("keys");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                85, // webextstorage:uniffi_webext_storage_fn_method_webextstoragestore_get
                FfiConverterTypeWebExtStorageStore.lower(this),
                FfiConverterString.lower(extId),
                FfiConverterTypeJsonValue.lower(keys),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * getBytesInUse
     * @returns {number}
     */
    getBytesInUse(extId,keys) {
        const liftResult = (result) => FfiConverterU64.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterString.checkType(extId)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("extId");
                }
                throw e;
            }
            try {
                FfiConverterTypeJsonValue.checkType(keys)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("keys");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                86, // webextstorage:uniffi_webext_storage_fn_method_webextstoragestore_get_bytes_in_use
                FfiConverterTypeWebExtStorageStore.lower(this),
                FfiConverterString.lower(extId),
                FfiConverterTypeJsonValue.lower(keys),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * getSyncedChanges
     * @returns {Array.<SyncedExtensionChange>}
     */
    getSyncedChanges() {
        const liftResult = (result) => FfiConverterSequenceTypeSyncedExtensionChange.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            return UniFFIScaffolding.callAsyncWrapper(
                87, // webextstorage:uniffi_webext_storage_fn_method_webextstoragestore_get_synced_changes
                FfiConverterTypeWebExtStorageStore.lower(this),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * remove
     * @returns {StorageChanges}
     */
    remove(extId,keys) {
        const liftResult = (result) => FfiConverterTypeStorageChanges.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterString.checkType(extId)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("extId");
                }
                throw e;
            }
            try {
                FfiConverterTypeJsonValue.checkType(keys)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("keys");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                88, // webextstorage:uniffi_webext_storage_fn_method_webextstoragestore_remove
                FfiConverterTypeWebExtStorageStore.lower(this),
                FfiConverterString.lower(extId),
                FfiConverterTypeJsonValue.lower(keys),
            )
        }
        try {
            return functionCall().then((result) => handleRustResult(result, liftResult, liftError));
        }  catch (error) {
            return Promise.reject(error)
        }
    }

    /**
     * set
     * @returns {StorageChanges}
     */
    set(extId,val) {
        const liftResult = (result) => FfiConverterTypeStorageChanges.lift(result);
        const liftError = (data) => FfiConverterTypeWebExtStorageApiError.lift(data);
        const functionCall = () => {
            try {
                FfiConverterString.checkType(extId)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("extId");
                }
                throw e;
            }
            try {
                FfiConverterTypeJsonValue.checkType(val)
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart("val");
                }
                throw e;
            }
            return UniFFIScaffolding.callAsyncWrapper(
                89, // webextstorage:uniffi_webext_storage_fn_method_webextstoragestore_set
                FfiConverterTypeWebExtStorageStore.lower(this),
                FfiConverterString.lower(extId),
                FfiConverterTypeJsonValue.lower(val),
            )
        }
        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 FfiConverterTypeWebExtStorageStore extends FfiConverter {
    static lift(value) {
        const opts = {};
        opts[constructUniffiObject] = value;
        return new WebExtStorageStore(opts);
    }

    static lower(value) {
        const ptr = value[uniffiObjectPtr];
        if (!(ptr instanceof UniFFIPointer)) {
            throw new UniFFITypeError("Object is not a 'WebExtStorageStore' instance");
        }
        return ptr;
    }

    static read(dataStream) {
        return this.lift(dataStream.readPointerWebExtStorageStore());
    }

    static write(dataStream, value) {
        dataStream.writePointerWebExtStorageStore(value[uniffiObjectPtr]);
    }

    static computeSize(value) {
        return 8;
    }
}

/**
 * StorageChanges
 */
export class StorageChanges {
    constructor({ changes } = {}) {
        try {
            FfiConverterSequenceTypeStorageValueChange.checkType(changes)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("changes");
            }
            throw e;
        }
        /**
         * @type {Array.<StorageValueChange>}
         */
        this.changes = changes;
    }

    equals(other) {
        return (
            this.changes == other.changes
        )
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeStorageChanges extends FfiConverterArrayBuffer {
    static read(dataStream) {
        return new StorageChanges({
            changes: FfiConverterSequenceTypeStorageValueChange.read(dataStream),
        });
    }
    static write(dataStream, value) {
        FfiConverterSequenceTypeStorageValueChange.write(dataStream, value.changes);
    }

    static computeSize(value) {
        let totalSize = 0;
        totalSize += FfiConverterSequenceTypeStorageValueChange.computeSize(value.changes);
        return totalSize
    }

    static checkType(value) {
        super.checkType(value);
        if (!(value instanceof StorageChanges)) {
            throw new UniFFITypeError(`Expected 'StorageChanges', found '${typeof value}'`);
        }
        try {
            FfiConverterSequenceTypeStorageValueChange.checkType(value.changes);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".changes");
            }
            throw e;
        }
    }
}

/**
 * StorageValueChange
 */
export class StorageValueChange {
    constructor({ key, oldValue, newValue } = {}) {
        try {
            FfiConverterString.checkType(key)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("key");
            }
            throw e;
        }
        try {
            FfiConverterOptionalTypeJsonValue.checkType(oldValue)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("oldValue");
            }
            throw e;
        }
        try {
            FfiConverterOptionalTypeJsonValue.checkType(newValue)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("newValue");
            }
            throw e;
        }
        /**
         * @type {string}
         */
        this.key = key;
        /**
         * @type {?JsonValue}
         */
        this.oldValue = oldValue;
        /**
         * @type {?JsonValue}
         */
        this.newValue = newValue;
    }

    equals(other) {
        return (
            this.key == other.key &&
            this.oldValue == other.oldValue &&
            this.newValue == other.newValue
        )
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeStorageValueChange extends FfiConverterArrayBuffer {
    static read(dataStream) {
        return new StorageValueChange({
            key: FfiConverterString.read(dataStream),
            oldValue: FfiConverterOptionalTypeJsonValue.read(dataStream),
            newValue: FfiConverterOptionalTypeJsonValue.read(dataStream),
        });
    }
    static write(dataStream, value) {
        FfiConverterString.write(dataStream, value.key);
        FfiConverterOptionalTypeJsonValue.write(dataStream, value.oldValue);
        FfiConverterOptionalTypeJsonValue.write(dataStream, value.newValue);
    }

    static computeSize(value) {
        let totalSize = 0;
        totalSize += FfiConverterString.computeSize(value.key);
        totalSize += FfiConverterOptionalTypeJsonValue.computeSize(value.oldValue);
        totalSize += FfiConverterOptionalTypeJsonValue.computeSize(value.newValue);
        return totalSize
    }

    static checkType(value) {
        super.checkType(value);
        if (!(value instanceof StorageValueChange)) {
            throw new UniFFITypeError(`Expected 'StorageValueChange', found '${typeof value}'`);
        }
        try {
            FfiConverterString.checkType(value.key);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".key");
            }
            throw e;
        }
        try {
            FfiConverterOptionalTypeJsonValue.checkType(value.oldValue);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".oldValue");
            }
            throw e;
        }
        try {
            FfiConverterOptionalTypeJsonValue.checkType(value.newValue);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".newValue");
            }
            throw e;
        }
    }
}

/**
 * SyncedExtensionChange
 */
export class SyncedExtensionChange {
    constructor({ extId, changes } = {}) {
        try {
            FfiConverterString.checkType(extId)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("extId");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(changes)
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart("changes");
            }
            throw e;
        }
        /**
         * @type {string}
         */
        this.extId = extId;
        /**
         * @type {string}
         */
        this.changes = changes;
    }

    equals(other) {
        return (
            this.extId == other.extId &&
            this.changes == other.changes
        )
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeSyncedExtensionChange extends FfiConverterArrayBuffer {
    static read(dataStream) {
        return new SyncedExtensionChange({
            extId: FfiConverterString.read(dataStream),
            changes: FfiConverterString.read(dataStream),
        });
    }
    static write(dataStream, value) {
        FfiConverterString.write(dataStream, value.extId);
        FfiConverterString.write(dataStream, value.changes);
    }

    static computeSize(value) {
        let totalSize = 0;
        totalSize += FfiConverterString.computeSize(value.extId);
        totalSize += FfiConverterString.computeSize(value.changes);
        return totalSize
    }

    static checkType(value) {
        super.checkType(value);
        if (!(value instanceof SyncedExtensionChange)) {
            throw new UniFFITypeError(`Expected 'SyncedExtensionChange', found '${typeof value}'`);
        }
        try {
            FfiConverterString.checkType(value.extId);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".extId");
            }
            throw e;
        }
        try {
            FfiConverterString.checkType(value.changes);
        } catch (e) {
            if (e instanceof UniFFITypeError) {
                e.addItemDescriptionPart(".changes");
            }
            throw e;
        }
    }
}


/**
 * QuotaReason
 */
export const QuotaReason = {
    /**
     * TOTAL_BYTES
     */
    TOTAL_BYTES: 1,
    /**
     * ITEM_BYTES
     */
    ITEM_BYTES: 2,
    /**
     * MAX_ITEMS
     */
    MAX_ITEMS: 3,
};

Object.freeze(QuotaReason);
// Export the FFIConverter object to make external types work.
export class FfiConverterTypeQuotaReason extends FfiConverterArrayBuffer {
    static read(dataStream) {
        switch (dataStream.readInt32()) {
            case 1:
                return QuotaReason.TOTAL_BYTES
            case 2:
                return QuotaReason.ITEM_BYTES
            case 3:
                return QuotaReason.MAX_ITEMS
            default:
                throw new UniFFITypeError("Unknown QuotaReason variant");
        }
    }

    static write(dataStream, value) {
        if (value === QuotaReason.TOTAL_BYTES) {
            dataStream.writeInt32(1);
            return;
        }
        if (value === QuotaReason.ITEM_BYTES) {
            dataStream.writeInt32(2);
            return;
        }
        if (value === QuotaReason.MAX_ITEMS) {
            dataStream.writeInt32(3);
            return;
        }
        throw new UniFFITypeError("Unknown QuotaReason 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 QuotaReason`);
      }
    }
}





/**
 * WebExtStorageApiError
 */
export class WebExtStorageApiError extends Error {}


/**
 * UnexpectedError
 */
export class UnexpectedError extends WebExtStorageApiError {

    constructor(
        reason,
        ...params
    ) {
        const message = `reason: ${ reason }`;
        super(message, ...params);
        this.reason = reason;
    }
    toString() {
        return `UnexpectedError: ${super.toString()}`
    }
}

/**
 * JsonError
 */
export class JsonError extends WebExtStorageApiError {

    constructor(
        reason,
        ...params
    ) {
        const message = `reason: ${ reason }`;
        super(message, ...params);
        this.reason = reason;
    }
    toString() {
        return `JsonError: ${super.toString()}`
    }
}

/**
 * QuotaError
 */
export class QuotaError extends WebExtStorageApiError {

    constructor(
        reason,
        ...params
    ) {
        const message = `reason: ${ reason }`;
        super(message, ...params);
        this.reason = reason;
    }
    toString() {
        return `QuotaError: ${super.toString()}`
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeWebExtStorageApiError extends FfiConverterArrayBuffer {
    static read(dataStream) {
        switch (dataStream.readInt32()) {
            case 1:
                return new UnexpectedError(
                    FfiConverterString.read(dataStream)
                    );
            case 2:
                return new JsonError(
                    FfiConverterString.read(dataStream)
                    );
            case 3:
                return new QuotaError(
                    FfiConverterTypeQuotaReason.read(dataStream)
                    );
            default:
                throw new UniFFITypeError("Unknown WebExtStorageApiError variant");
        }
    }
    static computeSize(value) {
        // Size of the Int indicating the variant
        let totalSize = 4;
        if (value instanceof UnexpectedError) {
            totalSize += FfiConverterString.computeSize(value.reason);
            return totalSize;
        }
        if (value instanceof JsonError) {
            totalSize += FfiConverterString.computeSize(value.reason);
            return totalSize;
        }
        if (value instanceof QuotaError) {
            totalSize += FfiConverterTypeQuotaReason.computeSize(value.reason);
            return totalSize;
        }
        throw new UniFFITypeError("Unknown WebExtStorageApiError variant");
    }
    static write(dataStream, value) {
        if (value instanceof UnexpectedError) {
            dataStream.writeInt32(1);
            FfiConverterString.write(dataStream, value.reason);
            return;
        }
        if (value instanceof JsonError) {
            dataStream.writeInt32(2);
            FfiConverterString.write(dataStream, value.reason);
            return;
        }
        if (value instanceof QuotaError) {
            dataStream.writeInt32(3);
            FfiConverterTypeQuotaReason.write(dataStream, value.reason);
            return;
        }
        throw new UniFFITypeError("Unknown WebExtStorageApiError variant");
    }

    static errorClass = WebExtStorageApiError;
}

// 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 FfiConverterOptionalTypeJsonValue extends FfiConverterArrayBuffer {
    static checkType(value) {
        if (value !== undefined && value !== null) {
            FfiConverterTypeJsonValue.checkType(value)
        }
    }

    static read(dataStream) {
        const code = dataStream.readUint8(0);
        switch (code) {
            case 0:
                return null
            case 1:
                return FfiConverterTypeJsonValue.read(dataStream)
            default:
                throw UniFFIError(`Unexpected code: ${code}`);
        }
    }

    static write(dataStream, value) {
        if (value === null || value === undefined) {
            dataStream.writeUint8(0);
            return;
        }
        dataStream.writeUint8(1);
        FfiConverterTypeJsonValue.write(dataStream, value)
    }

    static computeSize(value) {
        if (value === null || value === undefined) {
            return 1;
        }
        return 1 + FfiConverterTypeJsonValue.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 FfiConverterSequenceTypeStorageValueChange extends FfiConverterArrayBuffer {
    static read(dataStream) {
        const len = dataStream.readInt32();
        const arr = [];
        for (let i = 0; i < len; i++) {
            arr.push(FfiConverterTypeStorageValueChange.read(dataStream));
        }
        return arr;
    }

    static write(dataStream, value) {
        dataStream.writeInt32(value.length);
        value.forEach((innerValue) => {
            FfiConverterTypeStorageValueChange.write(dataStream, innerValue);
        })
    }

    static computeSize(value) {
        // The size of the length
        let size = 4;
        for (const innerValue of value) {
            size += FfiConverterTypeStorageValueChange.computeSize(innerValue);
        }
        return size;
    }

    static checkType(value) {
        if (!Array.isArray(value)) {
            throw new UniFFITypeError(`${value} is not an array`);
        }
        value.forEach((innerValue, idx) => {
            try {
                FfiConverterTypeStorageValueChange.checkType(innerValue);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart(`[${idx}]`);
                }
                throw e;
            }
        })
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterSequenceTypeSyncedExtensionChange extends FfiConverterArrayBuffer {
    static read(dataStream) {
        const len = dataStream.readInt32();
        const arr = [];
        for (let i = 0; i < len; i++) {
            arr.push(FfiConverterTypeSyncedExtensionChange.read(dataStream));
        }
        return arr;
    }

    static write(dataStream, value) {
        dataStream.writeInt32(value.length);
        value.forEach((innerValue) => {
            FfiConverterTypeSyncedExtensionChange.write(dataStream, innerValue);
        })
    }

    static computeSize(value) {
        // The size of the length
        let size = 4;
        for (const innerValue of value) {
            size += FfiConverterTypeSyncedExtensionChange.computeSize(innerValue);
        }
        return size;
    }

    static checkType(value) {
        if (!Array.isArray(value)) {
            throw new UniFFITypeError(`${value} is not an array`);
        }
        value.forEach((innerValue, idx) => {
            try {
                FfiConverterTypeSyncedExtensionChange.checkType(innerValue);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart(`[${idx}]`);
                }
                throw e;
            }
        })
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterSequenceTypeGuid extends FfiConverterArrayBuffer {
    static read(dataStream) {
        const len = dataStream.readInt32();
        const arr = [];
        for (let i = 0; i < len; i++) {
            arr.push(FfiConverterTypeGuid.read(dataStream));
        }
        return arr;
    }

    static write(dataStream, value) {
        dataStream.writeInt32(value.length);
        value.forEach((innerValue) => {
            FfiConverterTypeGuid.write(dataStream, innerValue);
        })
    }

    static computeSize(value) {
        // The size of the length
        let size = 4;
        for (const innerValue of value) {
            size += FfiConverterTypeGuid.computeSize(innerValue);
        }
        return size;
    }

    static checkType(value) {
        if (!Array.isArray(value)) {
            throw new UniFFITypeError(`${value} is not an array`);
        }
        value.forEach((innerValue, idx) => {
            try {
                FfiConverterTypeGuid.checkType(innerValue);
            } catch (e) {
                if (e instanceof UniFFITypeError) {
                    e.addItemDescriptionPart(`[${idx}]`);
                }
                throw e;
            }
        })
    }
}

// Export the FFIConverter object to make external types work.
export class FfiConverterTypeGuid 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 the FFIConverter object to make external types work.
export class FfiConverterTypeJsonValue 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.




