X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=typescript_strings.py;h=faa13d572d623a6b09d4dbba495ba473b5692203;hb=4dc5fc99fc92a6d0ea7e641a12dd0306838f8ae3;hp=be200406245e6b638e73296f0f6fc2a6f8989f41;hpb=ec1a09b7537270af77128e1b3ffd1fd7936daa1f;p=ldk-java diff --git a/typescript_strings.py b/typescript_strings.py index be200406..faa13d57 100644 --- a/typescript_strings.py +++ b/typescript_strings.py @@ -80,15 +80,37 @@ public static native long new_empty_slice_vec(); self.util_fn_sfx = "" self.common_base = """ - export default class CommonBase { - protected ptr: number; - protected ptrs_to: object[] = []; - protected constructor(ptr: number) { this.ptr = ptr; } - public _test_only_get_ptr(): number { return this.ptr; } - protected finalize() { - // TODO: finalize myself - } - } +function freer(f: () => void) { f() } +const finalizer = new FinalizationRegistry(freer); +function get_freeer(ptr: number, free_fn: (number) => void) { + return () => { + free_fn(ptr); + } +} + +export default class CommonBase { + protected ptr: number; + protected ptrs_to: object[] = []; + protected constructor(ptr: number, free_fn: (ptr: number) => void) { + this.ptr = ptr; + if (Number.isFinite(ptr) && ptr != 0){ + finalizer.register(this, get_freeer(ptr, free_fn)); + } + } + // In Java, protected means "any subclass can access fields on any other subclass'" + // In TypeScript, protected means "any subclass can access parent fields on instances of itself" + // To work around this, we add accessors for other instances' protected fields here. + protected static add_ref_from(holder: CommonBase, referent: object) { + holder.ptrs_to.push(referent); + } + protected static get_ptr_of(o: CommonBase) { + return o.ptr; + } + protected static set_null_skip_free(o: CommonBase) { + o.ptr = 0; + finalizer.unregister(o); + } +} """ self.c_file_pfx = """#include "js-wasm.h" @@ -281,9 +303,10 @@ void __attribute__((visibility("default"))) TS_free(uint32_t ptr) { self.c_version_file = "" - self.hu_struct_file_prefix = f""" -import CommonBase from './CommonBase'; + self.hu_struct_file_prefix = """ +import CommonBase from './CommonBase.mjs'; import * as bindings from '../bindings.mjs' +import * as InternalUtils from '../InternalUtils.mjs' """ self.c_fn_ty_pfx = "" @@ -295,6 +318,12 @@ import * as bindings from '../bindings.mjs' self.is_arr_some_check = ("", " != 0") self.get_native_arr_len_call = ("", "->arr_len") + with open(outdir + "/InternalUtils.mts", "w") as f: + f.write("export function check_arr_len(arr: Uint8Array, len: number): Uint8Array {\n") + f.write("\tif (arr.length != len) { throw new Error(\"Expected array of length \" + len + \"got \" + arr.length); }\n") + f.write("\treturn arr;\n") + f.write("}") + def release_native_arr_ptr_call(self, ty_info, arr_var, arr_ptr_var): return None def create_native_arr_call(self, arr_len, ty_info): @@ -339,15 +368,9 @@ import * as bindings from '../bindings.mjs' def wasm_import_header(self, target): res = """ -function freer(f: () => void) { f() } -const finalizer = new FinalizationRegistry(freer); -const memory = new WebAssembly.Memory({initial: 256}); - const imports: any = {}; imports.env = {}; -imports.env.memoryBase = 0; -imports.env.memory = memory; imports.env.tableBase = 0; imports.env.table = new WebAssembly.Table({initial: 4, element: 'anyfunc'}); @@ -414,16 +437,16 @@ const nextMultipleOfFour = (value: number) => { const encodeUint8Array = (inputArray) => { const cArrayPointer = wasm.TS_malloc(inputArray.length + 4); - const arrayLengthView = new Uint32Array(memory.buffer, cArrayPointer, 1); + const arrayLengthView = new Uint32Array(wasm.memory.buffer, cArrayPointer, 1); arrayLengthView[0] = inputArray.length; - const arrayMemoryView = new Uint8Array(memory.buffer, cArrayPointer + 4, inputArray.length); + const arrayMemoryView = new Uint8Array(wasm.memory.buffer, cArrayPointer + 4, inputArray.length); arrayMemoryView.set(inputArray); return cArrayPointer; } const encodeUint32Array = (inputArray) => { const cArrayPointer = wasm.TS_malloc((inputArray.length + 1) * 4); - const arrayMemoryView = new Uint32Array(memory.buffer, cArrayPointer, inputArray.length); + const arrayMemoryView = new Uint32Array(wasm.memory.buffer, cArrayPointer, inputArray.length); arrayMemoryView.set(inputArray, 1); arrayMemoryView[0] = inputArray.length; return cArrayPointer; @@ -431,7 +454,7 @@ const encodeUint32Array = (inputArray) => { const getArrayLength = (arrayPointer) => { const arraySizeViewer = new Uint32Array( - memory.buffer, // value + wasm.memory.buffer, // value arrayPointer, // offset 1 // one int ); @@ -440,7 +463,7 @@ const getArrayLength = (arrayPointer) => { const decodeUint8Array = (arrayPointer, free = true) => { const arraySize = getArrayLength(arrayPointer); const actualArrayViewer = new Uint8Array( - memory.buffer, // value + wasm.memory.buffer, // value arrayPointer + 4, // offset (ignoring length bytes) arraySize // uint8 count ); @@ -455,7 +478,7 @@ const decodeUint8Array = (arrayPointer, free = true) => { const decodeUint32Array = (arrayPointer, free = true) => { const arraySize = getArrayLength(arrayPointer); const actualArrayViewer = new Uint32Array( - memory.buffer, // value + wasm.memory.buffer, // value arrayPointer + 4, // offset (ignoring length bytes) arraySize // uint32 count ); @@ -473,7 +496,7 @@ const encodeString = (string) => { const memoryNeed = nextMultipleOfFour(string.length + 1); const stringPointer = wasm.TS_malloc(memoryNeed); const stringMemoryView = new Uint8Array( - memory.buffer, // value + wasm.memory.buffer, // value stringPointer, // offset string.length + 1 // length ); @@ -485,7 +508,7 @@ const encodeString = (string) => { } const decodeString = (stringPointer, free = true) => { - const memoryView = new Uint8Array(memory.buffer, stringPointer); + const memoryView = new Uint8Array(wasm.memory.buffer, stringPointer); let cursor = 0; let result = ''; @@ -508,6 +531,20 @@ const decodeString = (stringPointer, free = true) => { def var_decl_statement(self, ty_string, var_name, statement): return "const " + var_name + ": " + ty_string + " = " + statement + def get_ptr(self, var): + return "CommonBase.get_ptr_of(" + var + ")" + def set_null_skip_free(self, var): + return "CommonBase.set_null_skip_free(" + var + ");" + + def add_ref(self, holder, referent): + return "CommonBase.add_ref_from(" + holder + ", " + referent + ")" + + def obj_defined(self, struct_names, folder): + with open(self.outdir + "/index.mts", 'a') as index: + index.write(f"export * from './{folder}/{struct_names[0]}.mjs';\n") + with open(self.outdir + "/imports.mts.part", 'a') as imports: + imports.write(f"import {{ {', '.join(struct_names)} }} from '../{folder}/{struct_names[0]}.mjs';\n") + def native_c_unitary_enum_map(self, struct_name, variants, enum_doc_comment): out_c = "static inline LDK" + struct_name + " LDK" + struct_name + "_from_js(int32_t ord) {\n" out_c = out_c + "\tswitch (ord) {\n" @@ -541,6 +578,7 @@ const decodeString = (stringPointer, free = true) => { }} """ out_typescript_enum = f"export {{ {struct_name} }} from \"../bindings.mjs\";" + self.obj_defined([struct_name], "enums") return (out_c, out_typescript_enum, out_typescript) def c_unitary_enum_to_native_call(self, ty_info): @@ -656,48 +694,40 @@ const decodeString = (stringPointer, free = true) => { trait_constructor_arguments += ", " + suparg[1] out_typescript_human = f""" - {self.hu_struct_file_prefix} - - export class {struct_name.replace("LDK","")} extends CommonBase {{ - - bindings_instance?: bindings.{struct_name}; - - constructor(ptr?: number, arg?: bindings.{struct_name}{constructor_arguments}) {{ - if (Number.isFinite(ptr)) {{ - super(ptr); - this.bindings_instance = null; - }} else {{ - // TODO: private constructor instantiation - super(bindings.{struct_name}_new(arg{super_instantiator})); - this.ptrs_to.push(arg); - {pointer_to_adder} - }} - }} - - protected finalize() {{ - if (this.ptr != 0) {{ - bindings.{struct_name.replace("LDK","")}_free(this.ptr); - }} - super.finalize(); - }} - - static new_impl(arg: {struct_name.replace("LDK", "")}Interface{impl_constructor_arguments}): {struct_name.replace("LDK", "")} {{ - const impl_holder: {struct_name}Holder = new {struct_name}Holder(); - let structImplementation = {{ - // todo: in-line interface filling - {out_interface_implementation_overrides} - }}; - impl_holder.held = new {struct_name.replace("LDK", "")} (null, structImplementation{trait_constructor_arguments}); - }} - }} +{self.hu_struct_file_prefix} - export interface {struct_name.replace("LDK", "")}Interface {{ - {out_java_interface} - }} +{struct_name.replace("LDK","")} extends CommonBase {{ - class {struct_name}Holder {{ - held: {struct_name.replace("LDK", "")}; - }} + bindings_instance?: bindings.{struct_name}; + + constructor(ptr?: number, arg?: bindings.{struct_name}{constructor_arguments}) {{ + if (Number.isFinite(ptr)) {{ + super(ptr, bindings.{struct_name.replace("LDK","")}_free); + this.bindings_instance = null; + }} else {{ + // TODO: private constructor instantiation + super(bindings.{struct_name}_new(arg{super_instantiator})); + this.ptrs_to.push(arg); + {pointer_to_adder} + }} + }} + + static new_impl(arg: {struct_name.replace("LDK", "")}Interface{impl_constructor_arguments}): {struct_name.replace("LDK", "")} {{ + const impl_holder: {struct_name}Holder = new {struct_name}Holder(); + let structImplementation = {{ + // todo: in-line interface filling + {out_interface_implementation_overrides} + }}; + impl_holder.held = new {struct_name.replace("LDK", "")} (null, structImplementation{trait_constructor_arguments}); + }} + + export interface {struct_name.replace("LDK", "")}Interface {{ + {out_java_interface} + }} + + class {struct_name}Holder {{ + held: {struct_name.replace("LDK", "")}; + }} """ out_typescript_bindings += "\t\texport interface " + struct_name + " {\n" @@ -894,12 +924,8 @@ const decodeString = (stringPointer, free = true) => { out_java_enum += (self.hu_struct_file_prefix) java_hu_class = "" - java_hu_class += "export default class " + java_hu_type + " extends CommonBase {\n" - java_hu_class += "\tprotected constructor(_dummy: object, ptr: number) { super(ptr); }\n" - java_hu_class += "\tprotected finalize() {\n" - java_hu_class += "\t\tsuper.finalize();\n" - java_hu_class += "\t\tif (this.ptr != 0) { bindings." + java_hu_type + "_free(this.ptr); }\n" - java_hu_class += "\t}\n" + java_hu_class += "export class " + java_hu_type + " extends CommonBase {\n" + java_hu_class += "\tprotected constructor(_dummy: object, ptr: number) { super(ptr, bindings." + bindings_type + "_free); }\n" java_hu_class += "\t/* @internal */\n" java_hu_class += f"\tpublic static constr_from_ptr(ptr: number): {java_hu_type} {{\n" java_hu_class += f"\t\tconst raw_val: bindings.{struct_name} = bindings." + struct_name + "_ref_from_ptr(ptr);\n" @@ -964,42 +990,89 @@ const decodeString = (stringPointer, free = true) => { out_c += ("\t}\n}\n") out_java_enum += java_hu_class self.struct_file_suffixes[java_hu_type] = java_hu_subclasses + self.obj_defined([java_hu_type], "structs") return (out_java, out_java_enum, out_c) def map_opaque_struct(self, struct_name, struct_doc_comment): implementations = "" method_header = "" if struct_name.startswith("LDKLocked"): - implementations += "implements AutoCloseable " - method_header = """ - public close() { -""" - else: - method_header = """ - protected finalize() { - super.finalize(); -""" + return "NOT IMPLEMENTED" - out_opaque_struct_human = f""" - {self.hu_struct_file_prefix} + hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple").replace("LDK", "") + out_opaque_struct_human = f"""{self.hu_struct_file_prefix} - export default class {struct_name.replace("LDK","")} extends CommonBase {implementations}{{ - /* @internal */ - public constructor(_dummy: object, ptr: number) {{ - super(ptr); - }} +export class {hu_name} extends CommonBase {implementations}{{ + /* @internal */ + public constructor(_dummy: object, ptr: number) {{ + super(ptr, bindings.{struct_name.replace("LDK","")}_free); + }} - {method_header} - if (this.ptr != 0) {{ - bindings.{struct_name.replace("LDK","")}_free(this.ptr); - }} - }} """ + self.obj_defined([hu_name], "structs") return out_opaque_struct_human def map_tuple(self, struct_name): return self.map_opaque_struct(struct_name, "A Tuple") + def map_result(self, struct_name, res_map, err_map): + human_ty = struct_name.replace("LDKCResult", "Result") + + suffixes = f"export class {human_ty}_OK extends {human_ty} {{\n" + if res_map.java_hu_ty != "void": + suffixes += "\tpublic res: " + res_map.java_hu_ty + ";\n" + suffixes += f""" + /* @internal */ + public constructor(_dummy: object, ptr: number) {{ + super(_dummy, ptr); +""" + if res_map.java_hu_ty == "void": + pass + elif res_map.to_hu_conv is not None: + suffixes += "\t\tconst res: " + res_map.java_ty + " = bindings." + struct_name.replace("LDK", "") + "_get_ok(ptr);\n" + suffixes += "\t\t" + res_map.to_hu_conv.replace("\n", "\n\t\t") + suffixes += "\n\t\tthis.res = " + res_map.to_hu_conv_name + ";\n" + else: + suffixes += "\t\tthis.res = bindings." + struct_name.replace("LDK", "") + "_get_ok(ptr);\n" + suffixes += "\t}\n}\n" + + suffixes += f"export class {human_ty}_Err extends {human_ty} {{\n" + if err_map.java_hu_ty != "void": + suffixes += "\tpublic err: " + err_map.java_hu_ty + ";\n" + suffixes += f""" + /* @internal */ + public constructor(_dummy: object, ptr: number) {{ + super(_dummy, ptr); +""" + if err_map.java_hu_ty == "void": + pass + elif err_map.to_hu_conv is not None: + suffixes += "\t\tconst err: " + err_map.java_ty + " = bindings." + struct_name.replace("LDK", "") + "_get_err(ptr);\n" + suffixes += "\t\t" + err_map.to_hu_conv.replace("\n", "\n\t\t") + suffixes += "\n\t\tthis.err = " + err_map.to_hu_conv_name + ";\n" + else: + suffixes += "\t\tthis.err = bindings." + struct_name.replace("LDK", "") + "_get_err(ptr);\n" + suffixes += "\t}\n}" + + self.struct_file_suffixes[human_ty] = suffixes + self.obj_defined([human_ty], "structs") + + return f"""{self.hu_struct_file_prefix} + +export class {human_ty} extends CommonBase {{ + protected constructor(_dummy: object, ptr: number) {{ + super(ptr, bindings.{struct_name.replace("LDK","")}_free); + }} + /* @internal */ + public static constr_from_ptr(ptr: number): {human_ty} {{ + if (bindings.{struct_name.replace("LDK", "")}_is_ok(ptr)) {{ + return new {human_ty}_OK(null, ptr); + }} else {{ + return new {human_ty}_Err(null, ptr); + }} + }} +""" + def fn_call_body(self, method_name, return_c_ty, return_java_ty, method_argument_string, native_call_argument_string): has_return_value = return_c_ty != 'void' needs_decoding = return_c_ty in self.wasm_decoding_map