diff --git a/example/demo_gen/custom_func/a.mjs b/example/demo_gen/custom_func/a.mjs index fedec928a..644027fbf 100644 --- a/example/demo_gen/custom_func/a.mjs +++ b/example/demo_gen/custom_func/a.mjs @@ -1,7 +1,7 @@ import { lib } from "./index.mjs"; export function multiplyPow10(power) { - let fixedDecimal = lib.FixedDecimal.new_(10); + let fixedDecimal = new lib.FixedDecimal(10); fixedDecimal.multiplyPow10(power); return fixedDecimal.toString(); } diff --git a/example/demo_gen/demo/FixedDecimal.mjs b/example/demo_gen/demo/FixedDecimal.mjs index 428f1d642..1ac9b9b46 100644 --- a/example/demo_gen/demo/FixedDecimal.mjs +++ b/example/demo_gen/demo/FixedDecimal.mjs @@ -3,7 +3,7 @@ export function toString(v) { return (function (...args) { return args[0].toString(...args.slice(1)) }).apply( null, [ - FixedDecimal.new_.apply( + (function (...args) { return new FixedDecimal(...args) } ).apply( null, [ v diff --git a/example/demo_gen/demo/FixedDecimalFormatter.mjs b/example/demo_gen/demo/FixedDecimalFormatter.mjs index 6411db57d..58f4a25f4 100644 --- a/example/demo_gen/demo/FixedDecimalFormatter.mjs +++ b/example/demo_gen/demo/FixedDecimalFormatter.mjs @@ -10,7 +10,7 @@ export function formatWrite(name, grouping_strategy, some_other_config, v) { FixedDecimalFormatter.tryNew.apply( null, [ - Locale.new_.apply( + (function (...args) { return new Locale(...args) } ).apply( null, [ name @@ -22,7 +22,7 @@ export function formatWrite(name, grouping_strategy, some_other_config, v) { ] ), (function (...args) { - return new FixedDecimalFormatterOptions({ + return FixedDecimalFormatterOptions.fromFields({ groupingStrategy: args[0], someOtherConfig: args[1]}); }).apply( @@ -34,7 +34,7 @@ export function formatWrite(name, grouping_strategy, some_other_config, v) { ) ] ), - FixedDecimal.new_.apply( + (function (...args) { return new FixedDecimal(...args) } ).apply( null, [ v diff --git a/example/demo_gen/demo/a.mjs b/example/demo_gen/demo/a.mjs index fedec928a..644027fbf 100644 --- a/example/demo_gen/demo/a.mjs +++ b/example/demo_gen/demo/a.mjs @@ -1,7 +1,7 @@ import { lib } from "./index.mjs"; export function multiplyPow10(power) { - let fixedDecimal = lib.FixedDecimal.new_(10); + let fixedDecimal = new lib.FixedDecimal(10); fixedDecimal.multiplyPow10(power); return fixedDecimal.toString(); } diff --git a/example/js/lib/api/DataProvider.d.ts b/example/js/lib/api/DataProvider.d.ts index c05589e1b..c4a015644 100644 --- a/example/js/lib/api/DataProvider.d.ts +++ b/example/js/lib/api/DataProvider.d.ts @@ -1,17 +1,18 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; - + /** An data provider, capable of loading data keys from some source. * -*See the [Rust documentation for `icu_provider`](https://docs.rs/icu_provider/latest/icu_provider/index.html) for more information. -*/ -export class DataProvider { +*See the [Rust documentation for `icu_provider`](https://docs.rs/icu_provider/latest/icu_provider/index.html) for more information. +*/ + + +export class DataProvider { - - get ffiValue(): pointer; - - static newStatic(): DataProvider; - - static returnsResult(): boolean; + get ffiValue(): pointer; + + static newStatic(): DataProvider; + + static returnsResult(): boolean; } \ No newline at end of file diff --git a/example/js/lib/api/DataProvider.mjs b/example/js/lib/api/DataProvider.mjs index cd03b2142..01da00c18 100644 --- a/example/js/lib/api/DataProvider.mjs +++ b/example/js/lib/api/DataProvider.mjs @@ -2,16 +2,17 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; - + /** An data provider, capable of loading data keys from some source. * -*See the [Rust documentation for `icu_provider`](https://docs.rs/icu_provider/latest/icu_provider/index.html) for more information. -*/ +*See the [Rust documentation for `icu_provider`](https://docs.rs/icu_provider/latest/icu_provider/index.html) for more information. +*/ const DataProvider_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.icu4x_DataProvider_destroy_mv1(ptr); -}); - -export class DataProvider { +}); + +export class DataProvider { + // Internal ptr reference: #ptr = null; @@ -19,7 +20,7 @@ export class DataProvider { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("DataProvider is an Opaque type. You cannot call its constructor."); return; @@ -32,12 +33,13 @@ export class DataProvider { if (this.#selfEdge.length === 0) { DataProvider_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static newStatic() { const result = wasm.icu4x_DataProvider_new_static_mv1(); @@ -46,8 +48,8 @@ export class DataProvider { } finally {} - } - + } + static returnsResult() { const result = wasm.icu4x_DataProvider_returns_result_mv1(); @@ -56,5 +58,9 @@ export class DataProvider { } finally {} - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/example/js/lib/api/FixedDecimal.d.ts b/example/js/lib/api/FixedDecimal.d.ts index 4866c24d2..0b0bf8091 100644 --- a/example/js/lib/api/FixedDecimal.d.ts +++ b/example/js/lib/api/FixedDecimal.d.ts @@ -1,17 +1,18 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; - -/** See the [Rust documentation for `FixedDecimal`](https://docs.rs/fixed_decimal/latest/fixed_decimal/struct.FixedDecimal.html) for more information. -*/ -export class FixedDecimal { + +/** See the [Rust documentation for `FixedDecimal`](https://docs.rs/fixed_decimal/latest/fixed_decimal/struct.FixedDecimal.html) for more information. +*/ + + +export class FixedDecimal { - - get ffiValue(): pointer; - - static new_(v: number): FixedDecimal; - - multiplyPow10(power: number): void; - - toString(): string | null; + get ffiValue(): pointer; + + multiplyPow10(power: number): void; + + toString(): string | null; + + constructor(v: number); } \ No newline at end of file diff --git a/example/js/lib/api/FixedDecimal.mjs b/example/js/lib/api/FixedDecimal.mjs index 193a2a70d..77d08296c 100644 --- a/example/js/lib/api/FixedDecimal.mjs +++ b/example/js/lib/api/FixedDecimal.mjs @@ -2,14 +2,15 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; - -/** See the [Rust documentation for `FixedDecimal`](https://docs.rs/fixed_decimal/latest/fixed_decimal/struct.FixedDecimal.html) for more information. -*/ + +/** See the [Rust documentation for `FixedDecimal`](https://docs.rs/fixed_decimal/latest/fixed_decimal/struct.FixedDecimal.html) for more information. +*/ const FixedDecimal_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.icu4x_FixedDecimal_destroy_mv1(ptr); -}); - -export class FixedDecimal { +}); + +export class FixedDecimal { + // Internal ptr reference: #ptr = null; @@ -17,7 +18,7 @@ export class FixedDecimal { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("FixedDecimal is an Opaque type. You cannot call its constructor."); return; @@ -30,13 +31,14 @@ export class FixedDecimal { if (this.#selfEdge.length === 0) { FixedDecimal_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - - static new_(v) { + } + + #defaultConstructor(v) { const result = wasm.icu4x_FixedDecimal_new_mv1(v); try { @@ -44,15 +46,15 @@ export class FixedDecimal { } finally {} - } - + } + multiplyPow10(power) {wasm.icu4x_FixedDecimal_multiply_pow10_mv1(this.ffiValue, power); try {} finally {} - } - + } + toString() { const write = new diplomatRuntime.DiplomatWriteBuf(wasm); @@ -65,5 +67,15 @@ export class FixedDecimal { finally { write.free(); } - } + } + + constructor(v) { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/example/js/lib/api/FixedDecimalFormatter.d.ts b/example/js/lib/api/FixedDecimalFormatter.d.ts index 9561d4b46..b287f5c48 100644 --- a/example/js/lib/api/FixedDecimalFormatter.d.ts +++ b/example/js/lib/api/FixedDecimalFormatter.d.ts @@ -6,17 +6,18 @@ import type { FixedDecimalFormatterOptions_obj } from "./FixedDecimalFormatterOp import type { Locale } from "./Locale" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; - + /** An Fixed Decimal Format object, capable of formatting a [`FixedDecimal`] as a string. * -*See the [Rust documentation for `FixedDecimalFormatter`](https://docs.rs/icu/latest/icu/decimal/struct.FixedDecimalFormatter.html) for more information. -*/ -export class FixedDecimalFormatter { +*See the [Rust documentation for `FixedDecimalFormatter`](https://docs.rs/icu/latest/icu/decimal/struct.FixedDecimalFormatter.html) for more information. +*/ + + +export class FixedDecimalFormatter { - - get ffiValue(): pointer; - - static tryNew(locale: Locale, provider: DataProvider, options: FixedDecimalFormatterOptions_obj): FixedDecimalFormatter | null; - - formatWrite(value: FixedDecimal): string; + get ffiValue(): pointer; + + static tryNew(locale: Locale, provider: DataProvider, options: FixedDecimalFormatterOptions_obj): FixedDecimalFormatter | null; + + formatWrite(value: FixedDecimal): string; } \ No newline at end of file diff --git a/example/js/lib/api/FixedDecimalFormatter.mjs b/example/js/lib/api/FixedDecimalFormatter.mjs index c424ec42f..660a7e738 100644 --- a/example/js/lib/api/FixedDecimalFormatter.mjs +++ b/example/js/lib/api/FixedDecimalFormatter.mjs @@ -6,16 +6,17 @@ import { Locale } from "./Locale.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; - + /** An Fixed Decimal Format object, capable of formatting a [`FixedDecimal`] as a string. * -*See the [Rust documentation for `FixedDecimalFormatter`](https://docs.rs/icu/latest/icu/decimal/struct.FixedDecimalFormatter.html) for more information. -*/ +*See the [Rust documentation for `FixedDecimalFormatter`](https://docs.rs/icu/latest/icu/decimal/struct.FixedDecimalFormatter.html) for more information. +*/ const FixedDecimalFormatter_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.icu4x_FixedDecimalFormatter_destroy_mv1(ptr); -}); - -export class FixedDecimalFormatter { +}); + +export class FixedDecimalFormatter { + // Internal ptr reference: #ptr = null; @@ -23,7 +24,7 @@ export class FixedDecimalFormatter { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("FixedDecimalFormatter is an Opaque type. You cannot call its constructor."); return; @@ -36,12 +37,13 @@ export class FixedDecimalFormatter { if (this.#selfEdge.length === 0) { FixedDecimalFormatter_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static tryNew(locale, provider, options) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -61,8 +63,8 @@ export class FixedDecimalFormatter { diplomatReceive.free(); } - } - + } + formatWrite(value) { const write = new diplomatRuntime.DiplomatWriteBuf(wasm); wasm.icu4x_FixedDecimalFormatter_format_write_mv1(this.ffiValue, value.ffiValue, write.buffer); @@ -74,5 +76,9 @@ export class FixedDecimalFormatter { finally { write.free(); } - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/example/js/lib/api/FixedDecimalFormatterOptions.d.ts b/example/js/lib/api/FixedDecimalFormatterOptions.d.ts index 23db17b77..e4c232ae2 100644 --- a/example/js/lib/api/FixedDecimalFormatterOptions.d.ts +++ b/example/js/lib/api/FixedDecimalFormatterOptions.d.ts @@ -7,14 +7,21 @@ type FixedDecimalFormatterOptions_obj = { someOtherConfig: boolean; }; -export class FixedDecimalFormatterOptions { - - get groupingStrategy() : FixedDecimalGroupingStrategy; + + +export class FixedDecimalFormatterOptions { + + get groupingStrategy() : FixedDecimalGroupingStrategy; set groupingStrategy(value: FixedDecimalGroupingStrategy); - - get someOtherConfig() : boolean; + + get someOtherConfig() : boolean; set someOtherConfig(value: boolean); - constructor(structObj : FixedDecimalFormatterOptions_obj); - - static default_(): FixedDecimalFormatterOptions; + + /** Create `FixedDecimalFormatterOptions` from an object that contains all of `FixedDecimalFormatterOptions`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : FixedDecimalFormatterOptions_obj) : FixedDecimalFormatterOptions; + + + constructor(); } \ No newline at end of file diff --git a/example/js/lib/api/FixedDecimalFormatterOptions.mjs b/example/js/lib/api/FixedDecimalFormatterOptions.mjs index f601efb19..ce900e0ef 100644 --- a/example/js/lib/api/FixedDecimalFormatterOptions.mjs +++ b/example/js/lib/api/FixedDecimalFormatterOptions.mjs @@ -3,24 +3,36 @@ import { FixedDecimalGroupingStrategy } from "./FixedDecimalGroupingStrategy.mjs import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class FixedDecimalFormatterOptions { - + + +export class FixedDecimalFormatterOptions { + #groupingStrategy; + get groupingStrategy() { return this.#groupingStrategy; - } + } set groupingStrategy(value) { this.#groupingStrategy = value; } - + #someOtherConfig; + get someOtherConfig() { return this.#someOtherConfig; - } + } set someOtherConfig(value) { this.#someOtherConfig = value; } - constructor(structObj) { + + /** Create `FixedDecimalFormatterOptions` from an object that contains all of `FixedDecimalFormatterOptions`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new FixedDecimalFormatterOptions(diplomatRuntime.exposeConstructor, structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("FixedDecimalFormatterOptions's constructor takes an object of FixedDecimalFormatterOptions's fields."); } @@ -37,6 +49,7 @@ export class FixedDecimalFormatterOptions { throw new Error("Missing required field someOtherConfig."); } + return this; } // Return this struct in FFI function friendly format. @@ -62,7 +75,7 @@ export class FixedDecimalFormatterOptions { return obj; } - return new FixedDecimalFormatterOptions(obj); + return FixedDecimalFormatterOptions.fromFields(obj); } _writeToArrayBuffer( @@ -85,16 +98,16 @@ export class FixedDecimalFormatterOptions { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("FixedDecimalFormatterOptions._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const groupingStrategyDeref = diplomatRuntime.enumDiscriminant(wasm, ptr); structObj.groupingStrategy = new FixedDecimalGroupingStrategy(diplomatRuntime.internalConstructor, groupingStrategyDeref); const someOtherConfigDeref = (new Uint8Array(wasm.memory.buffer, ptr + 4, 1))[0] === 1; structObj.someOtherConfig = someOtherConfigDeref; - return new FixedDecimalFormatterOptions(structObj, internalConstructor); - } - - static default_() { + return new FixedDecimalFormatterOptions(diplomatRuntime.exposeConstructor, structObj); + } + + #defaultConstructor() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 8, 4, false); const result = wasm.icu4x_FixedDecimalFormatterOptions_default_mv1(diplomatReceive.buffer); @@ -106,5 +119,15 @@ export class FixedDecimalFormatterOptions { finally { diplomatReceive.free(); } - } + } + + constructor() { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/example/js/lib/api/FixedDecimalGroupingStrategy.d.ts b/example/js/lib/api/FixedDecimalGroupingStrategy.d.ts index c692e9429..3e5f5b60b 100644 --- a/example/js/lib/api/FixedDecimalGroupingStrategy.d.ts +++ b/example/js/lib/api/FixedDecimalGroupingStrategy.d.ts @@ -1,9 +1,12 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -// Base enumerator definition -export class FixedDecimalGroupingStrategy { - constructor(value : FixedDecimalGroupingStrategy | string); + + +export class FixedDecimalGroupingStrategy { + + + static fromValue(value : FixedDecimalGroupingStrategy | string) : FixedDecimalGroupingStrategy; get value() : string; @@ -12,5 +15,7 @@ export class FixedDecimalGroupingStrategy { static Auto : FixedDecimalGroupingStrategy; static Never : FixedDecimalGroupingStrategy; static Always : FixedDecimalGroupingStrategy; - static Min2 : FixedDecimalGroupingStrategy; + static Min2 : FixedDecimalGroupingStrategy; + + constructor(value: FixedDecimalGroupingStrategy | string ); } \ No newline at end of file diff --git a/example/js/lib/api/FixedDecimalGroupingStrategy.mjs b/example/js/lib/api/FixedDecimalGroupingStrategy.mjs index ba673bd3a..966d389d5 100644 --- a/example/js/lib/api/FixedDecimalGroupingStrategy.mjs +++ b/example/js/lib/api/FixedDecimalGroupingStrategy.mjs @@ -2,8 +2,10 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -// Base enumerator definition -export class FixedDecimalGroupingStrategy { + + +export class FixedDecimalGroupingStrategy { + #value = undefined; static #values = new Map([ @@ -16,14 +18,14 @@ export class FixedDecimalGroupingStrategy { static getAllEntries() { return FixedDecimalGroupingStrategy.#values.entries(); } - - constructor(value) { + + #internalConstructor(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 this; } return FixedDecimalGroupingStrategy.#objectValues[arguments[1]]; } @@ -35,13 +37,17 @@ export class FixedDecimalGroupingStrategy { let intVal = FixedDecimalGroupingStrategy.#values.get(value); // Nullish check, checks for null or undefined - if (intVal == null) { + if (intVal != null) { return FixedDecimalGroupingStrategy.#objectValues[intVal]; } throw TypeError(value + " is not a FixedDecimalGroupingStrategy and does not correspond to any of its enumerator values."); } + static fromValue(value) { + return new FixedDecimalGroupingStrategy(value); + } + get value() { return [...FixedDecimalGroupingStrategy.#values.keys()][this.#value]; } @@ -59,5 +65,9 @@ export class FixedDecimalGroupingStrategy { static Auto = FixedDecimalGroupingStrategy.#objectValues[0]; static Never = FixedDecimalGroupingStrategy.#objectValues[1]; static Always = FixedDecimalGroupingStrategy.#objectValues[2]; - static Min2 = FixedDecimalGroupingStrategy.#objectValues[3]; + static Min2 = FixedDecimalGroupingStrategy.#objectValues[3]; + + constructor(value) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/example/js/lib/api/Locale.d.ts b/example/js/lib/api/Locale.d.ts index df9c2944b..6d53d14d0 100644 --- a/example/js/lib/api/Locale.d.ts +++ b/example/js/lib/api/Locale.d.ts @@ -1,15 +1,16 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; - + /** An Locale, capable of representing strings like `"en-US"`. * -*See the [Rust documentation for `Locale`](https://docs.rs/icu/latest/icu/locid/struct.Locale.html) for more information. -*/ -export class Locale { +*See the [Rust documentation for `Locale`](https://docs.rs/icu/latest/icu/locid/struct.Locale.html) for more information. +*/ + + +export class Locale { - - get ffiValue(): pointer; - - static new_(name: string): Locale; + get ffiValue(): pointer; + + constructor(name: string); } \ No newline at end of file diff --git a/example/js/lib/api/Locale.mjs b/example/js/lib/api/Locale.mjs index de94e0f46..0a4fce0ec 100644 --- a/example/js/lib/api/Locale.mjs +++ b/example/js/lib/api/Locale.mjs @@ -2,16 +2,17 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; - + /** An Locale, capable of representing strings like `"en-US"`. * -*See the [Rust documentation for `Locale`](https://docs.rs/icu/latest/icu/locid/struct.Locale.html) for more information. -*/ +*See the [Rust documentation for `Locale`](https://docs.rs/icu/latest/icu/locid/struct.Locale.html) for more information. +*/ const Locale_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.icu4x_Locale_destroy_mv1(ptr); -}); - -export class Locale { +}); + +export class Locale { + // Internal ptr reference: #ptr = null; @@ -19,7 +20,7 @@ export class Locale { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("Locale is an Opaque type. You cannot call its constructor."); return; @@ -32,13 +33,14 @@ export class Locale { if (this.#selfEdge.length === 0) { Locale_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - - static new_(name) { + } + + #defaultConstructor(name) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); const nameSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.str8(wasm, name)); @@ -52,5 +54,15 @@ export class Locale { finally { functionCleanupArena.free(); } - } + } + + constructor(name) { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/example/js/lib/api/diplomat-runtime.mjs b/example/js/lib/api/diplomat-runtime.mjs index fc8d591f3..6c0e2b3c0 100644 --- a/example/js/lib/api/diplomat-runtime.mjs +++ b/example/js/lib/api/diplomat-runtime.mjs @@ -1,5 +1,11 @@ -/** For internal Diplomat use when constructing opaques or structs. */ +/** For internal Diplomat use when constructing opaques or out structs. + * This is for when we're handling items that we don't want the user to touch, like an structure that's only meant to be output, or de-referencing a pointer we're handed from WASM. + */ export const internalConstructor = Symbol("constructor"); +/** For internal Diplomat use when accessing a from-fields/from-value constructor that's been overridden by a default constructor. + * If we want to pass in arguments without also passing in internalConstructor to avoid triggering some logic we don't want, we use exposeConstructor. + */ +export const exposeConstructor = Symbol("exposeConstructor"); export function readString8(wasm, ptr, len) { const buf = new Uint8Array(wasm.memory.buffer, ptr, len); diff --git a/feature_tests/c/include/DefaultEnum.d.h b/feature_tests/c/include/DefaultEnum.d.h new file mode 100644 index 000000000..354e0834f --- /dev/null +++ b/feature_tests/c/include/DefaultEnum.d.h @@ -0,0 +1,23 @@ +#ifndef DefaultEnum_D_H +#define DefaultEnum_D_H + +#include +#include +#include +#include +#include "diplomat_runtime.h" + + + + + +typedef enum DefaultEnum { + DefaultEnum_A = 0, + DefaultEnum_B = 1, +} DefaultEnum; + +typedef struct DefaultEnum_option {union { DefaultEnum ok; }; bool is_ok; } DefaultEnum_option; + + + +#endif // DefaultEnum_D_H diff --git a/feature_tests/c/include/DefaultEnum.h b/feature_tests/c/include/DefaultEnum.h new file mode 100644 index 000000000..ac5442434 --- /dev/null +++ b/feature_tests/c/include/DefaultEnum.h @@ -0,0 +1,25 @@ +#ifndef DefaultEnum_H +#define DefaultEnum_H + +#include +#include +#include +#include +#include "diplomat_runtime.h" + + +#include "DefaultEnum.d.h" + + + + + + +DefaultEnum DefaultEnum_new(void); + + + + + + +#endif // DefaultEnum_H diff --git a/feature_tests/cpp/include/DefaultEnum.d.hpp b/feature_tests/cpp/include/DefaultEnum.d.hpp new file mode 100644 index 000000000..5b66b0bac --- /dev/null +++ b/feature_tests/cpp/include/DefaultEnum.d.hpp @@ -0,0 +1,47 @@ +#ifndef DefaultEnum_D_HPP +#define DefaultEnum_D_HPP + +#include +#include +#include +#include +#include +#include +#include "diplomat_runtime.hpp" + + +namespace diplomat { +namespace capi { + enum DefaultEnum { + DefaultEnum_A = 0, + DefaultEnum_B = 1, + }; + + typedef struct DefaultEnum_option {union { DefaultEnum ok; }; bool is_ok; } DefaultEnum_option; +} // namespace capi +} // namespace + +class DefaultEnum { +public: + enum Value { + A = 0, + B = 1, + }; + + DefaultEnum() = default; + // Implicit conversions between enum and ::Value + constexpr DefaultEnum(Value v) : value(v) {} + constexpr operator Value() const { return value; } + // Prevent usage as boolean value + explicit operator bool() const = delete; + + inline static DefaultEnum new_(); + + inline diplomat::capi::DefaultEnum AsFFI() const; + inline static DefaultEnum FromFFI(diplomat::capi::DefaultEnum c_enum); +private: + Value value; +}; + + +#endif // DefaultEnum_D_HPP diff --git a/feature_tests/cpp/include/DefaultEnum.hpp b/feature_tests/cpp/include/DefaultEnum.hpp new file mode 100644 index 000000000..d4f830ff6 --- /dev/null +++ b/feature_tests/cpp/include/DefaultEnum.hpp @@ -0,0 +1,44 @@ +#ifndef DefaultEnum_HPP +#define DefaultEnum_HPP + +#include "DefaultEnum.d.hpp" + +#include +#include +#include +#include +#include +#include +#include "diplomat_runtime.hpp" + + +namespace diplomat { +namespace capi { + extern "C" { + + diplomat::capi::DefaultEnum DefaultEnum_new(void); + + + } // extern "C" +} // namespace capi +} // namespace + +inline diplomat::capi::DefaultEnum DefaultEnum::AsFFI() const { + return static_cast(value); +} + +inline DefaultEnum DefaultEnum::FromFFI(diplomat::capi::DefaultEnum c_enum) { + switch (c_enum) { + case diplomat::capi::DefaultEnum_A: + case diplomat::capi::DefaultEnum_B: + return static_cast(c_enum); + default: + abort(); + } +} + +inline DefaultEnum DefaultEnum::new_() { + auto result = diplomat::capi::DefaultEnum_new(); + return DefaultEnum::FromFFI(result); +} +#endif // DefaultEnum_HPP diff --git a/feature_tests/dart/lib/src/DefaultEnum.g.dart b/feature_tests/dart/lib/src/DefaultEnum.g.dart new file mode 100644 index 000000000..60fb9e533 --- /dev/null +++ b/feature_tests/dart/lib/src/DefaultEnum.g.dart @@ -0,0 +1,19 @@ +// generated by diplomat-tool + +part of 'lib.g.dart'; + +enum DefaultEnum { + a, + + b; + + static DefaultEnum new_() { + final result = _DefaultEnum_new(); + return DefaultEnum.values[result]; + } +} + +@meta.RecordUse() +@ffi.Native(isLeaf: true, symbol: 'DefaultEnum_new') +// ignore: non_constant_identifier_names +external int _DefaultEnum_new(); diff --git a/feature_tests/dart/lib/src/lib.g.dart b/feature_tests/dart/lib/src/lib.g.dart index 19976ac8c..d3f59089f 100644 --- a/feature_tests/dart/lib/src/lib.g.dart +++ b/feature_tests/dart/lib/src/lib.g.dart @@ -19,6 +19,7 @@ part 'ContiguousEnum.g.dart'; part 'CyclicStructA.g.dart'; part 'CyclicStructB.g.dart'; part 'CyclicStructC.g.dart'; +part 'DefaultEnum.g.dart'; part 'ErrorEnum.g.dart'; part 'ErrorStruct.g.dart'; part 'Float64Vec.g.dart'; diff --git a/feature_tests/demo_gen/demo/CyclicStructA.mjs b/feature_tests/demo_gen/demo/CyclicStructA.mjs index cd8983d00..8ec0f6315 100644 --- a/feature_tests/demo_gen/demo/CyclicStructA.mjs +++ b/feature_tests/demo_gen/demo/CyclicStructA.mjs @@ -5,13 +5,13 @@ export function cyclicOut(field) { null, [ (function (...args) { - return new CyclicStructA({ + return CyclicStructA.fromFields({ a: args[0]}); }).apply( null, [ (function (...args) { - return new CyclicStructB({ + return CyclicStructB.fromFields({ field: args[0]}); }).apply( null, diff --git a/feature_tests/demo_gen/demo/CyclicStructC.mjs b/feature_tests/demo_gen/demo/CyclicStructC.mjs index 4576838c9..a53ecd531 100644 --- a/feature_tests/demo_gen/demo/CyclicStructC.mjs +++ b/feature_tests/demo_gen/demo/CyclicStructC.mjs @@ -6,19 +6,19 @@ export function cyclicOut(field) { null, [ (function (...args) { - return new CyclicStructC({ + return CyclicStructC.fromFields({ a: args[0]}); }).apply( null, [ (function (...args) { - return new CyclicStructA({ + return CyclicStructA.fromFields({ a: args[0]}); }).apply( null, [ (function (...args) { - return new CyclicStructB({ + return CyclicStructB.fromFields({ field: args[0]}); }).apply( null, diff --git a/feature_tests/demo_gen/demo/Float64Vec.mjs b/feature_tests/demo_gen/demo/Float64Vec.mjs index f321848ce..1baf3a9c5 100644 --- a/feature_tests/demo_gen/demo/Float64Vec.mjs +++ b/feature_tests/demo_gen/demo/Float64Vec.mjs @@ -3,7 +3,7 @@ export function toString(v) { return (function (...args) { return args[0].toString(...args.slice(1)) }).apply( null, [ - Float64Vec.newFromOwned.apply( + (function (...args) { return new Float64Vec(...args) } ).apply( null, [ v diff --git a/feature_tests/demo_gen/demo/MyString.mjs b/feature_tests/demo_gen/demo/MyString.mjs index efba98356..dc3a9e7a1 100644 --- a/feature_tests/demo_gen/demo/MyString.mjs +++ b/feature_tests/demo_gen/demo/MyString.mjs @@ -3,7 +3,7 @@ export function getStr(v) { return (function (...args) { return args[0].getStr }).apply( null, [ - MyString.new_.apply( + (function (...args) { return new MyString(...args) } ).apply( null, [ v diff --git a/feature_tests/demo_gen/demo/Opaque.mjs b/feature_tests/demo_gen/demo/Opaque.mjs index 626b27275..ec39b6218 100644 --- a/feature_tests/demo_gen/demo/Opaque.mjs +++ b/feature_tests/demo_gen/demo/Opaque.mjs @@ -3,7 +3,7 @@ export function getDebugStr() { return (function (...args) { return args[0].getDebugStr(...args.slice(1)) }).apply( null, [ - Opaque.new_.apply( + (function (...args) { return new Opaque(...args) } ).apply( null, [ ] diff --git a/feature_tests/demo_gen/demo/Utf16Wrap.mjs b/feature_tests/demo_gen/demo/Utf16Wrap.mjs index 0ba39fba7..7346d421f 100644 --- a/feature_tests/demo_gen/demo/Utf16Wrap.mjs +++ b/feature_tests/demo_gen/demo/Utf16Wrap.mjs @@ -3,7 +3,7 @@ export function getDebugStr(input) { return (function (...args) { return args[0].getDebugStr(...args.slice(1)) }).apply( null, [ - Utf16Wrap.fromUtf16.apply( + (function (...args) { return new Utf16Wrap(...args) } ).apply( null, [ input diff --git a/feature_tests/js/api/AttrOpaque1Renamed.d.ts b/feature_tests/js/api/AttrOpaque1Renamed.d.ts index be40b1e74..5c4acdc8e 100644 --- a/feature_tests/js/api/AttrOpaque1Renamed.d.ts +++ b/feature_tests/js/api/AttrOpaque1Renamed.d.ts @@ -3,18 +3,19 @@ import type { RenamedAttrEnum } from "./RenamedAttrEnum" import type { Unnamespaced } from "./Unnamespaced" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class AttrOpaque1Renamed { + + +export class AttrOpaque1Renamed { - - get ffiValue(): pointer; - - static totallyNotNew(): AttrOpaque1Renamed; - - get methodRenamed(): number; - - get abirenamed(): number; - - useUnnamespaced(un: Unnamespaced): void; - - useNamespaced(n: RenamedAttrEnum): void; + get ffiValue(): pointer; + + get methodRenamed(): number; + + get abirenamed(): number; + + useUnnamespaced(un: Unnamespaced): void; + + useNamespaced(n: RenamedAttrEnum): void; + + constructor(); } \ No newline at end of file diff --git a/feature_tests/js/api/AttrOpaque1Renamed.mjs b/feature_tests/js/api/AttrOpaque1Renamed.mjs index 5c550dfc7..0394d140b 100644 --- a/feature_tests/js/api/AttrOpaque1Renamed.mjs +++ b/feature_tests/js/api/AttrOpaque1Renamed.mjs @@ -6,9 +6,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const AttrOpaque1Renamed_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.namespace_AttrOpaque1_destroy(ptr); -}); - -export class AttrOpaque1Renamed { +}); + +export class AttrOpaque1Renamed { + // Internal ptr reference: #ptr = null; @@ -16,7 +17,7 @@ export class AttrOpaque1Renamed { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("AttrOpaque1Renamed is an Opaque type. You cannot call its constructor."); return; @@ -29,13 +30,14 @@ export class AttrOpaque1Renamed { if (this.#selfEdge.length === 0) { AttrOpaque1Renamed_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - - static totallyNotNew() { + } + + #defaultConstructor() { const result = wasm.namespace_AttrOpaque1_new(); try { @@ -43,8 +45,8 @@ export class AttrOpaque1Renamed { } finally {} - } - + } + get methodRenamed() { const result = wasm.namespace_AttrOpaque1_method(this.ffiValue); @@ -53,8 +55,8 @@ export class AttrOpaque1Renamed { } finally {} - } - + } + get abirenamed() { const result = wasm.renamed_on_abi_only(this.ffiValue); @@ -63,19 +65,29 @@ export class AttrOpaque1Renamed { } finally {} - } - + } + useUnnamespaced(un) {wasm.namespace_AttrOpaque1_use_unnamespaced(this.ffiValue, un.ffiValue); try {} finally {} - } - + } + useNamespaced(n) {wasm.namespace_AttrOpaque1_use_namespaced(this.ffiValue, n.ffiValue); try {} finally {} - } + } + + constructor() { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/feature_tests/js/api/Bar.d.ts b/feature_tests/js/api/Bar.d.ts index cec745181..34f0bf15d 100644 --- a/feature_tests/js/api/Bar.d.ts +++ b/feature_tests/js/api/Bar.d.ts @@ -2,10 +2,11 @@ import type { Foo } from "./Foo" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class Bar { + + +export class Bar { - - get ffiValue(): pointer; - - get foo(): Foo; + get ffiValue(): pointer; + + get foo(): Foo; } \ No newline at end of file diff --git a/feature_tests/js/api/Bar.mjs b/feature_tests/js/api/Bar.mjs index 9d7ce6553..04e7dfab4 100644 --- a/feature_tests/js/api/Bar.mjs +++ b/feature_tests/js/api/Bar.mjs @@ -5,9 +5,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const Bar_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.Bar_destroy(ptr); -}); - -export class Bar { +}); + +export class Bar { + // Internal ptr reference: #ptr = null; @@ -17,7 +18,7 @@ export class Bar { #bEdge = []; #aEdge = []; - constructor(symbol, ptr, selfEdge, bEdge, aEdge) { + #internalConstructor(symbol, ptr, selfEdge, bEdge, aEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("Bar is an Opaque type. You cannot call its constructor."); return; @@ -36,12 +37,13 @@ export class Bar { if (this.#selfEdge.length === 0) { Bar_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + get foo() { // This lifetime edge depends on lifetimes 'b, 'a let bEdges = [this]; @@ -56,5 +58,9 @@ export class Bar { } finally {} - } + } + + constructor(symbol, ptr, selfEdge, bEdge, aEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/BigStructWithStuff.d.ts b/feature_tests/js/api/BigStructWithStuff.d.ts index add1d37c5..ba2294585 100644 --- a/feature_tests/js/api/BigStructWithStuff.d.ts +++ b/feature_tests/js/api/BigStructWithStuff.d.ts @@ -3,9 +3,9 @@ import type { ScalarPairWithPadding } from "./ScalarPairWithPadding" import type { ScalarPairWithPadding_obj } from "./ScalarPairWithPadding" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; - -/** Testing JS-specific layout/padding behavior -*/ + +/** Testing JS-specific layout/padding behavior +*/ type BigStructWithStuff_obj = { first: number; second: number; @@ -14,23 +14,32 @@ type BigStructWithStuff_obj = { fifth: number; }; -export class BigStructWithStuff { - - get first() : number; + + +export class BigStructWithStuff { + + get first() : number; set first(value: number); - - get second() : number; + + get second() : number; set second(value: number); - - get third() : number; + + get third() : number; set third(value: number); - - get fourth() : ScalarPairWithPadding; + + get fourth() : ScalarPairWithPadding; set fourth(value: ScalarPairWithPadding); - - get fifth() : number; + + get fifth() : number; set fifth(value: number); - constructor(structObj : BigStructWithStuff_obj); - - assertValue(extraVal: number): void; + + /** Create `BigStructWithStuff` from an object that contains all of `BigStructWithStuff`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : BigStructWithStuff_obj) : BigStructWithStuff; + + + assertValue(extraVal: number): void; + + constructor(structObj : BigStructWithStuff_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/BigStructWithStuff.mjs b/feature_tests/js/api/BigStructWithStuff.mjs index 1669c9eba..9ad39095e 100644 --- a/feature_tests/js/api/BigStructWithStuff.mjs +++ b/feature_tests/js/api/BigStructWithStuff.mjs @@ -3,51 +3,66 @@ import { ScalarPairWithPadding } from "./ScalarPairWithPadding.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; - -/** Testing JS-specific layout/padding behavior -*/ -export class BigStructWithStuff { - + +/** Testing JS-specific layout/padding behavior +*/ + + +export class BigStructWithStuff { + #first; + get first() { return this.#first; - } + } set first(value) { this.#first = value; } - + #second; + get second() { return this.#second; - } + } set second(value) { this.#second = value; } - + #third; + get third() { return this.#third; - } + } set third(value) { this.#third = value; } - + #fourth; + get fourth() { return this.#fourth; - } + } set fourth(value) { this.#fourth = value; } - + #fifth; + get fifth() { return this.#fifth; - } + } set fifth(value) { this.#fifth = value; } - constructor(structObj) { + + /** Create `BigStructWithStuff` from an object that contains all of `BigStructWithStuff`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new BigStructWithStuff(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("BigStructWithStuff's constructor takes an object of BigStructWithStuff's fields."); } @@ -82,6 +97,7 @@ export class BigStructWithStuff { throw new Error("Missing required field fifth."); } + return this; } // Return this struct in FFI function friendly format. @@ -103,7 +119,7 @@ export class BigStructWithStuff { return obj; } - return new BigStructWithStuff(obj); + return BigStructWithStuff.fromFields(obj); } _writeToArrayBuffer( @@ -128,7 +144,7 @@ export class BigStructWithStuff { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("BigStructWithStuff._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const firstDeref = (new Uint8Array(wasm.memory.buffer, ptr, 1))[0]; structObj.first = firstDeref; const secondDeref = (new Uint16Array(wasm.memory.buffer, ptr + 2, 1))[0]; @@ -140,9 +156,9 @@ export class BigStructWithStuff { const fifthDeref = (new Uint8Array(wasm.memory.buffer, ptr + 16, 1))[0]; structObj.fifth = fifthDeref; - return new BigStructWithStuff(structObj, internalConstructor); - } - + return new BigStructWithStuff(structObj); + } + assertValue(extraVal) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); wasm.BigStructWithStuff_assert_value(...this._intoFFI(), extraVal); @@ -152,5 +168,9 @@ export class BigStructWithStuff { finally { functionCleanupArena.free(); } - } + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/BorrowedFields.d.ts b/feature_tests/js/api/BorrowedFields.d.ts index 13c15d576..ae73f2444 100644 --- a/feature_tests/js/api/BorrowedFields.d.ts +++ b/feature_tests/js/api/BorrowedFields.d.ts @@ -8,17 +8,26 @@ type BorrowedFields_obj = { c: string; }; -export class BorrowedFields { - - get a() : string; + + +export class BorrowedFields { + + get a() : string; set a(value: string); - - get b() : string; + + get b() : string; set b(value: string); - - get c() : string; + + get c() : string; set c(value: string); - constructor(structObj : BorrowedFields_obj); - - static fromBarAndStrings(bar: Bar, dstr16: string, utf8Str: string): BorrowedFields; + + /** Create `BorrowedFields` from an object that contains all of `BorrowedFields`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : BorrowedFields_obj) : BorrowedFields; + + + static fromBarAndStrings(bar: Bar, dstr16: string, utf8Str: string): BorrowedFields; + + constructor(structObj : BorrowedFields_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/BorrowedFields.mjs b/feature_tests/js/api/BorrowedFields.mjs index b3182c6b7..e3eb72854 100644 --- a/feature_tests/js/api/BorrowedFields.mjs +++ b/feature_tests/js/api/BorrowedFields.mjs @@ -3,32 +3,45 @@ import { Bar } from "./Bar.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class BorrowedFields { - + + +export class BorrowedFields { + #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(structObj) { + + /** Create `BorrowedFields` from an object that contains all of `BorrowedFields`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new BorrowedFields(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("BorrowedFields's constructor takes an object of BorrowedFields's fields."); } @@ -51,6 +64,7 @@ export class BorrowedFields { throw new Error("Missing required field c."); } + return this; } // Return this struct in FFI function friendly format. @@ -75,7 +89,7 @@ export class BorrowedFields { return obj; } - return new BorrowedFields(obj); + return BorrowedFields.fromFields(obj); } _writeToArrayBuffer( @@ -93,7 +107,7 @@ export class BorrowedFields { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("BorrowedFields._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const aDeref = ptr; structObj.a = new diplomatRuntime.DiplomatSliceStr(wasm, aDeref, "string16", aEdges).getValue(); const bDeref = ptr + 8; @@ -101,7 +115,7 @@ export class BorrowedFields { const cDeref = ptr + 16; structObj.c = new diplomatRuntime.DiplomatSliceStr(wasm, cDeref, "string8", aEdges).getValue(); - return new BorrowedFields(structObj, internalConstructor); + return new BorrowedFields(structObj); } // Return all fields corresponding to lifetime `'a` @@ -111,8 +125,8 @@ export class BorrowedFields { // the caller should take care to also call _fieldsForLifetimeOther get _fieldsForLifetimeA() { return [a, b, c]; - }; - + }; + static fromBarAndStrings(bar, dstr16, utf8Str) { let functionGarbageCollectorGrip = new diplomatRuntime.GarbageCollectorGrip(); const dstr16Slice = functionGarbageCollectorGrip.alloc(diplomatRuntime.DiplomatBuf.str16(wasm, dstr16)); @@ -135,5 +149,9 @@ export class BorrowedFields { diplomatReceive.free(); } - } + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/BorrowedFieldsReturning.d.ts b/feature_tests/js/api/BorrowedFieldsReturning.d.ts index 609874175..0ea70a813 100644 --- a/feature_tests/js/api/BorrowedFieldsReturning.d.ts +++ b/feature_tests/js/api/BorrowedFieldsReturning.d.ts @@ -5,9 +5,18 @@ type BorrowedFieldsReturning_obj = { bytes: string; }; -export class BorrowedFieldsReturning { - - get bytes() : string; + + +export class BorrowedFieldsReturning { + + get bytes() : string; set bytes(value: string); - constructor(structObj : BorrowedFieldsReturning_obj); + + /** Create `BorrowedFieldsReturning` from an object that contains all of `BorrowedFieldsReturning`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : BorrowedFieldsReturning_obj) : BorrowedFieldsReturning; + + + constructor(structObj : BorrowedFieldsReturning_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/BorrowedFieldsReturning.mjs b/feature_tests/js/api/BorrowedFieldsReturning.mjs index ef1cda7b6..3f117c0d8 100644 --- a/feature_tests/js/api/BorrowedFieldsReturning.mjs +++ b/feature_tests/js/api/BorrowedFieldsReturning.mjs @@ -2,16 +2,27 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class BorrowedFieldsReturning { - + + +export class BorrowedFieldsReturning { + #bytes; + get bytes() { return this.#bytes; - } + } set bytes(value) { this.#bytes = value; } - constructor(structObj) { + + /** Create `BorrowedFieldsReturning` from an object that contains all of `BorrowedFieldsReturning`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new BorrowedFieldsReturning(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("BorrowedFieldsReturning's constructor takes an object of BorrowedFieldsReturning's fields."); } @@ -22,6 +33,7 @@ export class BorrowedFieldsReturning { throw new Error("Missing required field bytes."); } + return this; } // Return this struct in FFI function friendly format. @@ -46,7 +58,7 @@ export class BorrowedFieldsReturning { return obj; } - return new BorrowedFieldsReturning(obj); + return BorrowedFieldsReturning.fromFields(obj); } _writeToArrayBuffer( @@ -62,11 +74,11 @@ export class BorrowedFieldsReturning { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("BorrowedFieldsReturning._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const bytesDeref = ptr; structObj.bytes = new diplomatRuntime.DiplomatSliceStr(wasm, bytesDeref, "string8", aEdges).getValue(); - return new BorrowedFieldsReturning(structObj, internalConstructor); + return new BorrowedFieldsReturning(structObj); } // Return all fields corresponding to lifetime `'a` @@ -76,5 +88,9 @@ export class BorrowedFieldsReturning { // the caller should take care to also call _fieldsForLifetimeOther get _fieldsForLifetimeA() { return [bytes]; - }; + }; + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/BorrowedFieldsWithBounds.d.ts b/feature_tests/js/api/BorrowedFieldsWithBounds.d.ts index 875d7b41f..d012c95e7 100644 --- a/feature_tests/js/api/BorrowedFieldsWithBounds.d.ts +++ b/feature_tests/js/api/BorrowedFieldsWithBounds.d.ts @@ -8,17 +8,26 @@ type BorrowedFieldsWithBounds_obj = { fieldC: string; }; -export class BorrowedFieldsWithBounds { - - get fieldA() : string; + + +export class BorrowedFieldsWithBounds { + + get fieldA() : string; set fieldA(value: string); - - get fieldB() : string; + + get fieldB() : string; set fieldB(value: string); - - get fieldC() : string; + + get fieldC() : string; set fieldC(value: string); - constructor(structObj : BorrowedFieldsWithBounds_obj); - - static fromFooAndStrings(foo: Foo, dstr16X: string, utf8StrZ: string): BorrowedFieldsWithBounds; + + /** Create `BorrowedFieldsWithBounds` from an object that contains all of `BorrowedFieldsWithBounds`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : BorrowedFieldsWithBounds_obj) : BorrowedFieldsWithBounds; + + + static fromFooAndStrings(foo: Foo, dstr16X: string, utf8StrZ: string): BorrowedFieldsWithBounds; + + constructor(structObj : BorrowedFieldsWithBounds_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/BorrowedFieldsWithBounds.mjs b/feature_tests/js/api/BorrowedFieldsWithBounds.mjs index 91faddaaf..2fb1e63ed 100644 --- a/feature_tests/js/api/BorrowedFieldsWithBounds.mjs +++ b/feature_tests/js/api/BorrowedFieldsWithBounds.mjs @@ -3,32 +3,45 @@ import { Foo } from "./Foo.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class BorrowedFieldsWithBounds { - + + +export class BorrowedFieldsWithBounds { + #fieldA; + get fieldA() { return this.#fieldA; - } + } set fieldA(value) { this.#fieldA = value; } - + #fieldB; + get fieldB() { return this.#fieldB; - } + } set fieldB(value) { this.#fieldB = value; } - + #fieldC; + get fieldC() { return this.#fieldC; - } + } set fieldC(value) { this.#fieldC = value; } - constructor(structObj) { + + /** Create `BorrowedFieldsWithBounds` from an object that contains all of `BorrowedFieldsWithBounds`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new BorrowedFieldsWithBounds(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("BorrowedFieldsWithBounds's constructor takes an object of BorrowedFieldsWithBounds's fields."); } @@ -51,6 +64,7 @@ export class BorrowedFieldsWithBounds { throw new Error("Missing required field fieldC."); } + return this; } // Return this struct in FFI function friendly format. @@ -77,7 +91,7 @@ export class BorrowedFieldsWithBounds { return obj; } - return new BorrowedFieldsWithBounds(obj); + return BorrowedFieldsWithBounds.fromFields(obj); } _writeToArrayBuffer( @@ -95,7 +109,7 @@ export class BorrowedFieldsWithBounds { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("BorrowedFieldsWithBounds._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const fieldADeref = ptr; structObj.fieldA = new diplomatRuntime.DiplomatSliceStr(wasm, fieldADeref, "string16", aEdges).getValue(); const fieldBDeref = ptr + 8; @@ -103,7 +117,7 @@ export class BorrowedFieldsWithBounds { const fieldCDeref = ptr + 16; structObj.fieldC = new diplomatRuntime.DiplomatSliceStr(wasm, fieldCDeref, "string8", cEdges).getValue(); - return new BorrowedFieldsWithBounds(structObj, internalConstructor); + return new BorrowedFieldsWithBounds(structObj); } // Return all fields corresponding to lifetime `'a` @@ -131,8 +145,8 @@ export class BorrowedFieldsWithBounds { // the caller should take care to also call _fieldsForLifetimeOther get _fieldsForLifetimeC() { return [fieldC]; - }; - + }; + static fromFooAndStrings(foo, dstr16X, utf8StrZ) { let functionGarbageCollectorGrip = new diplomatRuntime.GarbageCollectorGrip(); const dstr16XSlice = functionGarbageCollectorGrip.alloc(diplomatRuntime.DiplomatBuf.str16(wasm, dstr16X)); @@ -161,5 +175,9 @@ export class BorrowedFieldsWithBounds { diplomatReceive.free(); } - } + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/ContiguousEnum.d.ts b/feature_tests/js/api/ContiguousEnum.d.ts index 851a5430a..7750755be 100644 --- a/feature_tests/js/api/ContiguousEnum.d.ts +++ b/feature_tests/js/api/ContiguousEnum.d.ts @@ -1,9 +1,12 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -// Base enumerator definition -export class ContiguousEnum { - constructor(value : ContiguousEnum | string); + + +export class ContiguousEnum { + + + static fromValue(value : ContiguousEnum | string) : ContiguousEnum; get value() : string; @@ -12,5 +15,7 @@ export class ContiguousEnum { static C : ContiguousEnum; static D : ContiguousEnum; static E : ContiguousEnum; - static F : ContiguousEnum; + static F : ContiguousEnum; + + constructor(value: ContiguousEnum | string ); } \ No newline at end of file diff --git a/feature_tests/js/api/ContiguousEnum.mjs b/feature_tests/js/api/ContiguousEnum.mjs index 77aeb5bd1..34c5f99ec 100644 --- a/feature_tests/js/api/ContiguousEnum.mjs +++ b/feature_tests/js/api/ContiguousEnum.mjs @@ -2,8 +2,10 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -// Base enumerator definition -export class ContiguousEnum { + + +export class ContiguousEnum { + #value = undefined; static #values = new Map([ @@ -16,14 +18,14 @@ export class ContiguousEnum { static getAllEntries() { return ContiguousEnum.#values.entries(); } - - constructor(value) { + + #internalConstructor(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 this; } return ContiguousEnum.#objectValues[arguments[1]]; } @@ -35,13 +37,17 @@ export class ContiguousEnum { let intVal = ContiguousEnum.#values.get(value); // Nullish check, checks for null or undefined - if (intVal == null) { + if (intVal != null) { return ContiguousEnum.#objectValues[intVal]; } throw TypeError(value + " is not a ContiguousEnum and does not correspond to any of its enumerator values."); } + static fromValue(value) { + return new ContiguousEnum(value); + } + get value() { return [...ContiguousEnum.#values.keys()][this.#value]; } @@ -59,5 +65,9 @@ export class ContiguousEnum { static C = ContiguousEnum.#objectValues[0]; static D = ContiguousEnum.#objectValues[1]; static E = ContiguousEnum.#objectValues[2]; - static F = ContiguousEnum.#objectValues[3]; + static F = ContiguousEnum.#objectValues[3]; + + constructor(value) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/CyclicStructA.d.ts b/feature_tests/js/api/CyclicStructA.d.ts index d4a4fde52..f5149146b 100644 --- a/feature_tests/js/api/CyclicStructA.d.ts +++ b/feature_tests/js/api/CyclicStructA.d.ts @@ -7,13 +7,22 @@ type CyclicStructA_obj = { a: CyclicStructB_obj; }; -export class CyclicStructA { - - get a() : CyclicStructB; + + +export class CyclicStructA { + + get a() : CyclicStructB; set a(value: CyclicStructB); - constructor(structObj : CyclicStructA_obj); - - static getB(): CyclicStructB; - - cyclicOut(): string; + + /** Create `CyclicStructA` from an object that contains all of `CyclicStructA`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : CyclicStructA_obj) : CyclicStructA; + + + static getB(): CyclicStructB; + + cyclicOut(): string; + + constructor(structObj : CyclicStructA_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/CyclicStructA.mjs b/feature_tests/js/api/CyclicStructA.mjs index d9cb148ab..2f5c2bdcb 100644 --- a/feature_tests/js/api/CyclicStructA.mjs +++ b/feature_tests/js/api/CyclicStructA.mjs @@ -3,16 +3,27 @@ import { CyclicStructB } from "./CyclicStructB.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class CyclicStructA { - + + +export class CyclicStructA { + #a; + get a() { return this.#a; - } + } set a(value) { this.#a = value; } - constructor(structObj) { + + /** Create `CyclicStructA` from an object that contains all of `CyclicStructA`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new CyclicStructA(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("CyclicStructA's constructor takes an object of CyclicStructA's fields."); } @@ -23,6 +34,7 @@ export class CyclicStructA { throw new Error("Missing required field a."); } + return this; } // Return this struct in FFI function friendly format. @@ -44,7 +56,7 @@ export class CyclicStructA { return obj; } - return new CyclicStructA(obj); + return CyclicStructA.fromFields(obj); } _writeToArrayBuffer( @@ -65,13 +77,13 @@ export class CyclicStructA { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("CyclicStructA._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const aDeref = primitiveValue; structObj.a = CyclicStructB._fromFFI(diplomatRuntime.internalConstructor, aDeref); - return new CyclicStructA(structObj, internalConstructor); - } - + return new CyclicStructA(structObj); + } + static getB() { const result = wasm.CyclicStructA_get_b(); @@ -80,8 +92,8 @@ export class CyclicStructA { } finally {} - } - + } + cyclicOut() { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -97,5 +109,9 @@ export class CyclicStructA { write.free(); } - } + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/CyclicStructB.d.ts b/feature_tests/js/api/CyclicStructB.d.ts index 74a06af26..6cc3a4f2c 100644 --- a/feature_tests/js/api/CyclicStructB.d.ts +++ b/feature_tests/js/api/CyclicStructB.d.ts @@ -6,13 +6,22 @@ type CyclicStructB_obj = { field: number; }; -export class CyclicStructB { - - get field() : number; + + +export class CyclicStructB { + + get field() : number; set field(value: number); - constructor(structObj : CyclicStructB_obj); - - static getA(): CyclicStructA; - - static getAOption(): CyclicStructA | null; + + /** Create `CyclicStructB` from an object that contains all of `CyclicStructB`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : CyclicStructB_obj) : CyclicStructB; + + + static getA(): CyclicStructA; + + static getAOption(): CyclicStructA | null; + + constructor(structObj : CyclicStructB_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/CyclicStructB.mjs b/feature_tests/js/api/CyclicStructB.mjs index 6f87daf7f..063cf553b 100644 --- a/feature_tests/js/api/CyclicStructB.mjs +++ b/feature_tests/js/api/CyclicStructB.mjs @@ -3,16 +3,27 @@ import { CyclicStructA } from "./CyclicStructA.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class CyclicStructB { - + + +export class CyclicStructB { + #field; + get field() { return this.#field; - } + } set field(value) { this.#field = value; } - constructor(structObj) { + + /** Create `CyclicStructB` from an object that contains all of `CyclicStructB`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new CyclicStructB(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("CyclicStructB's constructor takes an object of CyclicStructB's fields."); } @@ -23,6 +34,7 @@ export class CyclicStructB { throw new Error("Missing required field field."); } + return this; } // Return this struct in FFI function friendly format. @@ -44,7 +56,7 @@ export class CyclicStructB { return obj; } - return new CyclicStructB(obj); + return CyclicStructB.fromFields(obj); } _writeToArrayBuffer( @@ -65,13 +77,13 @@ export class CyclicStructB { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("CyclicStructB._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; structObj.field = primitiveValue; - return new CyclicStructB(structObj, internalConstructor); - } - + return new CyclicStructB(structObj); + } + static getA() { const result = wasm.CyclicStructB_get_a(); @@ -80,8 +92,8 @@ export class CyclicStructB { } finally {} - } - + } + static getAOption() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 2, 1, true); @@ -97,5 +109,9 @@ export class CyclicStructB { finally { diplomatReceive.free(); } - } + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/CyclicStructC.d.ts b/feature_tests/js/api/CyclicStructC.d.ts index 0edd8f613..22ec416e1 100644 --- a/feature_tests/js/api/CyclicStructC.d.ts +++ b/feature_tests/js/api/CyclicStructC.d.ts @@ -7,13 +7,22 @@ type CyclicStructC_obj = { a: CyclicStructA_obj; }; -export class CyclicStructC { - - get a() : CyclicStructA; + + +export class CyclicStructC { + + get a() : CyclicStructA; set a(value: CyclicStructA); - constructor(structObj : CyclicStructC_obj); - - static takesNestedParameters(c: CyclicStructC_obj): CyclicStructC; - - cyclicOut(): string; + + /** Create `CyclicStructC` from an object that contains all of `CyclicStructC`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : CyclicStructC_obj) : CyclicStructC; + + + static takesNestedParameters(c: CyclicStructC_obj): CyclicStructC; + + cyclicOut(): string; + + constructor(structObj : CyclicStructC_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/CyclicStructC.mjs b/feature_tests/js/api/CyclicStructC.mjs index 221beb115..2ccfece3a 100644 --- a/feature_tests/js/api/CyclicStructC.mjs +++ b/feature_tests/js/api/CyclicStructC.mjs @@ -3,16 +3,27 @@ import { CyclicStructA } from "./CyclicStructA.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class CyclicStructC { - + + +export class CyclicStructC { + #a; + get a() { return this.#a; - } + } set a(value) { this.#a = value; } - constructor(structObj) { + + /** Create `CyclicStructC` from an object that contains all of `CyclicStructC`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new CyclicStructC(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("CyclicStructC's constructor takes an object of CyclicStructC's fields."); } @@ -23,6 +34,7 @@ export class CyclicStructC { throw new Error("Missing required field a."); } + return this; } // Return this struct in FFI function friendly format. @@ -44,7 +56,7 @@ export class CyclicStructC { return obj; } - return new CyclicStructC(obj); + return CyclicStructC.fromFields(obj); } _writeToArrayBuffer( @@ -65,13 +77,13 @@ export class CyclicStructC { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("CyclicStructC._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const aDeref = primitiveValue; structObj.a = CyclicStructA._fromFFI(diplomatRuntime.internalConstructor, aDeref); - return new CyclicStructC(structObj, internalConstructor); - } - + return new CyclicStructC(structObj); + } + static takesNestedParameters(c) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -84,8 +96,8 @@ export class CyclicStructC { finally { functionCleanupArena.free(); } - } - + } + cyclicOut() { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -101,5 +113,9 @@ export class CyclicStructC { write.free(); } - } + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/DefaultEnum.d.ts b/feature_tests/js/api/DefaultEnum.d.ts new file mode 100644 index 000000000..8e27209ff --- /dev/null +++ b/feature_tests/js/api/DefaultEnum.d.ts @@ -0,0 +1,19 @@ +// generated by diplomat-tool +import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; + + + +export class DefaultEnum { + + + static fromValue(value : DefaultEnum | string) : DefaultEnum; + + get value() : string; + + get ffiValue() : number; + + static A : DefaultEnum; + static B : DefaultEnum; + + constructor(); +} \ No newline at end of file diff --git a/feature_tests/js/api/DefaultEnum.mjs b/feature_tests/js/api/DefaultEnum.mjs new file mode 100644 index 000000000..3afd89aeb --- /dev/null +++ b/feature_tests/js/api/DefaultEnum.mjs @@ -0,0 +1,83 @@ +// generated by diplomat-tool +import wasm from "./diplomat-wasm.mjs"; +import * as diplomatRuntime from "./diplomat-runtime.mjs"; + + + +export class DefaultEnum { + + #value = undefined; + + static #values = new Map([ + ["A", 0], + ["B", 1] + ]); + + static getAllEntries() { + return DefaultEnum.#values.entries(); + } + + #internalConstructor(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 this; + } + return DefaultEnum.#objectValues[arguments[1]]; + } + + if (value instanceof DefaultEnum) { + return value; + } + + let intVal = DefaultEnum.#values.get(value); + + // Nullish check, checks for null or undefined + if (intVal != null) { + return DefaultEnum.#objectValues[intVal]; + } + + throw TypeError(value + " is not a DefaultEnum and does not correspond to any of its enumerator values."); + } + + static fromValue(value) { + return new DefaultEnum(diplomatRuntime.exposeConstructor, value); + } + + get value() { + return [...DefaultEnum.#values.keys()][this.#value]; + } + + get ffiValue() { + return this.#value; + } + static #objectValues = [ + new DefaultEnum(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 0), + new DefaultEnum(diplomatRuntime.internalConstructor, diplomatRuntime.internalConstructor, 1), + ]; + + static A = DefaultEnum.#objectValues[0]; + static B = DefaultEnum.#objectValues[1]; + + #defaultConstructor() { + const result = wasm.DefaultEnum_new(); + + try { + return new DefaultEnum(diplomatRuntime.internalConstructor, result); + } + + finally {} + } + + constructor() { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } +} \ No newline at end of file diff --git a/feature_tests/js/api/ErrorEnum.d.ts b/feature_tests/js/api/ErrorEnum.d.ts index 802bfd300..918bbd0ae 100644 --- a/feature_tests/js/api/ErrorEnum.d.ts +++ b/feature_tests/js/api/ErrorEnum.d.ts @@ -1,14 +1,19 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -// Base enumerator definition -export class ErrorEnum { - constructor(value : ErrorEnum | string); + + +export class ErrorEnum { + + + static fromValue(value : ErrorEnum | string) : ErrorEnum; get value() : string; get ffiValue() : number; static Foo : ErrorEnum; - static Bar : ErrorEnum; + static Bar : ErrorEnum; + + constructor(value: ErrorEnum | string ); } \ No newline at end of file diff --git a/feature_tests/js/api/ErrorEnum.mjs b/feature_tests/js/api/ErrorEnum.mjs index cedaf53d2..de3f78f44 100644 --- a/feature_tests/js/api/ErrorEnum.mjs +++ b/feature_tests/js/api/ErrorEnum.mjs @@ -2,8 +2,10 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -// Base enumerator definition -export class ErrorEnum { + + +export class ErrorEnum { + #value = undefined; static #values = new Map([ @@ -14,14 +16,14 @@ export class ErrorEnum { static getAllEntries() { return ErrorEnum.#values.entries(); } - - constructor(value) { + + #internalConstructor(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 this; } return ErrorEnum.#objectValues[arguments[1]]; } @@ -33,13 +35,17 @@ export class ErrorEnum { let intVal = ErrorEnum.#values.get(value); // Nullish check, checks for null or undefined - if (intVal == null) { + if (intVal != null) { return ErrorEnum.#objectValues[intVal]; } throw TypeError(value + " is not a ErrorEnum and does not correspond to any of its enumerator values."); } + static fromValue(value) { + return new ErrorEnum(value); + } + get value() { return [...ErrorEnum.#values.keys()][this.#value]; } @@ -53,5 +59,9 @@ export class ErrorEnum { ]; static Foo = ErrorEnum.#objectValues[0]; - static Bar = ErrorEnum.#objectValues[1]; + static Bar = ErrorEnum.#objectValues[1]; + + constructor(value) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/ErrorStruct.d.ts b/feature_tests/js/api/ErrorStruct.d.ts index d7b99d1dc..79169f34d 100644 --- a/feature_tests/js/api/ErrorStruct.d.ts +++ b/feature_tests/js/api/ErrorStruct.d.ts @@ -6,12 +6,21 @@ type ErrorStruct_obj = { j: number; }; -export class ErrorStruct { - - get i() : number; + + +export class ErrorStruct { + + get i() : number; set i(value: number); - - get j() : number; + + get j() : number; set j(value: number); - constructor(structObj : ErrorStruct_obj); + + /** Create `ErrorStruct` from an object that contains all of `ErrorStruct`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : ErrorStruct_obj) : ErrorStruct; + + + constructor(structObj : ErrorStruct_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/ErrorStruct.mjs b/feature_tests/js/api/ErrorStruct.mjs index d4b05fdf7..ec8aa6333 100644 --- a/feature_tests/js/api/ErrorStruct.mjs +++ b/feature_tests/js/api/ErrorStruct.mjs @@ -2,24 +2,36 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class ErrorStruct { - + + +export class ErrorStruct { + #i; + get i() { return this.#i; - } + } set i(value) { this.#i = value; } - + #j; + get j() { return this.#j; - } + } set j(value) { this.#j = value; } - constructor(structObj) { + + /** Create `ErrorStruct` from an object that contains all of `ErrorStruct`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new ErrorStruct(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("ErrorStruct's constructor takes an object of ErrorStruct's fields."); } @@ -36,6 +48,7 @@ export class ErrorStruct { throw new Error("Missing required field j."); } + return this; } // Return this struct in FFI function friendly format. @@ -57,7 +70,7 @@ export class ErrorStruct { return obj; } - return new ErrorStruct(obj); + return ErrorStruct.fromFields(obj); } _writeToArrayBuffer( @@ -79,12 +92,16 @@ export class ErrorStruct { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("ErrorStruct._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const iDeref = (new Int32Array(wasm.memory.buffer, ptr, 1))[0]; structObj.i = iDeref; const jDeref = (new Int32Array(wasm.memory.buffer, ptr + 4, 1))[0]; structObj.j = jDeref; - return new ErrorStruct(structObj, internalConstructor); - } + return new ErrorStruct(structObj); + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/Float64Vec.d.ts b/feature_tests/js/api/Float64Vec.d.ts index 714cb07f5..29e90209f 100644 --- a/feature_tests/js/api/Float64Vec.d.ts +++ b/feature_tests/js/api/Float64Vec.d.ts @@ -1,34 +1,35 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class Float64Vec { + + +export class Float64Vec { - - get ffiValue(): pointer; - - static newBool(v: Array): Float64Vec; - - static newI16(v: Array): Float64Vec; - - static newU16(v: Array): Float64Vec; - - static newIsize(v: Array): Float64Vec; - - static newUsize(v: Array): Float64Vec; - - static newF64BeBytes(v: Uint8Array): Float64Vec; - - static newFromOwned(v: Array): Float64Vec; - - get asSlice(): Array; - - fillSlice(v: Array): void; - - setValue(newSlice: Array): void; - - toString(): string; - - borrow(): Array; - - get(i: number): number | null; + get ffiValue(): pointer; + + static newBool(v: Array): Float64Vec; + + static newI16(v: Array): Float64Vec; + + static newU16(v: Array): Float64Vec; + + static newIsize(v: Array): Float64Vec; + + static newUsize(v: Array): Float64Vec; + + static newF64BeBytes(v: Uint8Array): Float64Vec; + + get asSlice(): Array; + + fillSlice(v: Array): void; + + setValue(newSlice: Array): void; + + toString(): string; + + borrow(): Array; + + get(i: number): number | null; + + constructor(v: Array); } \ No newline at end of file diff --git a/feature_tests/js/api/Float64Vec.mjs b/feature_tests/js/api/Float64Vec.mjs index bac5ff7e5..203275b4f 100644 --- a/feature_tests/js/api/Float64Vec.mjs +++ b/feature_tests/js/api/Float64Vec.mjs @@ -4,9 +4,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const Float64Vec_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.Float64Vec_destroy(ptr); -}); - -export class Float64Vec { +}); + +export class Float64Vec { + // Internal ptr reference: #ptr = null; @@ -14,7 +15,7 @@ export class Float64Vec { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("Float64Vec is an Opaque type. You cannot call its constructor."); return; @@ -27,12 +28,13 @@ export class Float64Vec { if (this.#selfEdge.length === 0) { Float64Vec_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static newBool(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -47,8 +49,8 @@ export class Float64Vec { finally { functionCleanupArena.free(); } - } - + } + static newI16(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -63,8 +65,8 @@ export class Float64Vec { finally { functionCleanupArena.free(); } - } - + } + static newU16(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -79,8 +81,8 @@ export class Float64Vec { finally { functionCleanupArena.free(); } - } - + } + static newIsize(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -95,8 +97,8 @@ export class Float64Vec { finally { functionCleanupArena.free(); } - } - + } + static newUsize(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -111,8 +113,8 @@ export class Float64Vec { finally { functionCleanupArena.free(); } - } - + } + static newF64BeBytes(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -127,9 +129,9 @@ export class Float64Vec { finally { functionCleanupArena.free(); } - } - - static newFromOwned(v) { + } + + #defaultConstructor(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); const vSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.slice(wasm, v, "f64")); @@ -143,8 +145,8 @@ export class Float64Vec { finally { functionCleanupArena.free(); } - } - + } + get asSlice() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 8, 4, false); @@ -160,8 +162,8 @@ export class Float64Vec { finally { diplomatReceive.free(); } - } - + } + fillSlice(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -173,8 +175,8 @@ export class Float64Vec { finally { functionCleanupArena.free(); } - } - + } + setValue(newSlice) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -186,8 +188,8 @@ export class Float64Vec { finally { functionCleanupArena.free(); } - } - + } + toString() { const write = new diplomatRuntime.DiplomatWriteBuf(wasm); wasm.Float64Vec_to_string(this.ffiValue, write.buffer); @@ -199,8 +201,8 @@ export class Float64Vec { finally { write.free(); } - } - + } + borrow() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 8, 4, false); @@ -216,8 +218,8 @@ export class Float64Vec { finally { diplomatReceive.free(); } - } - + } + get(i) { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 9, 8, true); @@ -233,5 +235,15 @@ export class Float64Vec { finally { diplomatReceive.free(); } - } + } + + constructor(v) { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/feature_tests/js/api/Foo.d.ts b/feature_tests/js/api/Foo.d.ts index a4f65e6bc..6db0ce682 100644 --- a/feature_tests/js/api/Foo.d.ts +++ b/feature_tests/js/api/Foo.d.ts @@ -7,18 +7,19 @@ import type { BorrowedFieldsWithBounds_obj } from "./BorrowedFieldsWithBounds" import type { BorrowedFields_obj } from "./BorrowedFields" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class Foo { + + +export class Foo { - - get ffiValue(): pointer; - - static new_(x: string): Foo; - - get bar(): Bar; - - asReturning(): BorrowedFieldsReturning; - - static extractFromFields(fields: BorrowedFields_obj): Foo; - - static extractFromBounds(bounds: BorrowedFieldsWithBounds_obj, anotherString: string): Foo; + get ffiValue(): pointer; + + get bar(): Bar; + + asReturning(): BorrowedFieldsReturning; + + static extractFromFields(fields: BorrowedFields_obj): Foo; + + static extractFromBounds(bounds: BorrowedFieldsWithBounds_obj, anotherString: string): Foo; + + constructor(x: string); } \ No newline at end of file diff --git a/feature_tests/js/api/Foo.mjs b/feature_tests/js/api/Foo.mjs index 06572b431..f102c967c 100644 --- a/feature_tests/js/api/Foo.mjs +++ b/feature_tests/js/api/Foo.mjs @@ -8,9 +8,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const Foo_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.Foo_destroy(ptr); -}); - -export class Foo { +}); + +export class Foo { + // Internal ptr reference: #ptr = null; @@ -19,7 +20,7 @@ export class Foo { #selfEdge = []; #aEdge = []; - constructor(symbol, ptr, selfEdge, aEdge) { + #internalConstructor(symbol, ptr, selfEdge, aEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("Foo is an Opaque type. You cannot call its constructor."); return; @@ -35,13 +36,14 @@ export class Foo { if (this.#selfEdge.length === 0) { Foo_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - - static new_(x) { + } + + #defaultConstructor(x) { let functionGarbageCollectorGrip = new diplomatRuntime.GarbageCollectorGrip(); const xSlice = functionGarbageCollectorGrip.alloc(diplomatRuntime.DiplomatBuf.str8(wasm, x)); @@ -57,8 +59,8 @@ export class Foo { finally { functionGarbageCollectorGrip.releaseToGarbageCollector(); } - } - + } + get bar() { // This lifetime edge depends on lifetimes 'a let aEdges = [this]; @@ -73,8 +75,8 @@ export class Foo { } finally {} - } - + } + asReturning() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 8, 4, false); @@ -90,8 +92,8 @@ export class Foo { finally { diplomatReceive.free(); } - } - + } + static extractFromFields(fields) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -107,8 +109,8 @@ export class Foo { finally { functionCleanupArena.free(); } - } - + } + static extractFromBounds(bounds, anotherString) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -129,5 +131,15 @@ export class Foo { functionGarbageCollectorGrip.releaseToGarbageCollector(); } - } + } + + constructor(x) { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/feature_tests/js/api/ImportedStruct.d.ts b/feature_tests/js/api/ImportedStruct.d.ts index 8e9d1bceb..6d24956d9 100644 --- a/feature_tests/js/api/ImportedStruct.d.ts +++ b/feature_tests/js/api/ImportedStruct.d.ts @@ -7,12 +7,21 @@ type ImportedStruct_obj = { count: number; }; -export class ImportedStruct { - - get foo() : UnimportedEnum; + + +export class ImportedStruct { + + get foo() : UnimportedEnum; set foo(value: UnimportedEnum); - - get count() : number; + + get count() : number; set count(value: number); - constructor(structObj : ImportedStruct_obj); + + /** Create `ImportedStruct` from an object that contains all of `ImportedStruct`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : ImportedStruct_obj) : ImportedStruct; + + + constructor(structObj : ImportedStruct_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/ImportedStruct.mjs b/feature_tests/js/api/ImportedStruct.mjs index 1e1f535b7..0b86eeb22 100644 --- a/feature_tests/js/api/ImportedStruct.mjs +++ b/feature_tests/js/api/ImportedStruct.mjs @@ -3,24 +3,36 @@ import { UnimportedEnum } from "./UnimportedEnum.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class ImportedStruct { - + + +export class ImportedStruct { + #foo; + get foo() { return this.#foo; - } + } set foo(value) { this.#foo = value; } - + #count; + get count() { return this.#count; - } + } set count(value) { this.#count = value; } - constructor(structObj) { + + /** Create `ImportedStruct` from an object that contains all of `ImportedStruct`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new ImportedStruct(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("ImportedStruct's constructor takes an object of ImportedStruct's fields."); } @@ -37,6 +49,7 @@ export class ImportedStruct { throw new Error("Missing required field count."); } + return this; } // Return this struct in FFI function friendly format. @@ -62,7 +75,7 @@ export class ImportedStruct { return obj; } - return new ImportedStruct(obj); + return ImportedStruct.fromFields(obj); } _writeToArrayBuffer( @@ -85,12 +98,16 @@ export class ImportedStruct { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("ImportedStruct._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const fooDeref = diplomatRuntime.enumDiscriminant(wasm, ptr); structObj.foo = new UnimportedEnum(diplomatRuntime.internalConstructor, fooDeref); const countDeref = (new Uint8Array(wasm.memory.buffer, ptr + 4, 1))[0]; structObj.count = countDeref; - return new ImportedStruct(structObj, internalConstructor); - } + return new ImportedStruct(structObj); + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/MyEnum.d.ts b/feature_tests/js/api/MyEnum.d.ts index ace176e87..1566f177f 100644 --- a/feature_tests/js/api/MyEnum.d.ts +++ b/feature_tests/js/api/MyEnum.d.ts @@ -1,9 +1,12 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -// Base enumerator definition -export class MyEnum { - constructor(value : MyEnum | string); + + +export class MyEnum { + + + static fromValue(value : MyEnum | string) : MyEnum; get value() : string; @@ -14,9 +17,11 @@ export class MyEnum { static C : MyEnum; static D : MyEnum; static E : MyEnum; - static F : MyEnum; - - intoValue(): number; - - static getA(): MyEnum; + static F : MyEnum; + + intoValue(): number; + + static getA(): MyEnum; + + constructor(value: MyEnum | string ); } \ No newline at end of file diff --git a/feature_tests/js/api/MyEnum.mjs b/feature_tests/js/api/MyEnum.mjs index 788f7a045..ed674ed55 100644 --- a/feature_tests/js/api/MyEnum.mjs +++ b/feature_tests/js/api/MyEnum.mjs @@ -2,8 +2,10 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -// Base enumerator definition -export class MyEnum { + + +export class MyEnum { + #value = undefined; static #values = new Map([ @@ -18,14 +20,14 @@ export class MyEnum { static getAllEntries() { return MyEnum.#values.entries(); } - - constructor(value) { + + #internalConstructor(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 this; } return MyEnum.#objectValues[arguments[1]]; } @@ -37,13 +39,17 @@ export class MyEnum { let intVal = MyEnum.#values.get(value); // Nullish check, checks for null or undefined - if (intVal == null) { + if (intVal != null) { return MyEnum.#objectValues[intVal]; } throw TypeError(value + " is not a MyEnum and does not correspond to any of its enumerator values."); } + static fromValue(value) { + return new MyEnum(value); + } + get value() { for (let entry of MyEnum.#values) { if (entry[1] == this.#value) { @@ -69,8 +75,8 @@ export class MyEnum { static C = MyEnum.#objectValues[0]; static D = MyEnum.#objectValues[1]; static E = MyEnum.#objectValues[2]; - static F = MyEnum.#objectValues[3]; - + static F = MyEnum.#objectValues[3]; + intoValue() { const result = wasm.MyEnum_into_value(this.ffiValue); @@ -79,8 +85,8 @@ export class MyEnum { } finally {} - } - + } + static getA() { const result = wasm.MyEnum_get_a(); @@ -89,5 +95,9 @@ export class MyEnum { } finally {} - } + } + + constructor(value) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/MyOpaqueEnum.d.ts b/feature_tests/js/api/MyOpaqueEnum.d.ts index 43d7dd7e9..f462bd143 100644 --- a/feature_tests/js/api/MyOpaqueEnum.d.ts +++ b/feature_tests/js/api/MyOpaqueEnum.d.ts @@ -1,12 +1,13 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class MyOpaqueEnum { + + +export class MyOpaqueEnum { - - get ffiValue(): pointer; - - static new_(): MyOpaqueEnum; - - toString(): string; + get ffiValue(): pointer; + + static new_(): MyOpaqueEnum; + + toString(): string; } \ No newline at end of file diff --git a/feature_tests/js/api/MyOpaqueEnum.mjs b/feature_tests/js/api/MyOpaqueEnum.mjs index ca9ebbc9a..f0c65e94a 100644 --- a/feature_tests/js/api/MyOpaqueEnum.mjs +++ b/feature_tests/js/api/MyOpaqueEnum.mjs @@ -4,9 +4,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const MyOpaqueEnum_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.MyOpaqueEnum_destroy(ptr); -}); - -export class MyOpaqueEnum { +}); + +export class MyOpaqueEnum { + // Internal ptr reference: #ptr = null; @@ -14,7 +15,7 @@ export class MyOpaqueEnum { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("MyOpaqueEnum is an Opaque type. You cannot call its constructor."); return; @@ -27,12 +28,13 @@ export class MyOpaqueEnum { if (this.#selfEdge.length === 0) { MyOpaqueEnum_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static new_() { const result = wasm.MyOpaqueEnum_new(); @@ -41,8 +43,8 @@ export class MyOpaqueEnum { } finally {} - } - + } + toString() { const write = new diplomatRuntime.DiplomatWriteBuf(wasm); wasm.MyOpaqueEnum_to_string(this.ffiValue, write.buffer); @@ -54,5 +56,9 @@ export class MyOpaqueEnum { finally { write.free(); } - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/MyString.d.ts b/feature_tests/js/api/MyString.d.ts index e2d9609fb..221cf17b7 100644 --- a/feature_tests/js/api/MyString.d.ts +++ b/feature_tests/js/api/MyString.d.ts @@ -1,24 +1,25 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class MyString { + + +export class MyString { - - get ffiValue(): pointer; - - static new_(v: string): MyString; - - static newUnsafe(v: string): MyString; - - static newOwned(v: string): MyString; - - static newFromFirst(v: Array): MyString; - - set str(newStr: string); - - get str(): string; - - static stringTransform(foo: string): string; - - borrow(): string; + get ffiValue(): pointer; + + static newUnsafe(v: string): MyString; + + static newOwned(v: string): MyString; + + static newFromFirst(v: Array): MyString; + + set str(newStr: string); + + get str(): string; + + static stringTransform(foo: string): string; + + borrow(): string; + + constructor(v: string); } \ No newline at end of file diff --git a/feature_tests/js/api/MyString.mjs b/feature_tests/js/api/MyString.mjs index ea01b1c64..0b547e634 100644 --- a/feature_tests/js/api/MyString.mjs +++ b/feature_tests/js/api/MyString.mjs @@ -4,9 +4,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const MyString_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.MyString_destroy(ptr); -}); - -export class MyString { +}); + +export class MyString { + // Internal ptr reference: #ptr = null; @@ -14,7 +15,7 @@ export class MyString { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("MyString is an Opaque type. You cannot call its constructor."); return; @@ -27,13 +28,14 @@ export class MyString { if (this.#selfEdge.length === 0) { MyString_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - - static new_(v) { + } + + #defaultConstructor(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); const vSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.str8(wasm, v)); @@ -47,8 +49,8 @@ export class MyString { finally { functionCleanupArena.free(); } - } - + } + static newUnsafe(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -63,8 +65,8 @@ export class MyString { finally { functionCleanupArena.free(); } - } - + } + static newOwned(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -79,8 +81,8 @@ export class MyString { finally { functionCleanupArena.free(); } - } - + } + static newFromFirst(v) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -95,8 +97,8 @@ export class MyString { finally { functionCleanupArena.free(); } - } - + } + set str(newStr) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -108,8 +110,8 @@ export class MyString { finally { functionCleanupArena.free(); } - } - + } + get str() { const write = new diplomatRuntime.DiplomatWriteBuf(wasm); wasm.MyString_get_str(this.ffiValue, write.buffer); @@ -121,8 +123,8 @@ export class MyString { finally { write.free(); } - } - + } + static stringTransform(foo) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -140,8 +142,8 @@ export class MyString { write.free(); } - } - + } + borrow() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 8, 4, false); @@ -157,5 +159,15 @@ export class MyString { finally { diplomatReceive.free(); } - } + } + + constructor(v) { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/feature_tests/js/api/MyStruct.d.ts b/feature_tests/js/api/MyStruct.d.ts index 2f094a099..f53f35835 100644 --- a/feature_tests/js/api/MyStruct.d.ts +++ b/feature_tests/js/api/MyStruct.d.ts @@ -13,35 +13,42 @@ type MyStruct_obj = { g: MyEnum; }; -export class MyStruct { - - get a() : number; + + +export class MyStruct { + + get a() : number; set a(value: number); - - get b() : boolean; + + get b() : boolean; set b(value: boolean); - - get c() : number; + + get c() : number; set c(value: number); - - get d() : bigint; + + get d() : bigint; set d(value: bigint); - - get e() : number; + + get e() : number; set e(value: number); - - get f() : codepoint; + + get f() : codepoint; set f(value: codepoint); - - get g() : MyEnum; + + get g() : MyEnum; set g(value: MyEnum); - constructor(structObj : MyStruct_obj); - - static new_(): MyStruct; - - intoA(): number; - - static returnsZstResult(): void; - - static failsZstResult(): void; + + /** Create `MyStruct` from an object that contains all of `MyStruct`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : MyStruct_obj) : MyStruct; + + + intoA(): number; + + static returnsZstResult(): void; + + static failsZstResult(): void; + + constructor(); } \ No newline at end of file diff --git a/feature_tests/js/api/MyStruct.mjs b/feature_tests/js/api/MyStruct.mjs index 9c2d2daa4..1b087f277 100644 --- a/feature_tests/js/api/MyStruct.mjs +++ b/feature_tests/js/api/MyStruct.mjs @@ -4,64 +4,81 @@ import { MyZst } from "./MyZst.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class MyStruct { - + + +export class MyStruct { + #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; } - + #d; + get d() { return this.#d; - } + } set d(value) { this.#d = value; } - + #e; + get e() { return this.#e; - } + } set e(value) { this.#e = value; } - + #f; + get f() { return this.#f; - } + } set f(value) { this.#f = value; } - + #g; + get g() { return this.#g; - } + } set g(value) { this.#g = value; } - constructor(structObj) { + + /** Create `MyStruct` from an object that contains all of `MyStruct`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new MyStruct(diplomatRuntime.exposeConstructor, structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("MyStruct's constructor takes an object of MyStruct's fields."); } @@ -108,6 +125,7 @@ export class MyStruct { throw new Error("Missing required field g."); } + return this; } // Return this struct in FFI function friendly format. @@ -129,7 +147,7 @@ export class MyStruct { return obj; } - return new MyStruct(obj); + return MyStruct.fromFields(obj); } _writeToArrayBuffer( @@ -156,7 +174,7 @@ export class MyStruct { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("MyStruct._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const aDeref = (new Uint8Array(wasm.memory.buffer, ptr, 1))[0]; structObj.a = aDeref; const bDeref = (new Uint8Array(wasm.memory.buffer, ptr + 1, 1))[0] === 1; @@ -172,10 +190,10 @@ export class MyStruct { const gDeref = diplomatRuntime.enumDiscriminant(wasm, ptr + 24); structObj.g = new MyEnum(diplomatRuntime.internalConstructor, gDeref); - return new MyStruct(structObj, internalConstructor); - } - - static new_() { + return new MyStruct(diplomatRuntime.exposeConstructor, structObj); + } + + #defaultConstructor() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 32, 8, false); const result = wasm.MyStruct_new(diplomatReceive.buffer); @@ -187,8 +205,8 @@ export class MyStruct { finally { diplomatReceive.free(); } - } - + } + intoA() { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -201,33 +219,43 @@ export class MyStruct { finally { functionCleanupArena.free(); } - } - + } + static returnsZstResult() { const result = wasm.MyStruct_returns_zst_result(); try { if (result !== 1) { - const cause = new MyZst({}, diplomatRuntime.internalConstructor); + const cause = MyZst.fromFields({}, diplomatRuntime.internalConstructor); throw new globalThis.Error('MyZst', { cause }); } } finally {} - } - + } + static failsZstResult() { const result = wasm.MyStruct_fails_zst_result(); try { if (result !== 1) { - const cause = new MyZst({}, diplomatRuntime.internalConstructor); + const cause = MyZst.fromFields({}, diplomatRuntime.internalConstructor); throw new globalThis.Error('MyZst', { cause }); } } finally {} - } + } + + constructor() { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/feature_tests/js/api/MyZst.d.ts b/feature_tests/js/api/MyZst.d.ts index 83ac3785c..058d1250b 100644 --- a/feature_tests/js/api/MyZst.d.ts +++ b/feature_tests/js/api/MyZst.d.ts @@ -4,6 +4,15 @@ import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; type MyZst_obj = { }; -export class MyZst { - constructor(structObj : MyZst_obj); + + +export class MyZst { + + /** Create `MyZst` from an object that contains all of `MyZst`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : MyZst_obj) : MyZst; + + + constructor(structObj : MyZst_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/MyZst.mjs b/feature_tests/js/api/MyZst.mjs index 6caca21a0..06d1b8dd0 100644 --- a/feature_tests/js/api/MyZst.mjs +++ b/feature_tests/js/api/MyZst.mjs @@ -2,12 +2,27 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class MyZst { - constructor(structObj) { + + +export class MyZst { + + /** Create `MyZst` from an object that contains all of `MyZst`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new MyZst(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("MyZst's constructor takes an object of MyZst's fields."); } + return this; } - + + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/NestedBorrowedFields.d.ts b/feature_tests/js/api/NestedBorrowedFields.d.ts index 9e49766f9..b19f1b032 100644 --- a/feature_tests/js/api/NestedBorrowedFields.d.ts +++ b/feature_tests/js/api/NestedBorrowedFields.d.ts @@ -13,17 +13,26 @@ type NestedBorrowedFields_obj = { bounds2: BorrowedFieldsWithBounds_obj; }; -export class NestedBorrowedFields { - - get fields() : BorrowedFields; + + +export class NestedBorrowedFields { + + get fields() : BorrowedFields; set fields(value: BorrowedFields); - - get bounds() : BorrowedFieldsWithBounds; + + get bounds() : BorrowedFieldsWithBounds; set bounds(value: BorrowedFieldsWithBounds); - - get bounds2() : BorrowedFieldsWithBounds; + + get bounds2() : BorrowedFieldsWithBounds; set bounds2(value: BorrowedFieldsWithBounds); - constructor(structObj : NestedBorrowedFields_obj); - - static fromBarAndFooAndStrings(bar: Bar, foo: Foo, dstr16X: string, dstr16Z: string, utf8StrY: string, utf8StrZ: string): NestedBorrowedFields; + + /** Create `NestedBorrowedFields` from an object that contains all of `NestedBorrowedFields`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : NestedBorrowedFields_obj) : NestedBorrowedFields; + + + static fromBarAndFooAndStrings(bar: Bar, foo: Foo, dstr16X: string, dstr16Z: string, utf8StrY: string, utf8StrZ: string): NestedBorrowedFields; + + constructor(structObj : NestedBorrowedFields_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/NestedBorrowedFields.mjs b/feature_tests/js/api/NestedBorrowedFields.mjs index 2f225fabc..f52500a10 100644 --- a/feature_tests/js/api/NestedBorrowedFields.mjs +++ b/feature_tests/js/api/NestedBorrowedFields.mjs @@ -6,32 +6,45 @@ import { Foo } from "./Foo.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class NestedBorrowedFields { - + + +export class NestedBorrowedFields { + #fields; + get fields() { return this.#fields; - } + } set fields(value) { this.#fields = value; } - + #bounds; + get bounds() { return this.#bounds; - } + } set bounds(value) { this.#bounds = value; } - + #bounds2; + get bounds2() { return this.#bounds2; - } + } set bounds2(value) { this.#bounds2 = value; } - constructor(structObj) { + + /** Create `NestedBorrowedFields` from an object that contains all of `NestedBorrowedFields`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new NestedBorrowedFields(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("NestedBorrowedFields's constructor takes an object of NestedBorrowedFields's fields."); } @@ -54,6 +67,7 @@ export class NestedBorrowedFields { throw new Error("Missing required field bounds2."); } + return this; } // Return this struct in FFI function friendly format. @@ -80,7 +94,7 @@ export class NestedBorrowedFields { return obj; } - return new NestedBorrowedFields(obj); + return NestedBorrowedFields.fromFields(obj); } _writeToArrayBuffer( @@ -98,7 +112,7 @@ export class NestedBorrowedFields { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("NestedBorrowedFields._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const fieldsDeref = ptr; structObj.fields = BorrowedFields._fromFFI(diplomatRuntime.internalConstructor, fieldsDeref, xEdges); const boundsDeref = ptr + 24; @@ -106,7 +120,7 @@ export class NestedBorrowedFields { const bounds2Deref = ptr + 48; structObj.bounds2 = BorrowedFieldsWithBounds._fromFFI(diplomatRuntime.internalConstructor, bounds2Deref, zEdges, zEdges, zEdges); - return new NestedBorrowedFields(structObj, internalConstructor); + return new NestedBorrowedFields(structObj); } // Return all fields corresponding to lifetime `'x` @@ -134,8 +148,8 @@ export class NestedBorrowedFields { // the caller should take care to also call _fieldsForLifetimeOther get _fieldsForLifetimeZ() { return [...bounds2._fieldsForLifetimeA, ...bounds2._fieldsForLifetimeB, ...bounds2._fieldsForLifetimeC]; - }; - + }; + static fromBarAndFooAndStrings(bar, foo, dstr16X, dstr16Z, utf8StrY, utf8StrZ) { let functionGarbageCollectorGrip = new diplomatRuntime.GarbageCollectorGrip(); const dstr16XSlice = functionGarbageCollectorGrip.alloc(diplomatRuntime.DiplomatBuf.str16(wasm, dstr16X)); @@ -168,5 +182,9 @@ export class NestedBorrowedFields { diplomatReceive.free(); } - } + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/One.d.ts b/feature_tests/js/api/One.d.ts index 4b3823995..271f8538c 100644 --- a/feature_tests/js/api/One.d.ts +++ b/feature_tests/js/api/One.d.ts @@ -2,30 +2,31 @@ import type { Two } from "./Two" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class One { + + +export class One { - - get ffiValue(): pointer; - - static transitivity(hold: One, nohold: One): One; - - static cycle(hold: Two, nohold: One): One; - - static manyDependents(a: One, b: One, c: Two, d: Two, nohold: Two): One; - - static returnOutlivesParam(hold: Two, nohold: One): One; - - static diamondTop(top: One, left: One, right: One, bottom: One): One; - - static diamondLeft(top: One, left: One, right: One, bottom: One): One; - - static diamondRight(top: One, left: One, right: One, bottom: One): One; - - static diamondBottom(top: One, left: One, right: One, bottom: One): One; - - static diamondAndNestedTypes(a: One, b: One, c: One, d: One, nohold: One): One; - - static implicitBounds(explicitHold: One, implicitHold: One, nohold: One): One; - - static implicitBoundsDeep(explicit: One, implicit1: One, implicit2: One, nohold: One): One; + get ffiValue(): pointer; + + static transitivity(hold: One, nohold: One): One; + + static cycle(hold: Two, nohold: One): One; + + static manyDependents(a: One, b: One, c: Two, d: Two, nohold: Two): One; + + static returnOutlivesParam(hold: Two, nohold: One): One; + + static diamondTop(top: One, left: One, right: One, bottom: One): One; + + static diamondLeft(top: One, left: One, right: One, bottom: One): One; + + static diamondRight(top: One, left: One, right: One, bottom: One): One; + + static diamondBottom(top: One, left: One, right: One, bottom: One): One; + + static diamondAndNestedTypes(a: One, b: One, c: One, d: One, nohold: One): One; + + static implicitBounds(explicitHold: One, implicitHold: One, nohold: One): One; + + static implicitBoundsDeep(explicit: One, implicit1: One, implicit2: One, nohold: One): One; } \ No newline at end of file diff --git a/feature_tests/js/api/One.mjs b/feature_tests/js/api/One.mjs index 322273be4..ad09ffc1d 100644 --- a/feature_tests/js/api/One.mjs +++ b/feature_tests/js/api/One.mjs @@ -5,9 +5,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const One_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.One_destroy(ptr); -}); - -export class One { +}); + +export class One { + // Internal ptr reference: #ptr = null; @@ -16,7 +17,7 @@ export class One { #selfEdge = []; #aEdge = []; - constructor(symbol, ptr, selfEdge, aEdge) { + #internalConstructor(symbol, ptr, selfEdge, aEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("One is an Opaque type. You cannot call its constructor."); return; @@ -32,12 +33,13 @@ export class One { if (this.#selfEdge.length === 0) { One_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static transitivity(hold, nohold) { // This lifetime edge depends on lifetimes 'a, 'b, 'c, 'd, 'e let aEdges = [hold]; @@ -49,8 +51,8 @@ export class One { } finally {} - } - + } + static cycle(hold, nohold) { // This lifetime edge depends on lifetimes 'a, 'b, 'c let aEdges = [hold]; @@ -62,8 +64,8 @@ export class One { } finally {} - } - + } + static manyDependents(a, b, c, d, nohold) { // This lifetime edge depends on lifetimes 'a, 'b, 'c, 'd let aEdges = [a, b, c, d]; @@ -75,8 +77,8 @@ export class One { } finally {} - } - + } + static returnOutlivesParam(hold, nohold) { // This lifetime edge depends on lifetimes 'long let longEdges = [hold]; @@ -88,8 +90,8 @@ export class One { } finally {} - } - + } + static diamondTop(top, left, right, bottom) { // This lifetime edge depends on lifetimes 'top, 'left, 'right, 'bottom let topEdges = [top, left, right, bottom]; @@ -101,8 +103,8 @@ export class One { } finally {} - } - + } + static diamondLeft(top, left, right, bottom) { // This lifetime edge depends on lifetimes 'left, 'bottom let leftEdges = [left, bottom]; @@ -114,8 +116,8 @@ export class One { } finally {} - } - + } + static diamondRight(top, left, right, bottom) { // This lifetime edge depends on lifetimes 'right, 'bottom let rightEdges = [right, bottom]; @@ -127,8 +129,8 @@ export class One { } finally {} - } - + } + static diamondBottom(top, left, right, bottom) { // This lifetime edge depends on lifetimes 'bottom let bottomEdges = [bottom]; @@ -140,8 +142,8 @@ export class One { } finally {} - } - + } + static diamondAndNestedTypes(a, b, c, d, nohold) { // This lifetime edge depends on lifetimes 'a, 'b, 'c, 'd let aEdges = [a, b, c, d]; @@ -153,8 +155,8 @@ export class One { } finally {} - } - + } + static implicitBounds(explicitHold, implicitHold, nohold) { // This lifetime edge depends on lifetimes 'a, 'b, 'c, 'd, 'x let aEdges = [explicitHold, implicitHold]; @@ -166,8 +168,8 @@ export class One { } finally {} - } - + } + static implicitBoundsDeep(explicit, implicit1, implicit2, nohold) { // This lifetime edge depends on lifetimes 'a, 'b, 'c, 'd let aEdges = [explicit, implicit1, implicit2]; @@ -179,5 +181,9 @@ export class One { } finally {} - } + } + + constructor(symbol, ptr, selfEdge, aEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/Opaque.d.ts b/feature_tests/js/api/Opaque.d.ts index f9bcc0b7e..65f6a288e 100644 --- a/feature_tests/js/api/Opaque.d.ts +++ b/feature_tests/js/api/Opaque.d.ts @@ -4,24 +4,25 @@ import type { MyStruct } from "./MyStruct" import type { MyStruct_obj } from "./MyStruct" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class Opaque { + + +export class Opaque { - - get ffiValue(): pointer; - - static new_(): Opaque; - - static tryFromUtf8(input: string): Opaque | null; - - static fromStr(input: string): Opaque; - - getDebugStr(): string; - - assertStruct(s: MyStruct_obj): void; - - static returnsUsize(): number; - - static returnsImported(): ImportedStruct; - - static cmp(): number; + get ffiValue(): pointer; + + static tryFromUtf8(input: string): Opaque | null; + + static fromStr(input: string): Opaque; + + getDebugStr(): string; + + assertStruct(s: MyStruct_obj): void; + + static returnsUsize(): number; + + static returnsImported(): ImportedStruct; + + static cmp(): number; + + constructor(); } \ No newline at end of file diff --git a/feature_tests/js/api/Opaque.mjs b/feature_tests/js/api/Opaque.mjs index 6518a3a91..8024206bf 100644 --- a/feature_tests/js/api/Opaque.mjs +++ b/feature_tests/js/api/Opaque.mjs @@ -6,9 +6,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const Opaque_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.Opaque_destroy(ptr); -}); - -export class Opaque { +}); + +export class Opaque { + // Internal ptr reference: #ptr = null; @@ -16,7 +17,7 @@ export class Opaque { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("Opaque is an Opaque type. You cannot call its constructor."); return; @@ -29,13 +30,14 @@ export class Opaque { if (this.#selfEdge.length === 0) { Opaque_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - - static new_() { + } + + #defaultConstructor() { const result = wasm.Opaque_new(); try { @@ -43,8 +45,8 @@ export class Opaque { } finally {} - } - + } + static tryFromUtf8(input) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -59,8 +61,8 @@ export class Opaque { finally { functionCleanupArena.free(); } - } - + } + static fromStr(input) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -75,8 +77,8 @@ export class Opaque { finally { functionCleanupArena.free(); } - } - + } + getDebugStr() { const write = new diplomatRuntime.DiplomatWriteBuf(wasm); wasm.Opaque_get_debug_str(this.ffiValue, write.buffer); @@ -88,8 +90,8 @@ export class Opaque { finally { write.free(); } - } - + } + assertStruct(s) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); wasm.Opaque_assert_struct(this.ffiValue, ...MyStruct._fromSuppliedValue(diplomatRuntime.internalConstructor, s)._intoFFI(functionCleanupArena, {})); @@ -99,8 +101,8 @@ export class Opaque { finally { functionCleanupArena.free(); } - } - + } + static returnsUsize() { const result = wasm.Opaque_returns_usize(); @@ -109,8 +111,8 @@ export class Opaque { } finally {} - } - + } + static returnsImported() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 8, 4, false); @@ -123,8 +125,8 @@ export class Opaque { finally { diplomatReceive.free(); } - } - + } + static cmp() { const result = wasm.Opaque_cmp(); @@ -133,5 +135,15 @@ export class Opaque { } finally {} - } + } + + constructor() { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/feature_tests/js/api/OpaqueMutexedString.d.ts b/feature_tests/js/api/OpaqueMutexedString.d.ts index d1989901c..97d593a1c 100644 --- a/feature_tests/js/api/OpaqueMutexedString.d.ts +++ b/feature_tests/js/api/OpaqueMutexedString.d.ts @@ -2,26 +2,27 @@ import type { Utf16Wrap } from "./Utf16Wrap" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class OpaqueMutexedString { + + +export class OpaqueMutexedString { - - get ffiValue(): pointer; - - static fromUsize(number: number): OpaqueMutexedString; - - change(number: number): void; - - borrow(): OpaqueMutexedString; - - static borrowOther(other: OpaqueMutexedString): OpaqueMutexedString; - - borrowSelfOrOther(other: OpaqueMutexedString): OpaqueMutexedString; - - getLenAndAdd(other: number): number; - - dummyStr(): string; - - wrapper(): Utf16Wrap; - - toUnsignedFromUnsigned(input: number): number; + get ffiValue(): pointer; + + static fromUsize(number: number): OpaqueMutexedString; + + change(number: number): void; + + borrow(): OpaqueMutexedString; + + static borrowOther(other: OpaqueMutexedString): OpaqueMutexedString; + + borrowSelfOrOther(other: OpaqueMutexedString): OpaqueMutexedString; + + getLenAndAdd(other: number): number; + + dummyStr(): string; + + wrapper(): Utf16Wrap; + + toUnsignedFromUnsigned(input: number): number; } \ No newline at end of file diff --git a/feature_tests/js/api/OpaqueMutexedString.mjs b/feature_tests/js/api/OpaqueMutexedString.mjs index 16a0ea5ec..d9f49401e 100644 --- a/feature_tests/js/api/OpaqueMutexedString.mjs +++ b/feature_tests/js/api/OpaqueMutexedString.mjs @@ -5,9 +5,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const OpaqueMutexedString_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.OpaqueMutexedString_destroy(ptr); -}); - -export class OpaqueMutexedString { +}); + +export class OpaqueMutexedString { + // Internal ptr reference: #ptr = null; @@ -15,7 +16,7 @@ export class OpaqueMutexedString { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("OpaqueMutexedString is an Opaque type. You cannot call its constructor."); return; @@ -28,12 +29,13 @@ export class OpaqueMutexedString { if (this.#selfEdge.length === 0) { OpaqueMutexedString_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static fromUsize(number) { const result = wasm.OpaqueMutexedString_from_usize(number); @@ -42,15 +44,15 @@ export class OpaqueMutexedString { } finally {} - } - + } + change(number) {wasm.OpaqueMutexedString_change(this.ffiValue, number); try {} finally {} - } - + } + borrow() { // This lifetime edge depends on lifetimes 'a let aEdges = [this]; @@ -62,8 +64,8 @@ export class OpaqueMutexedString { } finally {} - } - + } + static borrowOther(other) { // This lifetime edge depends on lifetimes 'a let aEdges = [other]; @@ -75,8 +77,8 @@ export class OpaqueMutexedString { } finally {} - } - + } + borrowSelfOrOther(other) { // This lifetime edge depends on lifetimes 'a let aEdges = [this, other]; @@ -88,8 +90,8 @@ export class OpaqueMutexedString { } finally {} - } - + } + getLenAndAdd(other) { const result = wasm.OpaqueMutexedString_get_len_and_add(this.ffiValue, other); @@ -98,8 +100,8 @@ export class OpaqueMutexedString { } finally {} - } - + } + dummyStr() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 8, 4, false); @@ -115,8 +117,8 @@ export class OpaqueMutexedString { finally { diplomatReceive.free(); } - } - + } + wrapper() { const result = wasm.OpaqueMutexedString_wrapper(this.ffiValue); @@ -125,8 +127,8 @@ export class OpaqueMutexedString { } finally {} - } - + } + toUnsignedFromUnsigned(input) { const result = wasm.OpaqueMutexedString_to_unsigned_from_unsigned(this.ffiValue, input); @@ -135,5 +137,9 @@ export class OpaqueMutexedString { } finally {} - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/OptionEnum.d.ts b/feature_tests/js/api/OptionEnum.d.ts index 9c653bb63..56048a898 100644 --- a/feature_tests/js/api/OptionEnum.d.ts +++ b/feature_tests/js/api/OptionEnum.d.ts @@ -1,14 +1,19 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -// Base enumerator definition -export class OptionEnum { - constructor(value : OptionEnum | string); + + +export class OptionEnum { + + + static fromValue(value : OptionEnum | string) : OptionEnum; get value() : string; get ffiValue() : number; static Foo : OptionEnum; - static Bar : OptionEnum; + static Bar : OptionEnum; + + constructor(value: OptionEnum | string ); } \ No newline at end of file diff --git a/feature_tests/js/api/OptionEnum.mjs b/feature_tests/js/api/OptionEnum.mjs index 57907e448..2bf479abb 100644 --- a/feature_tests/js/api/OptionEnum.mjs +++ b/feature_tests/js/api/OptionEnum.mjs @@ -2,8 +2,10 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -// Base enumerator definition -export class OptionEnum { + + +export class OptionEnum { + #value = undefined; static #values = new Map([ @@ -14,14 +16,14 @@ export class OptionEnum { static getAllEntries() { return OptionEnum.#values.entries(); } - - constructor(value) { + + #internalConstructor(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 this; } return OptionEnum.#objectValues[arguments[1]]; } @@ -33,13 +35,17 @@ export class OptionEnum { let intVal = OptionEnum.#values.get(value); // Nullish check, checks for null or undefined - if (intVal == null) { + if (intVal != null) { return OptionEnum.#objectValues[intVal]; } throw TypeError(value + " is not a OptionEnum and does not correspond to any of its enumerator values."); } + static fromValue(value) { + return new OptionEnum(value); + } + get value() { return [...OptionEnum.#values.keys()][this.#value]; } @@ -53,5 +59,9 @@ export class OptionEnum { ]; static Foo = OptionEnum.#objectValues[0]; - static Bar = OptionEnum.#objectValues[1]; + static Bar = OptionEnum.#objectValues[1]; + + constructor(value) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/OptionInputStruct.d.ts b/feature_tests/js/api/OptionInputStruct.d.ts index 1548ad8b2..7671d9d94 100644 --- a/feature_tests/js/api/OptionInputStruct.d.ts +++ b/feature_tests/js/api/OptionInputStruct.d.ts @@ -8,15 +8,24 @@ type OptionInputStruct_obj = { c?: OptionEnum | null; }; -export class OptionInputStruct { - - get a() : number | null; + + +export class OptionInputStruct { + + get a() : number | null; set a(value: number | null); - - get b() : codepoint | null; + + get b() : codepoint | null; set b(value: codepoint | null); - - get c() : OptionEnum | null; + + get c() : OptionEnum | null; set c(value: OptionEnum | null); - constructor(structObj : OptionInputStruct_obj); + + /** Create `OptionInputStruct` from an object that contains all of `OptionInputStruct`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : OptionInputStruct_obj) : OptionInputStruct; + + + constructor(structObj : OptionInputStruct_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/OptionInputStruct.mjs b/feature_tests/js/api/OptionInputStruct.mjs index 15012b579..5fb088136 100644 --- a/feature_tests/js/api/OptionInputStruct.mjs +++ b/feature_tests/js/api/OptionInputStruct.mjs @@ -3,32 +3,45 @@ import { OptionEnum } from "./OptionEnum.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class OptionInputStruct { - + + +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(structObj) { + + /** Create `OptionInputStruct` from an object that contains all of `OptionInputStruct`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new OptionInputStruct(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("OptionInputStruct's constructor takes an object of OptionInputStruct's fields."); } @@ -51,6 +64,7 @@ export class OptionInputStruct { this.#c = null; } + return this; } // Return this struct in FFI function friendly format. @@ -72,7 +86,7 @@ export class OptionInputStruct { return obj; } - return new OptionInputStruct(obj); + return OptionInputStruct.fromFields(obj); } _writeToArrayBuffer( @@ -95,7 +109,7 @@ export class OptionInputStruct { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("OptionInputStruct._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const aDeref = ptr; structObj.a = diplomatRuntime.readOption(wasm, aDeref, 1, (wasm, offset) => { const deref = (new Uint8Array(wasm.memory.buffer, offset, 1))[0]; return deref }); const bDeref = ptr + 4; @@ -103,6 +117,10 @@ export class OptionInputStruct { const cDeref = ptr + 12; structObj.c = diplomatRuntime.readOption(wasm, cDeref, 4, (wasm, offset) => { const deref = diplomatRuntime.enumDiscriminant(wasm, offset); return new OptionEnum(diplomatRuntime.internalConstructor, deref) }); - return new OptionInputStruct(structObj, internalConstructor); - } + return new OptionInputStruct(structObj); + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ 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 587d09ae1..daef25477 100644 --- a/feature_tests/js/api/OptionOpaque.d.ts +++ b/feature_tests/js/api/OptionOpaque.d.ts @@ -4,38 +4,39 @@ import type { OptionInputStruct } from "./OptionInputStruct" import type { OptionStruct } from "./OptionStruct" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class OptionOpaque { + + +export class OptionOpaque { - - get ffiValue(): pointer; - - static new_(i: number): OptionOpaque | null; - - static newNone(): OptionOpaque | null; - - static returns(): OptionStruct | null; - - optionIsize(): number | null; - - optionUsize(): number | null; - - optionI32(): number | null; - - optionU32(): number | null; - - static newStruct(): OptionStruct; - - static newStructNones(): OptionStruct; - - 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; + get ffiValue(): pointer; + + static new_(i: number): OptionOpaque | null; + + static newNone(): OptionOpaque | null; + + static returns(): OptionStruct | null; + + optionIsize(): number | null; + + optionUsize(): number | null; + + optionI32(): number | null; + + optionU32(): number | null; + + static newStruct(): OptionStruct; + + static newStructNones(): OptionStruct; + + 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 2c24e05cb..9d733cdd0 100644 --- a/feature_tests/js/api/OptionOpaque.mjs +++ b/feature_tests/js/api/OptionOpaque.mjs @@ -7,9 +7,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const OptionOpaque_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.OptionOpaque_destroy(ptr); -}); - -export class OptionOpaque { +}); + +export class OptionOpaque { + // Internal ptr reference: #ptr = null; @@ -17,7 +18,7 @@ export class OptionOpaque { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("OptionOpaque is an Opaque type. You cannot call its constructor."); return; @@ -30,12 +31,13 @@ export class OptionOpaque { if (this.#selfEdge.length === 0) { OptionOpaque_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static new_(i) { const result = wasm.OptionOpaque_new(i); @@ -44,8 +46,8 @@ export class OptionOpaque { } finally {} - } - + } + static newNone() { const result = wasm.OptionOpaque_new_none(); @@ -54,8 +56,8 @@ export class OptionOpaque { } finally {} - } - + } + static returns() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 17, 4, true); @@ -71,8 +73,8 @@ export class OptionOpaque { finally { diplomatReceive.free(); } - } - + } + optionIsize() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -88,8 +90,8 @@ export class OptionOpaque { finally { diplomatReceive.free(); } - } - + } + optionUsize() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -105,8 +107,8 @@ export class OptionOpaque { finally { diplomatReceive.free(); } - } - + } + optionI32() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -122,8 +124,8 @@ export class OptionOpaque { finally { diplomatReceive.free(); } - } - + } + optionU32() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -139,8 +141,8 @@ export class OptionOpaque { finally { diplomatReceive.free(); } - } - + } + static newStruct() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 16, 4, false); @@ -153,8 +155,8 @@ export class OptionOpaque { finally { diplomatReceive.free(); } - } - + } + static newStructNones() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 16, 4, false); @@ -167,15 +169,15 @@ export class OptionOpaque { finally { diplomatReceive.free(); } - } - + } + assertInteger(i) {wasm.OptionOpaque_assert_integer(this.ffiValue, i); try {} finally {} - } - + } + static optionOpaqueArgument(arg) { const result = wasm.OptionOpaque_option_opaque_argument(arg.ffiValue ?? 0); @@ -184,8 +186,8 @@ export class OptionOpaque { } finally {} - } - + } + static acceptsOptionU8(arg) { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 2, 1, true); @@ -201,8 +203,8 @@ export class OptionOpaque { finally { diplomatReceive.free(); } - } - + } + static acceptsOptionEnum(arg) { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -218,8 +220,8 @@ export class OptionOpaque { finally { diplomatReceive.free(); } - } - + } + static acceptsOptionInputStruct(arg) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -239,8 +241,8 @@ export class OptionOpaque { diplomatReceive.free(); } - } - + } + static returnsOptionInputStruct() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 20, 4, false); @@ -253,5 +255,9 @@ export class OptionOpaque { finally { diplomatReceive.free(); } - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/OptionOpaqueChar.d.ts b/feature_tests/js/api/OptionOpaqueChar.d.ts index 06ad0f9c0..dfb5334fe 100644 --- a/feature_tests/js/api/OptionOpaqueChar.d.ts +++ b/feature_tests/js/api/OptionOpaqueChar.d.ts @@ -1,10 +1,11 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class OptionOpaqueChar { + + +export class OptionOpaqueChar { - - get ffiValue(): pointer; - - assertChar(ch: codepoint): void; + get ffiValue(): pointer; + + assertChar(ch: codepoint): void; } \ No newline at end of file diff --git a/feature_tests/js/api/OptionOpaqueChar.mjs b/feature_tests/js/api/OptionOpaqueChar.mjs index b9edc9d20..668c35e87 100644 --- a/feature_tests/js/api/OptionOpaqueChar.mjs +++ b/feature_tests/js/api/OptionOpaqueChar.mjs @@ -4,9 +4,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const OptionOpaqueChar_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.OptionOpaqueChar_destroy(ptr); -}); - -export class OptionOpaqueChar { +}); + +export class OptionOpaqueChar { + // Internal ptr reference: #ptr = null; @@ -14,7 +15,7 @@ export class OptionOpaqueChar { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("OptionOpaqueChar is an Opaque type. You cannot call its constructor."); return; @@ -27,16 +28,21 @@ export class OptionOpaqueChar { if (this.#selfEdge.length === 0) { OptionOpaqueChar_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + assertChar(ch) {wasm.OptionOpaqueChar_assert_char(this.ffiValue, ch); try {} finally {} - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/OptionString.d.ts b/feature_tests/js/api/OptionString.d.ts index 4ebce0a29..7a9c3858a 100644 --- a/feature_tests/js/api/OptionString.d.ts +++ b/feature_tests/js/api/OptionString.d.ts @@ -1,14 +1,15 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class OptionString { + + +export class OptionString { - - get ffiValue(): pointer; - - static new_(diplomatStr: string): OptionString | null; - - write(): string | null; - - borrow(): string | null; + get ffiValue(): pointer; + + static new_(diplomatStr: string): OptionString | null; + + write(): string | null; + + borrow(): string | null; } \ No newline at end of file diff --git a/feature_tests/js/api/OptionString.mjs b/feature_tests/js/api/OptionString.mjs index a3ea4e40a..3239065d2 100644 --- a/feature_tests/js/api/OptionString.mjs +++ b/feature_tests/js/api/OptionString.mjs @@ -4,9 +4,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const OptionString_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.OptionString_destroy(ptr); -}); - -export class OptionString { +}); + +export class OptionString { + // Internal ptr reference: #ptr = null; @@ -14,7 +15,7 @@ export class OptionString { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("OptionString is an Opaque type. You cannot call its constructor."); return; @@ -27,12 +28,13 @@ export class OptionString { if (this.#selfEdge.length === 0) { OptionString_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static new_(diplomatStr) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); @@ -47,8 +49,8 @@ export class OptionString { finally { functionCleanupArena.free(); } - } - + } + write() { const write = new diplomatRuntime.DiplomatWriteBuf(wasm); @@ -61,8 +63,8 @@ export class OptionString { finally { write.free(); } - } - + } + borrow() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 9, 4, true); @@ -81,5 +83,9 @@ export class OptionString { finally { diplomatReceive.free(); } - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/OptionStruct.d.ts b/feature_tests/js/api/OptionStruct.d.ts index 8d65486cd..d9e0b7aab 100644 --- a/feature_tests/js/api/OptionStruct.d.ts +++ b/feature_tests/js/api/OptionStruct.d.ts @@ -3,17 +3,16 @@ import type { OptionOpaque } from "./OptionOpaque" import type { OptionOpaqueChar } from "./OptionOpaqueChar" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class OptionStruct { - + + +export class OptionStruct { + get a() : OptionOpaque | null; - get b() : OptionOpaqueChar | null; - get c() : number; - get d() : OptionOpaque | null; - + } \ No newline at end of file diff --git a/feature_tests/js/api/OptionStruct.mjs b/feature_tests/js/api/OptionStruct.mjs index d66b22e66..7296d67cc 100644 --- a/feature_tests/js/api/OptionStruct.mjs +++ b/feature_tests/js/api/OptionStruct.mjs @@ -4,32 +4,35 @@ import { OptionOpaqueChar } from "./OptionOpaqueChar.mjs" import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -export class OptionStruct { - + + +export class OptionStruct { + #a; + get a() { return this.#a; } - #b; + get b() { return this.#b; } - #c; + get c() { return this.#c; } - #d; + get d() { return this.#d; } - constructor(structObj, internalConstructor) { + #internalConstructor(structObj, internalConstructor) { if (typeof structObj !== "object") { throw new Error("OptionStruct's constructor takes an object of OptionStruct's fields."); } @@ -61,6 +64,7 @@ export class OptionStruct { throw new Error("Missing required field d."); } + return this; } // Return this struct in FFI function friendly format. @@ -82,7 +86,7 @@ export class OptionStruct { return obj; } - return new OptionStruct(obj); + return OptionStruct.fromFields(obj); } _writeToArrayBuffer( @@ -106,7 +110,7 @@ export class OptionStruct { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("OptionStruct._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const aDeref = diplomatRuntime.ptrRead(wasm, ptr); structObj.a = aDeref === 0 ? null : new OptionOpaque(diplomatRuntime.internalConstructor, aDeref, []); const bDeref = diplomatRuntime.ptrRead(wasm, ptr + 4); @@ -117,5 +121,9 @@ export class OptionStruct { structObj.d = dDeref === 0 ? null : new OptionOpaque(diplomatRuntime.internalConstructor, dDeref, []); return new OptionStruct(structObj, internalConstructor); - } + } + + constructor(structObj, internalConstructor) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/RefList.d.ts b/feature_tests/js/api/RefList.d.ts index 8eb737974..5e198f07e 100644 --- a/feature_tests/js/api/RefList.d.ts +++ b/feature_tests/js/api/RefList.d.ts @@ -2,10 +2,11 @@ import type { RefListParameter } from "./RefListParameter" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class RefList { + + +export class RefList { - - get ffiValue(): pointer; - - static node(data: RefListParameter): RefList; + get ffiValue(): pointer; + + static node(data: RefListParameter): RefList; } \ No newline at end of file diff --git a/feature_tests/js/api/RefList.mjs b/feature_tests/js/api/RefList.mjs index 1ccd4444a..ca56f8b24 100644 --- a/feature_tests/js/api/RefList.mjs +++ b/feature_tests/js/api/RefList.mjs @@ -5,9 +5,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const RefList_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.RefList_destroy(ptr); -}); - -export class RefList { +}); + +export class RefList { + // Internal ptr reference: #ptr = null; @@ -16,7 +17,7 @@ export class RefList { #selfEdge = []; #aEdge = []; - constructor(symbol, ptr, selfEdge, aEdge) { + #internalConstructor(symbol, ptr, selfEdge, aEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("RefList is an Opaque type. You cannot call its constructor."); return; @@ -32,12 +33,13 @@ export class RefList { if (this.#selfEdge.length === 0) { RefList_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static node(data) { // This lifetime edge depends on lifetimes 'b let bEdges = [data]; @@ -49,5 +51,9 @@ export class RefList { } finally {} - } + } + + constructor(symbol, ptr, selfEdge, aEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/RefListParameter.d.ts b/feature_tests/js/api/RefListParameter.d.ts index 92ec0855f..79d32e33c 100644 --- a/feature_tests/js/api/RefListParameter.d.ts +++ b/feature_tests/js/api/RefListParameter.d.ts @@ -1,8 +1,9 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class RefListParameter { + + +export class RefListParameter { - - get ffiValue(): pointer; + get ffiValue(): pointer; } \ No newline at end of file diff --git a/feature_tests/js/api/RefListParameter.mjs b/feature_tests/js/api/RefListParameter.mjs index 1321ae415..3ce913683 100644 --- a/feature_tests/js/api/RefListParameter.mjs +++ b/feature_tests/js/api/RefListParameter.mjs @@ -4,9 +4,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const RefListParameter_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.RefListParameter_destroy(ptr); -}); - -export class RefListParameter { +}); + +export class RefListParameter { + // Internal ptr reference: #ptr = null; @@ -14,7 +15,7 @@ export class RefListParameter { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("RefListParameter is an Opaque type. You cannot call its constructor."); return; @@ -27,9 +28,14 @@ export class RefListParameter { if (this.#selfEdge.length === 0) { RefListParameter_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedAttrEnum.d.ts b/feature_tests/js/api/RenamedAttrEnum.d.ts index 367a44768..dc76f2434 100644 --- a/feature_tests/js/api/RenamedAttrEnum.d.ts +++ b/feature_tests/js/api/RenamedAttrEnum.d.ts @@ -1,9 +1,12 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -// Base enumerator definition -export class RenamedAttrEnum { - constructor(value : RenamedAttrEnum | string); + + +export class RenamedAttrEnum { + + + static fromValue(value : RenamedAttrEnum | string) : RenamedAttrEnum; get value() : string; @@ -11,5 +14,7 @@ export class RenamedAttrEnum { static A : RenamedAttrEnum; static B : RenamedAttrEnum; - static Renamed : RenamedAttrEnum; + static Renamed : RenamedAttrEnum; + + constructor(value: RenamedAttrEnum | string ); } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedAttrEnum.mjs b/feature_tests/js/api/RenamedAttrEnum.mjs index be4c09515..2813efa42 100644 --- a/feature_tests/js/api/RenamedAttrEnum.mjs +++ b/feature_tests/js/api/RenamedAttrEnum.mjs @@ -2,8 +2,10 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -// Base enumerator definition -export class RenamedAttrEnum { + + +export class RenamedAttrEnum { + #value = undefined; static #values = new Map([ @@ -15,14 +17,14 @@ export class RenamedAttrEnum { static getAllEntries() { return RenamedAttrEnum.#values.entries(); } - - constructor(value) { + + #internalConstructor(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 this; } return RenamedAttrEnum.#objectValues[arguments[1]]; } @@ -34,13 +36,17 @@ export class RenamedAttrEnum { let intVal = RenamedAttrEnum.#values.get(value); // Nullish check, checks for null or undefined - if (intVal == null) { + if (intVal != null) { return RenamedAttrEnum.#objectValues[intVal]; } throw TypeError(value + " is not a RenamedAttrEnum and does not correspond to any of its enumerator values."); } + static fromValue(value) { + return new RenamedAttrEnum(value); + } + get value() { return [...RenamedAttrEnum.#values.keys()][this.#value]; } @@ -56,5 +62,9 @@ export class RenamedAttrEnum { static A = RenamedAttrEnum.#objectValues[0]; static B = RenamedAttrEnum.#objectValues[1]; - static Renamed = RenamedAttrEnum.#objectValues[2]; + static Renamed = RenamedAttrEnum.#objectValues[2]; + + constructor(value) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedAttrOpaque2.d.ts b/feature_tests/js/api/RenamedAttrOpaque2.d.ts index 761ee8831..ecf22d1d9 100644 --- a/feature_tests/js/api/RenamedAttrOpaque2.d.ts +++ b/feature_tests/js/api/RenamedAttrOpaque2.d.ts @@ -1,8 +1,9 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class RenamedAttrOpaque2 { + + +export class RenamedAttrOpaque2 { - - get ffiValue(): pointer; + get ffiValue(): pointer; } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedAttrOpaque2.mjs b/feature_tests/js/api/RenamedAttrOpaque2.mjs index e2e2da2cc..b4abed1d2 100644 --- a/feature_tests/js/api/RenamedAttrOpaque2.mjs +++ b/feature_tests/js/api/RenamedAttrOpaque2.mjs @@ -4,9 +4,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const RenamedAttrOpaque2_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.namespace_AttrOpaque2_destroy(ptr); -}); - -export class RenamedAttrOpaque2 { +}); + +export class RenamedAttrOpaque2 { + // Internal ptr reference: #ptr = null; @@ -14,7 +15,7 @@ export class RenamedAttrOpaque2 { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("RenamedAttrOpaque2 is an Opaque type. You cannot call its constructor."); return; @@ -27,9 +28,14 @@ export class RenamedAttrOpaque2 { if (this.#selfEdge.length === 0) { RenamedAttrOpaque2_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedMyIterable.d.ts b/feature_tests/js/api/RenamedMyIterable.d.ts index 24bf845ef..31427daa7 100644 --- a/feature_tests/js/api/RenamedMyIterable.d.ts +++ b/feature_tests/js/api/RenamedMyIterable.d.ts @@ -2,12 +2,13 @@ import type { RenamedMyIterator } from "./RenamedMyIterator" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class RenamedMyIterable { + + +export class RenamedMyIterable { - - get ffiValue(): pointer; - - static new_(x: Array): RenamedMyIterable; - - [Symbol.iterator](): RenamedMyIterator; + get ffiValue(): pointer; + + [Symbol.iterator](): RenamedMyIterator; + + constructor(x: Array); } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedMyIterable.mjs b/feature_tests/js/api/RenamedMyIterable.mjs index fc2133413..a3d227d6f 100644 --- a/feature_tests/js/api/RenamedMyIterable.mjs +++ b/feature_tests/js/api/RenamedMyIterable.mjs @@ -5,9 +5,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const RenamedMyIterable_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.namespace_MyIterable_destroy(ptr); -}); - -export class RenamedMyIterable { +}); + +export class RenamedMyIterable { + // Internal ptr reference: #ptr = null; @@ -15,7 +16,7 @@ export class RenamedMyIterable { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("RenamedMyIterable is an Opaque type. You cannot call its constructor."); return; @@ -28,13 +29,14 @@ export class RenamedMyIterable { if (this.#selfEdge.length === 0) { RenamedMyIterable_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - - static new_(x) { + } + + #defaultConstructor(x) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); const xSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.slice(wasm, x, "u8")); @@ -48,8 +50,8 @@ export class RenamedMyIterable { finally { functionCleanupArena.free(); } - } - + } + [Symbol.iterator]() { // This lifetime edge depends on lifetimes 'a let aEdges = [this]; @@ -61,5 +63,15 @@ export class RenamedMyIterable { } finally {} - } + } + + constructor(x) { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedMyIterator.d.ts b/feature_tests/js/api/RenamedMyIterator.d.ts index 0511d5cfc..63f97d326 100644 --- a/feature_tests/js/api/RenamedMyIterator.d.ts +++ b/feature_tests/js/api/RenamedMyIterator.d.ts @@ -1,13 +1,11 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class RenamedMyIterator { + + +export class RenamedMyIterator { - - get ffiValue(): pointer; - - #iteratorNext(): number | null; - - - next() : IteratorResult; + get ffiValue(): pointer; + + next() : IteratorResult; } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedMyIterator.mjs b/feature_tests/js/api/RenamedMyIterator.mjs index fc8aaa141..e3d7736d5 100644 --- a/feature_tests/js/api/RenamedMyIterator.mjs +++ b/feature_tests/js/api/RenamedMyIterator.mjs @@ -4,9 +4,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const RenamedMyIterator_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.namespace_MyIterator_destroy(ptr); -}); - -export class RenamedMyIterator { +}); + +export class RenamedMyIterator { + // Internal ptr reference: #ptr = null; @@ -15,7 +16,7 @@ export class RenamedMyIterator { #selfEdge = []; #aEdge = []; - constructor(symbol, ptr, selfEdge, aEdge) { + #internalConstructor(symbol, ptr, selfEdge, aEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("RenamedMyIterator is an Opaque type. You cannot call its constructor."); return; @@ -31,12 +32,13 @@ export class RenamedMyIterator { if (this.#selfEdge.length === 0) { RenamedMyIterator_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + #iteratorNext() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 2, 1, true); @@ -52,15 +54,18 @@ export class RenamedMyIterator { finally { diplomatReceive.free(); } - } - - - next() { - const out = this.#iteratorNext(); - - return { - value: out, - done: out === null, - }; - } + } + + next() { + const out = this.#iteratorNext(); + + return { + value: out, + done: out === null, + }; + } + + constructor(symbol, ptr, selfEdge, aEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedOpaqueIterable.d.ts b/feature_tests/js/api/RenamedOpaqueIterable.d.ts index 5c13881da..719fccf9e 100644 --- a/feature_tests/js/api/RenamedOpaqueIterable.d.ts +++ b/feature_tests/js/api/RenamedOpaqueIterable.d.ts @@ -2,10 +2,11 @@ import type { RenamedOpaqueIterator } from "./RenamedOpaqueIterator" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class RenamedOpaqueIterable { + + +export class RenamedOpaqueIterable { - - get ffiValue(): pointer; - - [Symbol.iterator](): RenamedOpaqueIterator; + get ffiValue(): pointer; + + [Symbol.iterator](): RenamedOpaqueIterator; } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedOpaqueIterable.mjs b/feature_tests/js/api/RenamedOpaqueIterable.mjs index b43de5b73..7ba7d9f38 100644 --- a/feature_tests/js/api/RenamedOpaqueIterable.mjs +++ b/feature_tests/js/api/RenamedOpaqueIterable.mjs @@ -5,9 +5,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const RenamedOpaqueIterable_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.namespace_OpaqueIterable_destroy(ptr); -}); - -export class RenamedOpaqueIterable { +}); + +export class RenamedOpaqueIterable { + // Internal ptr reference: #ptr = null; @@ -15,7 +16,7 @@ export class RenamedOpaqueIterable { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("RenamedOpaqueIterable is an Opaque type. You cannot call its constructor."); return; @@ -28,12 +29,13 @@ export class RenamedOpaqueIterable { if (this.#selfEdge.length === 0) { RenamedOpaqueIterable_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + [Symbol.iterator]() { // This lifetime edge depends on lifetimes 'a let aEdges = [this]; @@ -45,5 +47,9 @@ export class RenamedOpaqueIterable { } finally {} - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedOpaqueIterator.d.ts b/feature_tests/js/api/RenamedOpaqueIterator.d.ts index 448d71ecf..5de94022c 100644 --- a/feature_tests/js/api/RenamedOpaqueIterator.d.ts +++ b/feature_tests/js/api/RenamedOpaqueIterator.d.ts @@ -2,13 +2,11 @@ import type { AttrOpaque1Renamed } from "./AttrOpaque1Renamed" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class RenamedOpaqueIterator { + + +export class RenamedOpaqueIterator { - - get ffiValue(): pointer; - - #iteratorNext(): AttrOpaque1Renamed | null; - - - next() : IteratorResult; + get ffiValue(): pointer; + + next() : IteratorResult; } \ No newline at end of file diff --git a/feature_tests/js/api/RenamedOpaqueIterator.mjs b/feature_tests/js/api/RenamedOpaqueIterator.mjs index c85ba89bf..18e1612b9 100644 --- a/feature_tests/js/api/RenamedOpaqueIterator.mjs +++ b/feature_tests/js/api/RenamedOpaqueIterator.mjs @@ -5,9 +5,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const RenamedOpaqueIterator_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.namespace_OpaqueIterator_destroy(ptr); -}); - -export class RenamedOpaqueIterator { +}); + +export class RenamedOpaqueIterator { + // Internal ptr reference: #ptr = null; @@ -16,7 +17,7 @@ export class RenamedOpaqueIterator { #selfEdge = []; #aEdge = []; - constructor(symbol, ptr, selfEdge, aEdge) { + #internalConstructor(symbol, ptr, selfEdge, aEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("RenamedOpaqueIterator is an Opaque type. You cannot call its constructor."); return; @@ -32,12 +33,13 @@ export class RenamedOpaqueIterator { if (this.#selfEdge.length === 0) { RenamedOpaqueIterator_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + #iteratorNext() { const result = wasm.namespace_OpaqueIterator_next(this.ffiValue); @@ -46,15 +48,18 @@ export class RenamedOpaqueIterator { } finally {} - } - - - next() { - const out = this.#iteratorNext(); - - return { - value: out, - done: out === null, - }; - } + } + + next() { + const out = this.#iteratorNext(); + + return { + value: out, + done: out === null, + }; + } + + constructor(symbol, ptr, selfEdge, aEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/ResultOpaque.d.ts b/feature_tests/js/api/ResultOpaque.d.ts index 03344b663..2db9692a8 100644 --- a/feature_tests/js/api/ResultOpaque.d.ts +++ b/feature_tests/js/api/ResultOpaque.d.ts @@ -3,26 +3,27 @@ import type { ErrorEnum } from "./ErrorEnum" import type { ErrorStruct } from "./ErrorStruct" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class ResultOpaque { + + +export class ResultOpaque { - - get ffiValue(): pointer; - - static new_(i: number): ResultOpaque; - - static newFailingFoo(): ResultOpaque; - - static newFailingBar(): ResultOpaque; - - static newFailingUnit(): ResultOpaque | null; - - static newFailingStruct(i: number): ResultOpaque; - - static newInErr(i: number): void; - - static newInt(i: number): number | null; - - static newInEnumErr(i: number): ErrorEnum; - - assertInteger(i: number): void; + get ffiValue(): pointer; + + static new_(i: number): ResultOpaque; + + static newFailingFoo(): ResultOpaque; + + static newFailingBar(): ResultOpaque; + + static newFailingUnit(): ResultOpaque | null; + + static newFailingStruct(i: number): ResultOpaque; + + static newInErr(i: number): void; + + static newInt(i: number): number | null; + + static newInEnumErr(i: number): ErrorEnum; + + assertInteger(i: number): void; } \ No newline at end of file diff --git a/feature_tests/js/api/ResultOpaque.mjs b/feature_tests/js/api/ResultOpaque.mjs index 0753c6c2a..b82fbba1a 100644 --- a/feature_tests/js/api/ResultOpaque.mjs +++ b/feature_tests/js/api/ResultOpaque.mjs @@ -6,9 +6,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const ResultOpaque_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.ResultOpaque_destroy(ptr); -}); - -export class ResultOpaque { +}); + +export class ResultOpaque { + // Internal ptr reference: #ptr = null; @@ -16,7 +17,7 @@ export class ResultOpaque { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("ResultOpaque is an Opaque type. You cannot call its constructor."); return; @@ -29,12 +30,13 @@ export class ResultOpaque { if (this.#selfEdge.length === 0) { ResultOpaque_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static new_(i) { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -51,8 +53,8 @@ export class ResultOpaque { finally { diplomatReceive.free(); } - } - + } + static newFailingFoo() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -69,8 +71,8 @@ export class ResultOpaque { finally { diplomatReceive.free(); } - } - + } + static newFailingBar() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -87,8 +89,8 @@ export class ResultOpaque { finally { diplomatReceive.free(); } - } - + } + static newFailingUnit() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -104,8 +106,8 @@ export class ResultOpaque { finally { diplomatReceive.free(); } - } - + } + static newFailingStruct(i) { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 9, 4, true); @@ -122,8 +124,8 @@ export class ResultOpaque { finally { diplomatReceive.free(); } - } - + } + static newInErr(i) { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -140,8 +142,8 @@ export class ResultOpaque { finally { diplomatReceive.free(); } - } - + } + static newInt(i) { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -157,8 +159,8 @@ export class ResultOpaque { finally { diplomatReceive.free(); } - } - + } + static newInEnumErr(i) { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 5, 4, true); @@ -175,12 +177,16 @@ export class ResultOpaque { finally { diplomatReceive.free(); } - } - + } + assertInteger(i) {wasm.ResultOpaque_assert_integer(this.ffiValue, i); try {} finally {} - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/ScalarPairWithPadding.d.ts b/feature_tests/js/api/ScalarPairWithPadding.d.ts index 13964fc3c..a6f0b5f50 100644 --- a/feature_tests/js/api/ScalarPairWithPadding.d.ts +++ b/feature_tests/js/api/ScalarPairWithPadding.d.ts @@ -1,22 +1,31 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; - -/** Testing JS-specific layout/padding behavior -*/ + +/** Testing JS-specific layout/padding behavior +*/ type ScalarPairWithPadding_obj = { first: number; second: number; }; -export class ScalarPairWithPadding { - - get first() : number; + + +export class ScalarPairWithPadding { + + get first() : number; set first(value: number); - - get second() : number; + + get second() : number; set second(value: number); - constructor(structObj : ScalarPairWithPadding_obj); - - assertValue(): void; + + /** Create `ScalarPairWithPadding` from an object that contains all of `ScalarPairWithPadding`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj : ScalarPairWithPadding_obj) : ScalarPairWithPadding; + + + assertValue(): void; + + constructor(structObj : ScalarPairWithPadding_obj); } \ No newline at end of file diff --git a/feature_tests/js/api/ScalarPairWithPadding.mjs b/feature_tests/js/api/ScalarPairWithPadding.mjs index 0ee8b43b5..68ca5a3a1 100644 --- a/feature_tests/js/api/ScalarPairWithPadding.mjs +++ b/feature_tests/js/api/ScalarPairWithPadding.mjs @@ -2,27 +2,39 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; - -/** Testing JS-specific layout/padding behavior -*/ -export class ScalarPairWithPadding { - + +/** Testing JS-specific layout/padding behavior +*/ + + +export class ScalarPairWithPadding { + #first; + get first() { return this.#first; - } + } set first(value) { this.#first = value; } - + #second; + get second() { return this.#second; - } + } set second(value) { this.#second = value; } - constructor(structObj) { + + /** Create `ScalarPairWithPadding` from an object that contains all of `ScalarPairWithPadding`s fields. + * Optional fields do not need to be included in the provided object. + */ + static fromFields(structObj) { + return new ScalarPairWithPadding(structObj); + } + + #internalConstructor(structObj) { if (typeof structObj !== "object") { throw new Error("ScalarPairWithPadding's constructor takes an object of ScalarPairWithPadding's fields."); } @@ -39,6 +51,7 @@ export class ScalarPairWithPadding { throw new Error("Missing required field second."); } + return this; } // Return this struct in FFI function friendly format. @@ -64,7 +77,7 @@ export class ScalarPairWithPadding { return obj; } - return new ScalarPairWithPadding(obj); + return ScalarPairWithPadding.fromFields(obj); } _writeToArrayBuffer( @@ -87,15 +100,15 @@ export class ScalarPairWithPadding { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("ScalarPairWithPadding._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; const firstDeref = (new Uint8Array(wasm.memory.buffer, ptr, 1))[0]; structObj.first = firstDeref; const secondDeref = (new Uint32Array(wasm.memory.buffer, ptr + 4, 1))[0]; structObj.second = secondDeref; - return new ScalarPairWithPadding(structObj, internalConstructor); - } - + return new ScalarPairWithPadding(structObj); + } + assertValue() { let functionCleanupArena = new diplomatRuntime.CleanupArena(); wasm.ScalarPairWithPadding_assert_value(...this._intoFFI()); @@ -105,5 +118,9 @@ export class ScalarPairWithPadding { finally { functionCleanupArena.free(); } - } + } + + constructor(structObj) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/Two.d.ts b/feature_tests/js/api/Two.d.ts index 8a06416fb..5bb22ea54 100644 --- a/feature_tests/js/api/Two.d.ts +++ b/feature_tests/js/api/Two.d.ts @@ -1,8 +1,9 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class Two { + + +export class Two { - - get ffiValue(): pointer; + get ffiValue(): pointer; } \ No newline at end of file diff --git a/feature_tests/js/api/Two.mjs b/feature_tests/js/api/Two.mjs index ec2263bbc..7bb95029b 100644 --- a/feature_tests/js/api/Two.mjs +++ b/feature_tests/js/api/Two.mjs @@ -4,9 +4,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const Two_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.Two_destroy(ptr); -}); - -export class Two { +}); + +export class Two { + // Internal ptr reference: #ptr = null; @@ -16,7 +17,7 @@ export class Two { #aEdge = []; #bEdge = []; - constructor(symbol, ptr, selfEdge, aEdge, bEdge) { + #internalConstructor(symbol, ptr, selfEdge, aEdge, bEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("Two is an Opaque type. You cannot call its constructor."); return; @@ -35,9 +36,14 @@ export class Two { if (this.#selfEdge.length === 0) { Two_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } + } + + constructor(symbol, ptr, selfEdge, aEdge, bEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/UnimportedEnum.d.ts b/feature_tests/js/api/UnimportedEnum.d.ts index 4a3b8ca1a..d2af86908 100644 --- a/feature_tests/js/api/UnimportedEnum.d.ts +++ b/feature_tests/js/api/UnimportedEnum.d.ts @@ -1,9 +1,12 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -// Base enumerator definition -export class UnimportedEnum { - constructor(value : UnimportedEnum | string); + + +export class UnimportedEnum { + + + static fromValue(value : UnimportedEnum | string) : UnimportedEnum; get value() : string; @@ -11,5 +14,7 @@ export class UnimportedEnum { static A : UnimportedEnum; static B : UnimportedEnum; - static C : UnimportedEnum; + static C : UnimportedEnum; + + constructor(value: UnimportedEnum | string ); } \ No newline at end of file diff --git a/feature_tests/js/api/UnimportedEnum.mjs b/feature_tests/js/api/UnimportedEnum.mjs index 273e06e5e..4434235eb 100644 --- a/feature_tests/js/api/UnimportedEnum.mjs +++ b/feature_tests/js/api/UnimportedEnum.mjs @@ -2,8 +2,10 @@ import wasm from "./diplomat-wasm.mjs"; import * as diplomatRuntime from "./diplomat-runtime.mjs"; -// Base enumerator definition -export class UnimportedEnum { + + +export class UnimportedEnum { + #value = undefined; static #values = new Map([ @@ -15,14 +17,14 @@ export class UnimportedEnum { static getAllEntries() { return UnimportedEnum.#values.entries(); } - - constructor(value) { + + #internalConstructor(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 this; } return UnimportedEnum.#objectValues[arguments[1]]; } @@ -34,13 +36,17 @@ export class UnimportedEnum { let intVal = UnimportedEnum.#values.get(value); // Nullish check, checks for null or undefined - if (intVal == null) { + if (intVal != null) { return UnimportedEnum.#objectValues[intVal]; } throw TypeError(value + " is not a UnimportedEnum and does not correspond to any of its enumerator values."); } + static fromValue(value) { + return new UnimportedEnum(value); + } + get value() { return [...UnimportedEnum.#values.keys()][this.#value]; } @@ -56,5 +62,9 @@ export class UnimportedEnum { static A = UnimportedEnum.#objectValues[0]; static B = UnimportedEnum.#objectValues[1]; - static C = UnimportedEnum.#objectValues[2]; + static C = UnimportedEnum.#objectValues[2]; + + constructor(value) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/Unnamespaced.d.ts b/feature_tests/js/api/Unnamespaced.d.ts index 6c7301346..5e433df4a 100644 --- a/feature_tests/js/api/Unnamespaced.d.ts +++ b/feature_tests/js/api/Unnamespaced.d.ts @@ -3,12 +3,13 @@ import type { AttrOpaque1Renamed } from "./AttrOpaque1Renamed" import type { RenamedAttrEnum } from "./RenamedAttrEnum" import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class Unnamespaced { + + +export class Unnamespaced { - - get ffiValue(): pointer; - - static make(e: RenamedAttrEnum): Unnamespaced; - - useNamespaced(n: AttrOpaque1Renamed): void; + get ffiValue(): pointer; + + static make(e: RenamedAttrEnum): Unnamespaced; + + useNamespaced(n: AttrOpaque1Renamed): void; } \ No newline at end of file diff --git a/feature_tests/js/api/Unnamespaced.mjs b/feature_tests/js/api/Unnamespaced.mjs index 50adc186f..2fedcab79 100644 --- a/feature_tests/js/api/Unnamespaced.mjs +++ b/feature_tests/js/api/Unnamespaced.mjs @@ -6,9 +6,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const Unnamespaced_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.namespace_Unnamespaced_destroy(ptr); -}); - -export class Unnamespaced { +}); + +export class Unnamespaced { + // Internal ptr reference: #ptr = null; @@ -16,7 +17,7 @@ export class Unnamespaced { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("Unnamespaced is an Opaque type. You cannot call its constructor."); return; @@ -29,12 +30,13 @@ export class Unnamespaced { if (this.#selfEdge.length === 0) { Unnamespaced_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - + } + static make(e) { const result = wasm.namespace_Unnamespaced_make(e.ffiValue); @@ -43,12 +45,16 @@ export class Unnamespaced { } finally {} - } - + } + useNamespaced(n) {wasm.namespace_Unnamespaced_use_namespaced(this.ffiValue, n.ffiValue); try {} finally {} - } + } + + constructor(symbol, ptr, selfEdge) { + return this.#internalConstructor(...arguments) + } } \ No newline at end of file diff --git a/feature_tests/js/api/Utf16Wrap.d.ts b/feature_tests/js/api/Utf16Wrap.d.ts index 856a7021b..802f599c4 100644 --- a/feature_tests/js/api/Utf16Wrap.d.ts +++ b/feature_tests/js/api/Utf16Wrap.d.ts @@ -1,14 +1,15 @@ // generated by diplomat-tool import type { pointer, codepoint } from "./diplomat-runtime.d.ts"; -export class Utf16Wrap { + + +export class Utf16Wrap { - - get ffiValue(): pointer; - - static fromUtf16(input: string): Utf16Wrap; - - getDebugStr(): string; - - borrowCont(): string; + get ffiValue(): pointer; + + getDebugStr(): string; + + borrowCont(): string; + + constructor(input: string); } \ No newline at end of file diff --git a/feature_tests/js/api/Utf16Wrap.mjs b/feature_tests/js/api/Utf16Wrap.mjs index 1bb497ea3..6124774d8 100644 --- a/feature_tests/js/api/Utf16Wrap.mjs +++ b/feature_tests/js/api/Utf16Wrap.mjs @@ -4,9 +4,10 @@ import * as diplomatRuntime from "./diplomat-runtime.mjs"; const Utf16Wrap_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.Utf16Wrap_destroy(ptr); -}); - -export class Utf16Wrap { +}); + +export class Utf16Wrap { + // Internal ptr reference: #ptr = null; @@ -14,7 +15,7 @@ export class Utf16Wrap { // Since JS won't garbage collect until there are no incoming edges. #selfEdge = []; - constructor(symbol, ptr, selfEdge) { + #internalConstructor(symbol, ptr, selfEdge) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("Utf16Wrap is an Opaque type. You cannot call its constructor."); return; @@ -27,13 +28,14 @@ export class Utf16Wrap { if (this.#selfEdge.length === 0) { Utf16Wrap_box_destroy_registry.register(this, this.#ptr); } + + return this; } - get ffiValue() { return this.#ptr; - } - - static fromUtf16(input) { + } + + #defaultConstructor(input) { let functionCleanupArena = new diplomatRuntime.CleanupArena(); const inputSlice = functionCleanupArena.alloc(diplomatRuntime.DiplomatBuf.str16(wasm, input)); @@ -47,8 +49,8 @@ export class Utf16Wrap { finally { functionCleanupArena.free(); } - } - + } + getDebugStr() { const write = new diplomatRuntime.DiplomatWriteBuf(wasm); wasm.Utf16Wrap_get_debug_str(this.ffiValue, write.buffer); @@ -60,8 +62,8 @@ export class Utf16Wrap { finally { write.free(); } - } - + } + borrowCont() { const diplomatReceive = new diplomatRuntime.DiplomatReceiveBuf(wasm, 8, 4, false); @@ -77,5 +79,15 @@ export class Utf16Wrap { finally { diplomatReceive.free(); } - } + } + + constructor(input) { + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + } } \ No newline at end of file diff --git a/feature_tests/js/api/diplomat-runtime.mjs b/feature_tests/js/api/diplomat-runtime.mjs index fc8d591f3..6c0e2b3c0 100644 --- a/feature_tests/js/api/diplomat-runtime.mjs +++ b/feature_tests/js/api/diplomat-runtime.mjs @@ -1,5 +1,11 @@ -/** For internal Diplomat use when constructing opaques or structs. */ +/** For internal Diplomat use when constructing opaques or out structs. + * This is for when we're handling items that we don't want the user to touch, like an structure that's only meant to be output, or de-referencing a pointer we're handed from WASM. + */ export const internalConstructor = Symbol("constructor"); +/** For internal Diplomat use when accessing a from-fields/from-value constructor that's been overridden by a default constructor. + * If we want to pass in arguments without also passing in internalConstructor to avoid triggering some logic we don't want, we use exposeConstructor. + */ +export const exposeConstructor = Symbol("exposeConstructor"); export function readString8(wasm, ptr, len) { const buf = new Uint8Array(wasm.memory.buffer, ptr, len); diff --git a/feature_tests/js/api/index.d.ts b/feature_tests/js/api/index.d.ts index 8d58c8aea..53f4f56e9 100644 --- a/feature_tests/js/api/index.d.ts +++ b/feature_tests/js/api/index.d.ts @@ -88,4 +88,6 @@ export { ErrorEnum } from "./ErrorEnum" export { ContiguousEnum } from "./ContiguousEnum" +export { DefaultEnum } from "./DefaultEnum" + export { MyEnum } from "./MyEnum" diff --git a/feature_tests/js/api/index.mjs b/feature_tests/js/api/index.mjs index 1b9d4286d..bd45d4014 100644 --- a/feature_tests/js/api/index.mjs +++ b/feature_tests/js/api/index.mjs @@ -86,4 +86,6 @@ export { ErrorEnum } from "./ErrorEnum.mjs" export { ContiguousEnum } from "./ContiguousEnum.mjs" +export { DefaultEnum } from "./DefaultEnum.mjs" + export { MyEnum } from "./MyEnum.mjs" diff --git a/feature_tests/js/test/attrs.mts b/feature_tests/js/test/attrs.mts index d8c5bf726..226d05d87 100644 --- a/feature_tests/js/test/attrs.mts +++ b/feature_tests/js/test/attrs.mts @@ -3,7 +3,7 @@ import test from "ava"; import { RenamedMyIterable } from "diplomat-wasm-js-feature-tests"; test("Verify Iterables and Iterators", t => { - let iterable = RenamedMyIterable.new_([10, 20, 30, 40, 50]); + let iterable = new RenamedMyIterable([10, 20, 30, 40, 50]); let start = 10; for (let i of iterable) { diff --git a/feature_tests/js/test/lifetimes.mts b/feature_tests/js/test/lifetimes.mts index 7e7e74d2a..4351cff29 100644 --- a/feature_tests/js/test/lifetimes.mts +++ b/feature_tests/js/test/lifetimes.mts @@ -2,7 +2,7 @@ import test from 'ava'; import { Foo } from "diplomat-wasm-js-feature-tests"; test("Foo", (t) => { - let f = Foo.new_("This is a test string."); + let f = new Foo("This is a test string."); t.not(f.ffiValue, null); let returning = f.asReturning(); diff --git a/feature_tests/js/test/slices.mts b/feature_tests/js/test/slices.mts index 4b22a8e58..1ef9679e3 100644 --- a/feature_tests/js/test/slices.mts +++ b/feature_tests/js/test/slices.mts @@ -2,7 +2,7 @@ import test from "ava"; import { MyString, Float64Vec } from "diplomat-wasm-js-feature-tests"; test("MyString functionality", (t) => { - let str = MyString.new_("This is a test value."); + let str = new MyString("This is a test value."); t.is(str.str, "This is a test value."); }); @@ -12,7 +12,7 @@ test("String List", (t) => { }); test("MyString borrow", (t) => { - let str = MyString.new_("This is a test."); + let str = new MyString("This is a test."); t.is(str.borrow(), "This is a test."); }); diff --git a/feature_tests/js/test/struct.mts b/feature_tests/js/test/struct.mts index d9d646d80..d90fd1ec0 100644 --- a/feature_tests/js/test/struct.mts +++ b/feature_tests/js/test/struct.mts @@ -1,8 +1,8 @@ import test from 'ava'; -import { MyEnum, MyStruct, CyclicStructB, CyclicStructC, ScalarPairWithPadding, BigStructWithStuff } from "diplomat-wasm-js-feature-tests"; +import { MyEnum, MyStruct, CyclicStructB, CyclicStructC, ScalarPairWithPadding, BigStructWithStuff, DefaultEnum } from "diplomat-wasm-js-feature-tests"; test("Verify invariants of struct", t => { - const s = MyStruct.new_(); + const s = new MyStruct(); t.is(s.a, 17); t.is(s.b, true); t.is(s.c, 209); @@ -14,7 +14,7 @@ test("Verify invariants of struct", t => { }); test("Test struct creation", t => { - const s = new MyStruct({ + const s = MyStruct.fromFields({ a: 17, b: true, c: 209, @@ -87,4 +87,10 @@ test("Function Returning Nested Struct of One Primitive", t => { test("Function De-Referencing Nested Struct of One Primitive", t => { const a = CyclicStructB.getAOption(); t.is(a.cyclicOut(), "0"); +}); + +test("Verify Enum Construction", t => { + t.is(new DefaultEnum(), DefaultEnum.A); + + t.is(DefaultEnum.fromValue("B"), DefaultEnum.B); }); \ No newline at end of file diff --git a/feature_tests/kotlin/somelib/src/main/kotlin/dev/diplomattest/somelib/DefaultEnum.kt b/feature_tests/kotlin/somelib/src/main/kotlin/dev/diplomattest/somelib/DefaultEnum.kt new file mode 100644 index 000000000..b98b3a090 --- /dev/null +++ b/feature_tests/kotlin/somelib/src/main/kotlin/dev/diplomattest/somelib/DefaultEnum.kt @@ -0,0 +1,38 @@ +package dev.diplomattest.somelib + +import com.sun.jna.Callback +import com.sun.jna.Library +import com.sun.jna.Native +import com.sun.jna.Pointer +import com.sun.jna.Structure + +internal interface DefaultEnumLib: Library { + fun DefaultEnum_new(): Int +} +enum class DefaultEnum { + A, + B; + + fun toNative(): Int { + return this.ordinal + } + + + companion object { + internal val libClass: Class = DefaultEnumLib::class.java + internal val lib: DefaultEnumLib = Native.load("somelib", libClass) + fun fromNative(native: Int): DefaultEnum { + return DefaultEnum.entries[native] + } + + fun default(): DefaultEnum { + return A + } + + fun new_(): DefaultEnum { + + val returnVal = lib.DefaultEnum_new(); + return (DefaultEnum.fromNative(returnVal)) + } + } +} \ No newline at end of file diff --git a/feature_tests/src/structs.rs b/feature_tests/src/structs.rs index a4c374494..7379be024 100644 --- a/feature_tests/src/structs.rs +++ b/feature_tests/src/structs.rs @@ -43,6 +43,11 @@ pub mod ffi { D(i32, ImportedStruct), } + pub enum DefaultEnum { + A, + B, + } + pub struct MyStruct { a: u8, b: bool, @@ -193,6 +198,13 @@ pub mod ffi { } } + impl DefaultEnum { + #[diplomat::attr(all(supports=constructors, not(dart)), constructor)] + pub fn new() -> DefaultEnum { + DefaultEnum::A + } + } + impl MyStruct { #[diplomat::attr(auto, constructor)] pub fn new() -> MyStruct { diff --git a/tool/src/demo_gen/terminus.rs b/tool/src/demo_gen/terminus.rs index e9e621cda..5517d12dc 100644 --- a/tool/src/demo_gen/terminus.rs +++ b/tool/src/demo_gen/terminus.rs @@ -356,6 +356,8 @@ impl RenderTerminusContext<'_, '_> { "(function (...args) {{ return args[0].{method_name}{} }})", if !is_getter { "(...args.slice(1))" } else { "" } ) + } else if let Some(hir::SpecialMethod::Constructor) = method.attrs.special_method { + format!("(function (...args) {{ return new {owner_type_name}(...args) }} )") } else { format!("{owner_type_name}.{method_name}") } diff --git a/tool/src/js/converter.rs b/tool/src/js/converter.rs index 110223070..169b2a174 100644 --- a/tool/src/js/converter.rs +++ b/tool/src/js/converter.rs @@ -205,7 +205,7 @@ impl<'tcx> TyGenContext<'_, 'tcx> { let type_def = self.tcx.resolve_type(id); match type_def { hir::TypeDef::Struct(st) if st.fields.is_empty() => { - format!("new {type_name}({{}}, diplomatRuntime.internalConstructor)").into() + format!("{type_name}.fromFields({{}}, diplomatRuntime.internalConstructor)").into() } hir::TypeDef::Struct(..) => { format!("{type_name}._fromFFI(diplomatRuntime.internalConstructor, {variable_name}{edges})").into() diff --git a/tool/src/js/gen.rs b/tool/src/js/gen.rs index a49f9feed..4e445970d 100644 --- a/tool/src/js/gen.rs +++ b/tool/src/js/gen.rs @@ -150,6 +150,9 @@ impl<'tcx> TyGenContext<'_, 'tcx> { doc_str: String, methods: &'a MethodsInfo<'a>, + + /// Used by `js_class.js.jinja`. If a constructor isn't overridden by #[diplomat::attr(auto, constructor)], this is the logic that `js_class.js.jinja` will use to determine whether or not to generate constructor code. + show_default_ctor: bool, } ImplTemplate { @@ -162,6 +165,8 @@ impl<'tcx> TyGenContext<'_, 'tcx> { is_contiguous, methods, + + show_default_ctor: true, } .render() .unwrap() @@ -186,9 +191,13 @@ impl<'tcx> TyGenContext<'_, 'tcx> { lifetimes: &'a LifetimeEnv, destructor: &'a str, - docs: String, + doc_str: String, methods: &'a MethodsInfo<'a>, + + /// Used by `js_class.js.jinja`. If a constructor isn't overridden by #[diplomat::attr(auto, constructor)], this is the logic that `js_class.js.jinja` will use to determine whether or not to generate constructor code. + /// Useful for hiding opaque constructors in typescript headers, for instance. + show_default_ctor: bool, } ImplTemplate { @@ -198,9 +207,11 @@ impl<'tcx> TyGenContext<'_, 'tcx> { lifetimes: &opaque_def.lifetimes, destructor, - docs: self.formatter.fmt_docs(&opaque_def.docs), + doc_str: self.formatter.fmt_docs(&opaque_def.docs), methods, + + show_default_ctor: !typescript, } .render() .unwrap() @@ -413,7 +424,11 @@ impl<'tcx> TyGenContext<'_, 'tcx> { wraps_primitive: bool, owns_wrapped_primitive: bool, - docs: String, + doc_str: String, + + /// Used by `js_class.js.jinja`. If a constructor isn't overridden by #[diplomat::attr(auto, constructor)], this is the logic that `js_class.js.jinja` will use to determine whether or not to generate constructor code. + /// Useful for hiding the fact that an out_struct has a constructor in typescript headers, for instance. + show_default_ctor: bool, } ImplTemplate { @@ -435,7 +450,9 @@ impl<'tcx> TyGenContext<'_, 'tcx> { hir::Type::Primitive(..) ), - docs: self.formatter.fmt_docs(&struct_def.docs), + doc_str: self.formatter.fmt_docs(&struct_def.docs), + + show_default_ctor: !is_out || !typescript, } .render() .unwrap() @@ -596,8 +613,11 @@ impl<'tcx> TyGenContext<'_, 'tcx> { format!("set {}", self.formatter.fmt_method_field_name(name, method)) } Some(SpecialMethod::Iterable) => "[Symbol.iterator]".to_string(), + // TODO: Make this hidden in typescript. Some(SpecialMethod::Iterator) => "#iteratorNext".to_string(), + Some(SpecialMethod::Constructor) => "#defaultConstructor".into(), + _ if method.param_self.is_none() => { format!("static {}", self.formatter.fmt_method_name(method)) } @@ -623,13 +643,14 @@ impl<'tcx> TyGenContext<'_, 'tcx> { SpecialMethodInfo { iterator, + constructor: None, typescript: false, } } } /// Represents a parameter of a method. Used as part of [`MethodInfo`], exclusively in the method definition. -#[derive(Default)] +#[derive(Default, Clone)] pub(super) struct ParamInfo<'a> { ty: Cow<'a, str>, name: Cow<'a, str>, @@ -642,6 +663,7 @@ pub(super) struct ParamInfo<'a> { /// [`ParamInfo`] represents the conversion of the slice into C-friendly terms. This just represents an extra stage for Diplomat to convert whatever slice type we're given into a type that returns a `.ptr` and `.size` field. /// /// See `DiplomatBuf` in `runtime.mjs` for more. +#[derive(Clone)] pub(super) struct SliceParam<'a> { name: Cow<'a, str>, /// How to convert the JS type into a C slice. @@ -651,7 +673,7 @@ pub(super) struct SliceParam<'a> { /// Represents a Rust method that we invoke inside of WebAssembly with JS. /// /// Has an attached template to convert it into Javascript. -#[derive(Default, Template)] +#[derive(Default, Template, Clone)] #[template(path = "js/method.js.jinja", escape = "none")] pub(super) struct MethodInfo<'info> { /// Do we return the `()` type? @@ -693,11 +715,11 @@ pub(super) struct MethodInfo<'info> { } /// See [`TyGenContext::generate_special_method`]. -#[derive(Template)] -#[template(path = "js/iterator.js.jinja", escape = "none")] +/// Used in `js_class.js.jinja` pub(super) struct SpecialMethodInfo<'a> { iterator: Option>, pub typescript: bool, + pub constructor: Option>, } /// An amalgamation of both [`SpecialMethodInfo`] and [`MethodInfo`], since these two always get passed together in methods. diff --git a/tool/src/js/mod.rs b/tool/src/js/mod.rs index be12d0062..d99fe635d 100644 --- a/tool/src/js/mod.rs +++ b/tool/src/js/mod.rs @@ -44,7 +44,7 @@ pub(crate) fn attr_support() -> BackendAttrSupport { a.utf16_strings = true; a.static_slices = false; - a.constructors = false; + a.constructors = true; a.named_constructors = false; a.fallible_constructors = false; a.accessors = true; @@ -128,12 +128,26 @@ pub(crate) fn run<'tcx>( _ => unreachable!("HIR/AST variant {:?} is unknown.", type_def), }; + let mut special_methods = context.generate_special_method(special_method_presence); + + let methods = m + .iter() + .flat_map(|method| { + let inf = context.generate_method(id, method); + if inf.is_some() { + if let Some(diplomat_core::hir::SpecialMethod::Constructor) = + method.attrs.special_method + { + special_methods.constructor.replace(inf.clone().unwrap()); + } + } + inf + }) + .collect::>(); + let mut methods_info = MethodsInfo { - methods: m - .iter() - .flat_map(|method| context.generate_method(id, method)) - .collect::>(), - special_methods: context.generate_special_method(special_method_presence), + methods, + special_methods, }; for file_type in [FileType::Module, FileType::Typescript] { diff --git a/tool/templates/demo_gen/struct.js.jinja b/tool/templates/demo_gen/struct.js.jinja index f1b9e00a0..f04e31f94 100644 --- a/tool/templates/demo_gen/struct.js.jinja +++ b/tool/templates/demo_gen/struct.js.jinja @@ -1,5 +1,5 @@ (function (...args) { - return new {{type_name}}({ + return {{type_name}}.fromFields({ {%- for field in fields %} {{field}}: args[{{loop.index0}}]{% if !loop.last %},{% endif %} {%- endfor -%} diff --git a/tool/templates/js/enum.js.jinja b/tool/templates/js/enum.js.jinja index 9878a5057..b17b107eb 100644 --- a/tool/templates/js/enum.js.jinja +++ b/tool/templates/js/enum.js.jinja @@ -1,9 +1,10 @@ -// Base enumerator definition -{% if !doc_str.is_empty() -%} -/** {{doc_str}} -*/ -{% endif -%} -export class {{type_name}} { +{% extends "js/js_class.js.jinja" %} + +{% block internal_ctor_params -%} +value {%- if typescript %}: {{type_name}} | string {% endif -%} +{%- endblock %} + +{% block class_body %} {%- if !typescript %} #value = undefined; @@ -16,16 +17,14 @@ export class {{type_name}} { static getAllEntries() { return {{type_name}}.#values.entries(); } - - {# TODO: I think it's possible to allow for constructors, - but we just need to check if a constructor will be generated. -#} - constructor(value) { + + #internalConstructor(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 this; } return {{type_name}}.#objectValues[arguments[1]]; } @@ -37,15 +36,19 @@ export class {{type_name}} { let intVal = {{type_name}}.#values.get(value); // Nullish check, checks for null or undefined - if (intVal == null) { + if (intVal != null) { return {{type_name}}.#objectValues[intVal]; } throw TypeError(value + " is not a {{type_name}} and does not correspond to any of its enumerator values."); } -{% else %} - constructor(value : {{type_name}} | string); -{% endif %} +{%- endif %} + + static fromValue(value {%- if typescript %} : {{type_name}} | string {%- endif %}) {%- if typescript %} : {{type_name}}; {% else %} { + return new {{type_name}}({% if overrides_constructor -%} diplomatRuntime.exposeConstructor, {% endif -%} value); + } + {%- endif %} + get value() {% if typescript %}: string;{% else %}{ {%- if is_contiguous %} return [...{{type_name}}.#values.keys()][this.#value]; @@ -74,9 +77,4 @@ export class {{type_name}} { static {{variant_name}} {% if typescript -%} : {{type_name}} {%- else -%} = {{type_name}}.#objectValues[{{ variant.discriminant }}] {%- endif -%}; {%- endfor -%} -{%- for method in methods.methods %} - - {{ method|indent(4) }} -{%- endfor ~%} - {{~ methods.special_methods|indent(4) -}} -} \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/tool/templates/js/iterator.js.jinja b/tool/templates/js/iterator.js.jinja deleted file mode 100644 index b77279121..000000000 --- a/tool/templates/js/iterator.js.jinja +++ /dev/null @@ -1,11 +0,0 @@ -{%- if let Some(it) = iterator %} - -next() {% if typescript %}: IteratorResult<{{it}}>;{% else %}{ - const out = this.#iteratorNext(); - - return { - value: out, - done: out === null, - }; -}{% endif %} -{% endif -%} \ No newline at end of file diff --git a/tool/templates/js/js_class.js.jinja b/tool/templates/js/js_class.js.jinja new file mode 100644 index 000000000..3325e4a95 --- /dev/null +++ b/tool/templates/js/js_class.js.jinja @@ -0,0 +1,65 @@ +{% if !doc_str.is_empty() %} +/** {{doc_str}} +*/ +{% endif -%} +{%- let overrides_constructor = methods.special_methods.constructor.is_some() -%} + +{% block header_info %}{% endblock %} + +export class {{type_name}} { + {% block class_body %}{% endblock %} + + {%- for method in methods.methods -%} + + {#- Do not include the method in typescript if it is meant to be private: -#} + {%- if !method.method_decl.starts_with('#') || !typescript %} + + {{ method|indent(4) }} + {%- endif -%} +{%- endfor -%} + {%- if let Some(it) = methods.special_methods.iterator %} + + next() {% if typescript %}: IteratorResult<{{it}}>;{% else %}{ + const out = this.#iteratorNext(); + + return { + value: out, + done: out === null, + }; + }{%- endif -%} + {%- endif -%} + +{%- if show_default_ctor || overrides_constructor %} + + constructor( + {%- if let Some(ctor) = methods.special_methods.constructor %} + {%- for param in ctor.parameters -%} + {{- param.name -}} + {%- if typescript %}: {{ param.ty -}}{%- endif -%} + {%- if !loop.last -%}, {% endif -%} + {%- endfor -%} + {%- else -%} + {%- block internal_ctor_params -%}{%- endblock -%} + {%- endif -%} + ) {%- if typescript -%} ; {%- else %} { + {#- Quick and dirty way to access an exposed constructor if we don't want to provide the internalConstructor + symbol to our constructor (for instance, if we are a struct that only takes structObj as a parameter for the constructor) -#} + {%- if let Some(ctor) = methods.special_methods.constructor %} + if (arguments[0] === diplomatRuntime.exposeConstructor) { + return this.#internalConstructor(...Array.prototype.slice.call(arguments, 1)); + } else if (arguments[0] === diplomatRuntime.internalConstructor) { + {#- + If the first symbol is an internal constructor symbol, that means we can't possibly be looking for the internal + #defaultConstructor. So instead we just pass along all of the arguments to the internalConstructor. + #} + return this.#internalConstructor(...arguments); + } else { + return this.#defaultConstructor(...arguments); + } + {%- else %} + return this.#internalConstructor(...arguments) + {%- endif %} + } + {%- endif -%} +{%- endif %} +} \ No newline at end of file diff --git a/tool/templates/js/opaque.js.jinja b/tool/templates/js/opaque.js.jinja index de9017459..19d012720 100644 --- a/tool/templates/js/opaque.js.jinja +++ b/tool/templates/js/opaque.js.jinja @@ -1,17 +1,21 @@ -{%- if !docs.is_empty() %} -/** {{docs}} -*/ -{% endif -%} +{% extends "js/js_class.js.jinja" %} + +{% block header_info %} {%- if !typescript -%} const {{type_name}}_box_destroy_registry = new FinalizationRegistry((ptr) => { wasm.{{destructor}}(ptr); }); -{% endif -%} +{%- endif -%} +{%- endblock %} + +{% block internal_ctor_params -%} +symbol, ptr, selfEdge {%- for lifetime in lifetimes.all_lifetimes() %}, {{lifetimes.fmt_lifetime(lifetime)}}Edge{% endfor %} +{%- endblock %} -export class {{type_name}} { - {% if !typescript -%} +{% block class_body -%} + {%- if !typescript %} // Internal ptr reference: #ptr = null; @@ -22,7 +26,7 @@ export class {{type_name}} { #{{lifetimes.fmt_lifetime(lifetime)}}Edge = []; {%- endfor %} - constructor(symbol, ptr, selfEdge {%- for lifetime in lifetimes.all_lifetimes() %}, {{lifetimes.fmt_lifetime(lifetime)}}Edge{% endfor %}) { + #internalConstructor(symbol, ptr, selfEdge {%- for lifetime in lifetimes.all_lifetimes() %}, {{lifetimes.fmt_lifetime(lifetime)}}Edge{% endfor %}) { if (symbol !== diplomatRuntime.internalConstructor) { console.error("{{type_name}} is an Opaque type. You cannot call its constructor."); return; @@ -38,18 +42,13 @@ export class {{type_name}} { if (this.#selfEdge.length === 0) { {{type_name}}_box_destroy_registry.register(this, this.#ptr); } + + return this; } {%- endif %} - get ffiValue(){% if typescript %}: pointer;{% else %} { return this.#ptr; } {%- endif -%} - -{%- for method in methods.methods %} - - {{ method|indent(4) }} -{%- endfor ~%} - {{~ methods.special_methods|indent(4) -}} -} \ No newline at end of file +{% endblock %} \ No newline at end of file diff --git a/tool/templates/js/runtime.mjs b/tool/templates/js/runtime.mjs index fc8d591f3..6c0e2b3c0 100644 --- a/tool/templates/js/runtime.mjs +++ b/tool/templates/js/runtime.mjs @@ -1,5 +1,11 @@ -/** For internal Diplomat use when constructing opaques or structs. */ +/** For internal Diplomat use when constructing opaques or out structs. + * This is for when we're handling items that we don't want the user to touch, like an structure that's only meant to be output, or de-referencing a pointer we're handed from WASM. + */ export const internalConstructor = Symbol("constructor"); +/** For internal Diplomat use when accessing a from-fields/from-value constructor that's been overridden by a default constructor. + * If we want to pass in arguments without also passing in internalConstructor to avoid triggering some logic we don't want, we use exposeConstructor. + */ +export const exposeConstructor = Symbol("exposeConstructor"); export function readString8(wasm, ptr, len) { const buf = new Uint8Array(wasm.memory.buffer, ptr, len); diff --git a/tool/templates/js/struct.js.jinja b/tool/templates/js/struct.js.jinja index c95a425fb..d5c362fd3 100644 --- a/tool/templates/js/struct.js.jinja +++ b/tool/templates/js/struct.js.jinja @@ -1,8 +1,6 @@ -{%- if !docs.is_empty() %} -/** {{docs}} -*/ -{% endif -%} +{% extends "js/js_class.js.jinja" %} +{% block header_info %} {%- if typescript && !is_out -%} type {{type_name}}_obj = { {%- for field in fields %} @@ -11,27 +9,45 @@ type {{type_name}}_obj = { }; {% endif -%} +{% endblock %} -export class {{type_name}} { - {%- for field in fields %} +{% block internal_ctor_params -%} +structObj {%- if typescript %} : {{type_name}}_obj {%- endif -%} {%- if is_out && !typescript %}, internalConstructor{% endif -%} +{%- endblock %} + +{% block class_body -%} + {%- for field in fields -%} - {% if !typescript -%} + {%- if !typescript %} #{{field.field_name}}; - {% endif -%} + {% endif %} get {{field.field_name}}() {% if typescript %}: {{field.js_type_name}};{% else %} { return this.#{{field.field_name}}; - }{% endif %} - {% if mutable -%} + }{% endif -%} + {%- if mutable %} set {{field.field_name}}(value{% if typescript %}: {{field.js_type_name}});{% else %}){% endif %} {% if !typescript -%} { this.#{{field.field_name}} = value; } {%- endif -%} - {%- endif -%} - {%- endfor %} + {%- endif %} + {% endfor -%} + + {%~ if !is_out %} + /** Create `{{type_name}}` from an object that contains all of `{{type_name}}`s fields. + * Optional fields do not need to be included in the provided object. + */ + {# This function exists because some structs can override their default constructors. + # This exposes that original default constructor, and will ALWAYS exist to allow for consistent function calls to this kind of constructor. + # For instance, demo_gen uses this function instead of the constructor + -#} + static fromFields(structObj {%- if typescript %} : {{type_name}}_obj {%- endif -%}) {% if typescript %}: {{type_name}}; {%- else -%} { + return new {{type_name}}({% if overrides_constructor %}diplomatRuntime.exposeConstructor, {% endif -%} structObj); + } {%- endif %} + {% endif -%} {%- if !(typescript && is_out) %} - constructor(structObj - {%- if typescript %} : {{type_name}}_obj {%- endif -%} + {%- if !typescript %} + #internalConstructor(structObj {%- if is_out && !typescript %}, internalConstructor{% endif -%} ) {%- if typescript %};{% else %} { if (typeof structObj !== "object") { @@ -55,9 +71,12 @@ export class {{type_name}} { {%- endif %} } {%~ endfor %} + return this; } {%- endif -%} - {%- endif %} + {%- endif -%} + + {%- endif -%} {%- if !typescript %} {%~ if !fields.is_empty() %} @@ -101,7 +120,7 @@ export class {{type_name}} { return obj; } - return new {{type_name}}(obj); + return {{type_name}}.fromFields(obj); } _writeToArrayBuffer( @@ -128,7 +147,7 @@ export class {{type_name}} { if (internalConstructor !== diplomatRuntime.internalConstructor) { throw new Error("{{type_name}}._fromFFI is not meant to be called externally. Please use the default constructor."); } - var structObj = {}; + let structObj = {}; {%- if wraps_primitive && owns_wrapped_primitive %} structObj.{{fields.first().unwrap().field_name}} = primitiveValue; @@ -139,7 +158,7 @@ export class {{type_name}} { {%- endfor %} {%- endif %} - return new {{type_name}}(structObj, internalConstructor); + return new {{type_name}}({% if overrides_constructor %}diplomatRuntime.exposeConstructor, {% endif -%} structObj {%- if is_out %}, internalConstructor{% endif -%}); } {%- for l in lifetimes.all_lifetimes() %} @@ -167,11 +186,5 @@ export class {{type_name}} { }; {%- endfor -%} {%- endif -%} - {%- endif %} - -{%- for method in methods.methods %} - - {{ method|indent(4) }} -{%- endfor ~%} - {{~ methods.special_methods|indent(4) -}} -} \ No newline at end of file + {%- endif -%} +{% endblock %} \ No newline at end of file