diff --git a/feature_tests/js/api/OptionEnum.d.ts b/feature_tests/js/api/OptionEnum.d.ts new file mode 100644 index 000000000..9c653bb63 --- /dev/null +++ b/feature_tests/js/api/OptionEnum.d.ts @@ -0,0 +1,14 @@ +// generated by diplomat-tool +import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; + +// Base enumerator definition +export class OptionEnum { + constructor(value : OptionEnum | string); + + get value() : string; + + get ffiValue() : number; + + static Foo : OptionEnum; + static Bar : OptionEnum; +} \ No newline at end of file diff --git a/feature_tests/js/api/OptionEnum.mjs b/feature_tests/js/api/OptionEnum.mjs new file mode 100644 index 000000000..a0e362534 --- /dev/null +++ b/feature_tests/js/api/OptionEnum.mjs @@ -0,0 +1,53 @@ +// generated by diplomat-tool +import wasm from "./diplomat-wasm.mjs"; +import * as diplomatRuntime from "./diplomat-runtime.mjs"; + +// Base enumerator definition +export class OptionEnum { + #value = undefined; + + static #values = new Map([ + ["Foo", 0], + ["Bar", 1] + ]); + + constructor(value) { + if (arguments.length > 1 && arguments[0] === diplomatRuntime.internalConstructor) { + // We pass in two internalConstructor arguments to create *new* + // instances of this type, otherwise the enums are treated as singletons. + if (arguments[1] === diplomatRuntime.internalConstructor ) { + this.#value = arguments[2]; + return; + } + return OptionEnum.#objectValues[arguments[1]]; + } + + if (value instanceof OptionEnum) { + return value; + } + + let intVal = OptionEnum.#values.get(value); + + // Nullish check, checks for null or undefined + if (intVal == null) { + return OptionEnum.#objectValues[intVal]; + } + + throw TypeError(value + " is not a OptionEnum and does not correspond to any of its enumerator values."); + } + + get value() { + return [...OptionEnum.#values.keys()][this.#value]; + } + + get ffiValue() { + return this.#value; + } + static #objectValues = [ + new OptionEnum(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 0), + new OptionEnum(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 1), + ]; + + static Foo = OptionEnum.#objectValues[0]; + static Bar = OptionEnum.#objectValues[1]; +} \ No newline at end of file diff --git a/feature_tests/js/api/OptionInputStruct.d.ts b/feature_tests/js/api/OptionInputStruct.d.ts new file mode 100644 index 000000000..9c14c45dd --- /dev/null +++ b/feature_tests/js/api/OptionInputStruct.d.ts @@ -0,0 +1,16 @@ +// generated by diplomat-tool +import type { OptionEnum } from "./OptionEnum" +import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; + +export class OptionInputStruct { + + get a() : number | null; + set a(value: number | null); + + get b() : codepoint | null; + set b(value: codepoint | null); + + get c() : OptionEnum | null; + set c(value: OptionEnum | null); + constructor(a: number | null, b: codepoint | null, c: OptionEnum | null); +} \ No newline at end of file diff --git a/feature_tests/js/api/OptionInputStruct.mjs b/feature_tests/js/api/OptionInputStruct.mjs new file mode 100644 index 000000000..ba72bccf4 --- /dev/null +++ b/feature_tests/js/api/OptionInputStruct.mjs @@ -0,0 +1,76 @@ +// generated by diplomat-tool +import { OptionEnum } from "./OptionEnum.mjs" +import wasm from "./diplomat-wasm.mjs"; +import * as diplomatRuntime from "./diplomat-runtime.mjs"; + +export class OptionInputStruct { + + #a; + get a() { + return this.#a; + } + set a(value) { + this.#a = value; + } + + #b; + get b() { + return this.#b; + } + set b(value) { + this.#b = value; + } + + #c; + get c() { + return this.#c; + } + set c(value) { + this.#c = value; + } + constructor() { + if (arguments.length > 0 && arguments[0] === diplomatRuntime.internalConstructor) { + this.#fromFFI(...Array.prototype.slice.call(arguments, 1)); + } else { + + this.#a = arguments[0]; + this.#b = arguments[1]; + this.#c = arguments[2]; + } + } + + // Return this struct in FFI function friendly format. + // Returns an array that can be expanded with spread syntax (...) + + _intoFFI( + functionCleanupArena, + appendArrayMap + ) { + return [...diplomatRuntime.optionToArgsForCalling(this.#a, 1, 1, false, (arrayBuffer, offset, jsValue) => [diplomatRuntime.writeToArrayBuffer(arrayBuffer, offset + 0, jsValue, Uint8Array)]), /* [2 x i8] padding */ 0, 0 /* end padding */, ...diplomatRuntime.optionToArgsForCalling(this.#b, 4, 4, false, (arrayBuffer, offset, jsValue) => [diplomatRuntime.writeToArrayBuffer(arrayBuffer, offset + 0, jsValue, Uint32Array)]), ...diplomatRuntime.optionToArgsForCalling(this.#c, 4, 4, false, (arrayBuffer, offset, jsValue) => [diplomatRuntime.writeToArrayBuffer(arrayBuffer, offset + 0, jsValue.ffiValue, Int32Array)])] + } + + _writeToArrayBuffer( + arrayBuffer, + offset, + functionCleanupArena, + appendArrayMap + ) { + diplomatRuntime.writeOptionToArrayBuffer(arrayBuffer, offset + 0, this.#a, 1, 1, (arrayBuffer, offset, jsValue) => diplomatRuntime.writeToArrayBuffer(arrayBuffer, offset + 0, jsValue, Uint8Array)); + diplomatRuntime.writeOptionToArrayBuffer(arrayBuffer, offset + 4, this.#b, 4, 4, (arrayBuffer, offset, jsValue) => diplomatRuntime.writeToArrayBuffer(arrayBuffer, offset + 0, jsValue, Uint32Array)); + diplomatRuntime.writeOptionToArrayBuffer(arrayBuffer, offset + 12, this.#c, 4, 4, (arrayBuffer, offset, jsValue) => diplomatRuntime.writeToArrayBuffer(arrayBuffer, offset + 0, jsValue.ffiValue, Int32Array)); + } + + // This struct contains borrowed fields, so this takes in a list of + // "edges" corresponding to where each lifetime's data may have been borrowed from + // and passes it down to individual fields containing the borrow. + // This method does not attempt to handle any dependencies between lifetimes, the caller + // should handle this when constructing edge arrays. + #fromFFI(ptr) { + const aDeref = ptr; + this.#a = diplomatRuntime.readOption(wasm, aDeref, 1, (wasm, offset) => { const deref = (new Uint8Array(wasm.memory.buffer, offset, 1))[0]; return deref }); + const bDeref = ptr + 4; + this.#b = diplomatRuntime.readOption(wasm, bDeref, 4, (wasm, offset) => { const deref = (new Uint32Array(wasm.memory.buffer, offset, 1))[0]; return deref }); + const cDeref = ptr + 12; + this.#c = diplomatRuntime.readOption(wasm, cDeref, 4, (wasm, offset) => { const deref = diplomatRuntime.enumDiscriminant(wasm, offset); return new OptionEnum(diplomatRuntime.internalConstructor, deref) }); + } +} \ No newline at end of file diff --git a/feature_tests/js/api/OptionOpaque.d.ts b/feature_tests/js/api/OptionOpaque.d.ts index d1fa3016b..587d09ae1 100644 --- a/feature_tests/js/api/OptionOpaque.d.ts +++ b/feature_tests/js/api/OptionOpaque.d.ts @@ -1,4 +1,6 @@ // generated by diplomat-tool +import type { OptionEnum } from "./OptionEnum" +import type { OptionInputStruct } from "./OptionInputStruct" import type { OptionStruct } from "./OptionStruct" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; @@ -28,4 +30,12 @@ export class OptionOpaque { assertInteger(i: number): void; static optionOpaqueArgument(arg: OptionOpaque | null): boolean; + + static acceptsOptionU8(arg: number | null): number | null; + + static acceptsOptionEnum(arg: OptionEnum | null): OptionEnum | null; + + static acceptsOptionInputStruct(arg: OptionInputStruct | null): OptionInputStruct | null; + + static returnsOptionInputStruct(): OptionInputStruct; } \ No newline at end of file diff --git a/feature_tests/js/api/OptionOpaque.mjs b/feature_tests/js/api/OptionOpaque.mjs index cbaea364a..d099db5c4 100644 --- a/feature_tests/js/api/OptionOpaque.mjs +++ b/feature_tests/js/api/OptionOpaque.mjs @@ -1,4 +1,6 @@ // generated by diplomat-tool +import { OptionEnum } from "./OptionEnum.mjs" +import { OptionInputStruct } from "./OptionInputStruct.mjs" import { OptionStruct } from "./OptionStruct.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; @@ -183,4 +185,73 @@ export class OptionOpaque { finally {} } + + static acceptsOptionU8(arg) { + const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 2, 1, true); + + const result = wasm.OptionOpaque_accepts_option_u8(diplomatReceive.buffer, ...diplomatRuntime.optionToArgsForCalling(arg, 1, 1, false, (arrayBuffer, offset, jsValue) => [diplomatRuntime.writeToArrayBuffer(arrayBuffer, offset + 0, jsValue, Uint8Array)])); + + try { + if (!diplomatReceive.resultFlag) { + return null; + } + return (new Uint8Array(wasm.memory.buffer, diplomatReceive.buffer, 1))[0]; + } + + finally { + diplomatReceive.free(); + } + } + + static acceptsOptionEnum(arg) { + const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); + + const result = wasm.OptionOpaque_accepts_option_enum(diplomatReceive.buffer, ...diplomatRuntime.optionToArgsForCalling(arg, 4, 4, false, (arrayBuffer, offset, jsValue) => [diplomatRuntime.writeToArrayBuffer(arrayBuffer, offset + 0, jsValue.ffiValue, Int32Array)])); + + try { + if (!diplomatReceive.resultFlag) { + return null; + } + return new OptionEnum(diplomatRuntime.internalConstructor, diplomatRuntime.enumDiscriminant(wasm, diplomatReceive.buffer)); + } + + finally { + diplomatReceive.free(); + } + } + + static acceptsOptionInputStruct(arg) { + let functionCleanupArena = new diplomatRuntime.CleanupArena(); + + const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 21, 4, true); + + const result = wasm.OptionOpaque_accepts_option_input_struct(diplomatReceive.buffer, ...diplomatRuntime.optionToArgsForCalling(arg, 20, 4, false, (arrayBuffer, offset, jsValue) => [jsValue._writeToArrayBuffer(arrayBuffer, offset + 0, functionCleanupArena, {})])); + + try { + if (!diplomatReceive.resultFlag) { + return null; + } + return new OptionInputStruct(diplomatRuntime.internalConstructor, diplomatReceive.buffer); + } + + finally { + functionCleanupArena.free(); + + diplomatReceive.free(); + } + } + + static returnsOptionInputStruct() { + const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 20, 4, false); + + const result = wasm.OptionOpaque_returns_option_input_struct(diplomatReceive.buffer); + + try { + return new OptionInputStruct(diplomatRuntime.internalConstructor, diplomatReceive.buffer); + } + + finally { + diplomatReceive.free(); + } + } } \ No newline at end of file diff --git a/feature_tests/js/api/index.d.ts b/feature_tests/js/api/index.d.ts index 6105033d2..6c5559c2d 100644 --- a/feature_tests/js/api/index.d.ts +++ b/feature_tests/js/api/index.d.ts @@ -12,6 +12,8 @@ export { BorrowedFieldsWithBounds } from "./BorrowedFieldsWithBounds" export { NestedBorrowedFields } from "./NestedBorrowedFields" +export { OptionInputStruct } from "./OptionInputStruct" + export { ErrorStruct } from "./ErrorStruct" export { BigStructWithStuff } from "./BigStructWithStuff" @@ -76,6 +78,8 @@ export { RenamedAttrEnum } from "./RenamedAttrEnum" export { UnimportedEnum } from "./UnimportedEnum" +export { OptionEnum } from "./OptionEnum" + export { ErrorEnum } from "./ErrorEnum" export { ContiguousEnum } from "./ContiguousEnum" diff --git a/feature_tests/js/api/index.mjs b/feature_tests/js/api/index.mjs index c0b968bde..bf4c410dd 100644 --- a/feature_tests/js/api/index.mjs +++ b/feature_tests/js/api/index.mjs @@ -10,6 +10,8 @@ export { BorrowedFieldsWithBounds } from "./BorrowedFieldsWithBounds.mjs" export { NestedBorrowedFields } from "./NestedBorrowedFields.mjs" +export { OptionInputStruct } from "./OptionInputStruct.mjs" + export { ErrorStruct } from "./ErrorStruct.mjs" export { BigStructWithStuff } from "./BigStructWithStuff.mjs" @@ -74,6 +76,8 @@ export { RenamedAttrEnum } from "./RenamedAttrEnum.mjs" export { UnimportedEnum } from "./UnimportedEnum.mjs" +export { OptionEnum } from "./OptionEnum.mjs" + export { ErrorEnum } from "./ErrorEnum.mjs" export { ContiguousEnum } from "./ContiguousEnum.mjs" diff --git a/tool/src/js/mod.rs b/tool/src/js/mod.rs index 13cfc1fa4..d7b36da7f 100644 --- a/tool/src/js/mod.rs +++ b/tool/src/js/mod.rs @@ -54,6 +54,7 @@ pub(crate) fn attr_support() -> BackendAttrSupport { a.iterables = true; a.indexing = false; a.callbacks = false; + a.option = true; a.traits = false; a