X-Git-Url: http://git.bitcoin.ninja/index.cgi?p=ldk-java;a=blobdiff_plain;f=typescript_strings.py;h=625716806f5f15c516286d0ac8ac7a9389151ca8;hp=46a2991c9f83f355b1c438247eb8ca12e802e55d;hb=HEAD;hpb=2056a98d21238f0761b5ed11c264cdc5bbffab64 diff --git a/typescript_strings.py b/typescript_strings.py index 46a2991c..9704a48f 100644 --- a/typescript_strings.py +++ b/typescript_strings.py @@ -17,10 +17,13 @@ class Consts: self.function_ptr_counter = 0 self.function_ptrs = {} self.c_type_map = dict( + bool = ['boolean', 'boolean', 'XXX'], uint8_t = ['number', 'number', 'Uint8Array'], uint16_t = ['number', 'number', 'Uint16Array'], uint32_t = ['number', 'number', 'Uint32Array'], + int64_t = ['bigint', 'bigint', 'BigInt64Array'], uint64_t = ['bigint', 'bigint', 'BigUint64Array'], + double = ['number', 'number', 'Float64Array'], ) self.java_type_map = dict( String = "number" @@ -125,8 +128,8 @@ async function finishInitializeWasm(wasmInstance: WebAssembly.Instance) { isWasmInitialized = true; } -const fn_list = ["uuuuuu", "buuuuu", "bbuuuu", "bbbuuu", "bbbbuu", - "bbbbbb", "ubuubu", "ubuuuu", "ubbuuu", "uubuuu", "uububu"]; +const fn_list = ["uuuuuu", "buuuuu", "bbuuuu", "bbbuuu", "bbbbuu", "bbbbbu", + "bbbbbb", "ubuubu", "ubuuuu", "ubbuuu", "uubuuu", "uubbuu", "uububu", "ububuu", "uuuubu"]; /* @internal */ export async function initializeWasmFromUint8Array(wasmBinary: Uint8Array) { @@ -187,6 +190,16 @@ export function encodeUint8Array (inputArray: Uint8Array|null): number { return cArrayPointer; } /* @internal */ +export function encodeUint16Array (inputArray: Uint16Array|Array|null): number { + if (inputArray == null) return 0; + const cArrayPointer = wasm.TS_malloc((inputArray.length + 4) * 2); + const arrayLengthView = new BigUint64Array(wasm.memory.buffer, cArrayPointer, 1); + arrayLengthView[0] = BigInt(inputArray.length); + const arrayMemoryView = new Uint16Array(wasm.memory.buffer, cArrayPointer + 8, inputArray.length); + arrayMemoryView.set(inputArray); + return cArrayPointer; +} +/* @internal */ export function encodeUint32Array (inputArray: Uint32Array|Array|null): number { if (inputArray == null) return 0; const cArrayPointer = wasm.TS_malloc((inputArray.length + 2) * 4); @@ -212,6 +225,12 @@ export function check_arr_len(arr: Uint8Array|null, len: number): Uint8Array|nul return arr; } +/* @internal */ +export function check_16_arr_len(arr: Uint16Array|null, len: number): Uint16Array|null { + if (arr !== null && arr.length != len) { throw new Error("Expected array of length " + len + " got " + arr.length); } + return arr; +} + /* @internal */ export function getArrayLength(arrayPointer: number): number { const arraySizeViewer = new BigUint64Array(wasm.memory.buffer, arrayPointer, 1); @@ -247,15 +266,13 @@ export function decodeUint8Array (arrayPointer: number, free = true): Uint8Array } return actualArray; } -const decodeUint32Array = (arrayPointer: number, free = true) => { +/* @internal */ +export function decodeUint16Array (arrayPointer: number, free = true): Uint16Array { const arraySize = getArrayLength(arrayPointer); - const actualArrayViewer = new Uint32Array( - wasm.memory.buffer, // value - arrayPointer + 8, // offset (ignoring length bytes) - arraySize // uint32 count - ); + const actualArrayViewer = new Uint16Array(wasm.memory.buffer, arrayPointer + 8, arraySize); // Clone the contents, TODO: In the future we should wrap the Viewer in a class that // will free the underlying memory when it becomes unreachable instead of copying here. + // Note that doing so may have edge-case interactions with memory resizing (invalidating the buffer). const actualArray = actualArrayViewer.slice(0, arraySize); if (free) { wasm.TS_free(arrayPointer); @@ -346,14 +363,13 @@ export async function initializeWasmFromBinary(bin: Uint8Array) { await initializeWasmFromUint8Array(bin); } +export * from './structs/UtilMethods.mjs'; """) self.bindings_version_file = """export function get_ldk_java_bindings_version(): String { return ""; }""" - self.bindings_footer = "" - self.common_base = """ function freer(f: () => void) { f() } const finalizer = new FinalizationRegistry(freer); @@ -431,6 +447,33 @@ export class UnqualifiedError { }""" self.obj_defined(["TxOut"], "structs") + self.txin_defn = """export class TxIn extends CommonBase { + /** The witness in this input, in serialized form */ + public witness: Uint8Array; + /** The script_sig in this input */ + public script_sig: Uint8Array; + /** The transaction output's sequence number */ + public sequence: number; + /** The txid this input is spending */ + public previous_txid: Uint8Array; + /** The output index within the spent transaction of the output this input is spending */ + public previous_vout: number; + + /* @internal */ + public constructor(_dummy: null, ptr: bigint) { + super(ptr, bindings.TxIn_free); + this.witness = bindings.decodeUint8Array(bindings.TxIn_get_witness(ptr)); + this.script_sig = bindings.decodeUint8Array(bindings.TxIn_get_script_sig(ptr)); + this.sequence = bindings.TxIn_get_sequence(ptr); + this.previous_txid = bindings.decodeUint8Array(bindings.TxIn_get_previous_txid(ptr)); + this.previous_vout = bindings.TxIn_get_previous_vout(ptr); + } + public static constructor_new(witness: Uint8Array, script_sig: Uint8Array, sequence: number, previous_txid: Uint8Array, previous_vout: number): TxIn { + return new TxIn(null, bindings.TxIn_new(bindings.encodeUint8Array(witness), bindings.encodeUint8Array(script_sig), sequence, bindings.encodeUint8Array(previous_txid), previous_vout)); + } +}""" + self.obj_defined(["TxIn"], "structs") + self.scalar_defn = """export class BigEndianScalar extends CommonBase { /** The bytes of the scalar value, in big endian */ public scalar_bytes: Uint8Array; @@ -446,6 +489,28 @@ export class UnqualifiedError { }""" self.obj_defined(["BigEndianScalar"], "structs") + self.witness_program_defn = """export class WitnessProgram extends CommonBase { + /** The witness program bytes themselves */ + public program: Uint8Array; + /** The witness program version */ + public version: WitnessVersion; + + /* @internal */ + public constructor(_dummy: null, ptr: bigint) { + super(ptr, bindings.WitnessProgram_free); + this.program = bindings.decodeUint8Array(bindings.WitnessProgram_get_program(ptr)); + this.version = new WitnessVersion(bindings.WitnessProgram_get_version(ptr)); + } + public static constructor_new(program: Uint8Array, version: WitnessVersion): WitnessProgram { + if (program.length < 2 || program.length > 40) + throw new Error("WitnessProgram must be between 2 and 40 bytes long"); + if (version.getVal() == 0 && program.length != 20 && program.length != 32) + throw new Error("WitnessProgram for version 0 must be between either 20 or 30 bytes"); + return new WitnessProgram(null, bindings.WitnessProgram_new(version.getVal(), bindings.encodeUint8Array(program))); + } +}""" + self.obj_defined(["WitnessProgram"], "structs") + self.c_file_pfx = """#include "js-wasm.h" #include #include @@ -644,6 +709,7 @@ _Static_assert(sizeof(void*) == 4, "Pointers mut be 32 bits"); DECL_ARR_TYPE(int64_t, int64_t); DECL_ARR_TYPE(uint64_t, uint64_t); DECL_ARR_TYPE(int8_t, int8_t); +DECL_ARR_TYPE(int16_t, int16_t); DECL_ARR_TYPE(uint32_t, uint32_t); DECL_ARR_TYPE(void*, ptr); DECL_ARR_TYPE(char, char); @@ -697,6 +763,7 @@ import { CommonBase, UInt5, WitnessVersion, UnqualifiedError } from './CommonBas import * as bindings from '../bindings.mjs' """ + self.hu_struct_file_suffix = "" self.util_fn_pfx = self.hu_struct_file_prefix + "\nexport class UtilMethods extends CommonBase {\n" self.util_fn_sfx = "}" self.c_fn_ty_pfx = "" @@ -707,26 +774,34 @@ import * as bindings from '../bindings.mjs' self.usize_c_ty = "uint32_t" self.usize_native_ty = "number" self.native_zero_ptr = "0n" - self.result_c_ty = "uint32_t" + self.unitary_enum_c_ty = "uint32_t" self.ptr_arr = "ptrArray" self.is_arr_some_check = ("", " != 0") self.get_native_arr_len_call = ("", "->arr_len") + def bindings_footer(self): + return "" + 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): if ty_info.c_ty == "ptrArray": - assert ty_info.rust_obj == "LDKCVec_U5Z" or (ty_info.subty is not None and ty_info.subty.c_ty.endswith("Array")) + assert ty_info.rust_obj == "LDKCVec_U5Z" or (ty_info.subty is not None and (ty_info.subty.c_ty.endswith("Array") or ty_info.subty.rust_obj == "LDKStr")) return "init_" + ty_info.c_ty + "(" + arr_len + ", __LINE__)" def set_native_arr_contents(self, arr_name, arr_len, ty_info): if ty_info.c_ty == "int8_tArray": return ("memcpy(" + arr_name + "->elems, ", ", " + arr_len + ")") + elif ty_info.c_ty == "int16_tArray": + return ("memcpy(" + arr_name + "->elems, ", ", " + arr_len + " * 2)") else: assert False def get_native_arr_contents(self, arr_name, dest_name, arr_len, ty_info, copy): - if ty_info.c_ty == "int8_tArray": + if ty_info.c_ty == "int8_tArray" or ty_info.c_ty == "int16_tArray": if copy: - return "memcpy(" + dest_name + ", " + arr_name + "->elems, " + arr_len + "); FREE(" + arr_name + ")" + byte_len = arr_len + if ty_info.c_ty == "int16_tArray": + byte_len = arr_len + " * 2" + return "memcpy(" + dest_name + ", " + arr_name + "->elems, " + byte_len + "); FREE(" + arr_name + ")" assert not copy if ty_info.c_ty == "ptrArray": return "(void*) " + arr_name + "->elems" @@ -746,11 +821,14 @@ import * as bindings from '../bindings.mjs' else: return "FREE(" + arr_name + ")" - def map_hu_array_elems(self, arr_name, conv_name, arr_ty, elem_ty): + def map_hu_array_elems(self, arr_name, conv_name, arr_ty, elem_ty, is_nullable): if elem_ty.rust_obj == "LDKU5": return arr_name + " != null ? bindings.uint5ArrToBytes(" + arr_name + ") : null" - assert elem_ty.c_ty == "uint64_t" or elem_ty.c_ty.endswith("Array") - return arr_name + " != null ? " + arr_name + ".map(" + conv_name + " => " + elem_ty.from_hu_conv[0] + ") : null" + assert elem_ty.c_ty == "uint64_t" or elem_ty.c_ty.endswith("Array") or elem_ty.rust_obj == "LDKStr" + if is_nullable: + return arr_name + " != null ? " + arr_name + ".map(" + conv_name + " => " + elem_ty.from_hu_conv[0] + ") : null" + else: + return arr_name + ".map(" + conv_name + " => " + elem_ty.from_hu_conv[0] + ")" def str_ref_to_native_call(self, var_name, str_len): return "str_ref_to_ts(" + var_name + ", " + str_len + ")" @@ -776,6 +854,8 @@ import * as bindings from '../bindings.mjs' return "bindings.getU64ArrayElem(" + arr_name + ", " + idx + ")" elif elem_ty.rust_obj == "LDKU5": return "bindings.getU8ArrayElem(" + arr_name + ", " + idx + ")" + elif elem_ty.rust_obj == "LDKStr": + return "bindings.getU32ArrayElem(" + arr_name + ", " + idx + ")" else: assert False def constr_hu_array(self, ty_info, arr_len): @@ -789,13 +869,17 @@ import * as bindings from '../bindings.mjs' if arr_ty.rust_obj == "LDKU128": return ("bindings.encodeUint128(" + inner + ")", "") if fixed_len is not None: - assert mapped_ty.c_ty == "int8_t" - inner = "bindings.check_arr_len(" + arr_name + ", " + fixed_len + ")" + if mapped_ty.c_ty == "int8_t": + inner = "bindings.check_arr_len(" + arr_name + ", " + fixed_len + ")" + elif mapped_ty.c_ty == "int16_t": + inner = "bindings.check_16_arr_len(" + arr_name + ", " + fixed_len + ")" if mapped_ty.c_ty.endswith("Array"): return ("bindings.encodeUint32Array(" + inner + ")", "") elif mapped_ty.c_ty == "uint8_t" or mapped_ty.c_ty == "int8_t": return ("bindings.encodeUint8Array(" + inner + ")", "") - elif mapped_ty.c_ty == "uint32_t": + elif mapped_ty.c_ty == "uint16_t" or mapped_ty.c_ty == "int16_t": + return ("bindings.encodeUint16Array(" + inner + ")", "") + elif mapped_ty.c_ty == "uint32_t" or mapped_ty.rust_obj == "LDKStr": return ("bindings.encodeUint32Array(" + inner + ")", "") elif mapped_ty.c_ty == "int64_t" or mapped_ty.c_ty == "uint64_t": return ("bindings.encodeUint64Array(" + inner + ")", "") @@ -809,6 +893,8 @@ import * as bindings from '../bindings.mjs' return "const " + conv_name + ": bigint = bindings.decodeUint128(" + arr_name + ");" elif mapped_ty.c_ty == "uint8_t" or mapped_ty.c_ty == "int8_t": return "const " + conv_name + ": Uint8Array = bindings.decodeUint8Array(" + arr_name + ");" + elif mapped_ty.c_ty == "uint16_t" or mapped_ty.c_ty == "int16_t": + return "const " + conv_name + ": Uint16Array = bindings.decodeUint16Array(" + arr_name + ");" elif mapped_ty.c_ty == "uint64_t" or mapped_ty.c_ty == "int64_t": return "const " + conv_name + ": bigint[] = bindings.decodeUint64Array(" + arr_name + ");" else: @@ -898,7 +984,6 @@ export enum {struct_name} {{ for var in flattened_field_var_conversions: if isinstance(var, ConvInfo): impl_constructor_arguments += f", {var.arg_name}: {var.java_hu_ty}" - super_instantiator += first_to_lower(var.arg_name) + ", " if var.from_hu_conv is not None: bindings_instantiator += ", " + var.from_hu_conv[0] if var.from_hu_conv[1] != "": @@ -907,7 +992,6 @@ export enum {struct_name} {{ bindings_instantiator += ", " + first_to_lower(var.arg_name) else: bindings_instantiator += ", " + first_to_lower(var[1]) + ".instance_idx!" - super_instantiator += first_to_lower(var[1]) + "_impl, " pointer_to_adder += "\t\timpl_holder.held.ptrs_to.push(" + first_to_lower(var[1]) + ");\n" impl_constructor_arguments += f", {first_to_lower(var[1])}_impl: {var[0].replace('LDK', '')}Interface" @@ -917,12 +1001,21 @@ export enum {struct_name} {{ if isinstance(var, ConvInfo): trait_constructor_arguments += ", " + var.arg_name else: - super_constructor_statements += "\t\tconst " + first_to_lower(var[1]) + " = " + var[1] + ".new_impl(" + super_instantiator + ");\n" + super_constructor_statements += "\t\tconst " + first_to_lower(var[1]) + " = " + var[1] + ".new_impl(" + first_to_lower(var[1]) + "_impl" + super_instantiator = "" + for suparg in var[2]: + if isinstance(suparg, ConvInfo): + super_instantiator += ", " + suparg.arg_name + else: + super_instantiator += ", " + first_to_lower(suparg[1]) + "_impl" + super_constructor_statements += super_instantiator + ");\n" trait_constructor_arguments += ", " + first_to_lower(var[1]) + ".instance_idx!" for suparg in var[2]: if isinstance(suparg, ConvInfo): trait_constructor_arguments += ", " + suparg.arg_name else: + # Blindly assume that we can just strip the first arg to build the args for the supertrait + super_constructor_statements += "\t\tconst " + first_to_lower(suparg[1]) + " = " + suparg[1] + ".new_impl(" + super_instantiator.split(", ", 1)[1] + ");\n" trait_constructor_arguments += ", " + suparg[1] # BUILD INTERFACE METHODS @@ -1107,7 +1200,7 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_c = out_c + arg_info.ret_conv[1].replace('\n', '\n\t') + "\n" fn_suffix = "" - assert len(fn_line.args_ty) < 6 + assert len(fn_line.args_ty) < 7 for arg_info in fn_line.args_ty: if arg_info.c_ty == "uint64_t" or arg_info.c_ty == "int64_t": fn_suffix += "b" @@ -1151,9 +1244,9 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_c = out_c + "static void " + struct_name + "_JCalls_cloned(" + struct_name + "* new_obj) {\n" out_c = out_c + "\t" + struct_name + "_JCalls *j_calls = (" + struct_name + "_JCalls*) new_obj->this_arg;\n" out_c = out_c + "\tatomic_fetch_add_explicit(&j_calls->refcnt, 1, memory_order_release);\n" - for var in field_var_conversions: + for var in flattened_field_var_conversions: if not isinstance(var, ConvInfo): - out_c = out_c + "\tatomic_fetch_add_explicit(&j_calls->" + var[1] + "->refcnt, 1, memory_order_release);\n" + out_c = out_c + "\tatomic_fetch_add_explicit(&j_calls->" + var[2].replace(".", "->") + "->refcnt, 1, memory_order_release);\n" out_c = out_c + "}\n" out_c = out_c + "static inline " + struct_name + " " + struct_name + "_init (JSValue o" @@ -1204,7 +1297,7 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_c = out_c + "\t};\n" for var in flattened_field_var_conversions: if not isinstance(var, ConvInfo): - out_c = out_c + "\tcalls->" + var[1] + " = ret." + var[1] + ".this_arg;\n" + out_c = out_c + "\tcalls->" + var[1] + " = ret." + var[2] + ".this_arg;\n" out_c = out_c + "\treturn ret;\n" out_c = out_c + "}\n" @@ -1294,7 +1387,7 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_c += "\t" + struct_name + " *obj = (" + struct_name + "*)untag_ptr(ptr);\n" out_c += f"\tassert(obj->tag == {struct_name}_{var.var_name});\n" if field_map.ret_conv is not None: - out_c += ("\t\t\t" + field_map.ret_conv[0].replace("\n", "\n\t\t\t")) + out_c += ("\t" + field_map.ret_conv[0].replace("\n", "\n\t")) if var.tuple_variant: out_c += "obj->" + camel_to_snake(var.var_name) else: @@ -1314,10 +1407,9 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ return (out_java, out_java_enum, out_c) def map_opaque_struct(self, struct_name, struct_doc_comment): - implementations = "" method_header = "" - hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple").replace("LDK", "") + hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple").replace("LDKC4Tuple", "FourTuple").replace("LDK", "") out_opaque_struct_human = f"{self.hu_struct_file_prefix}" constructor_body = "super(ptr, bindings." + struct_name.replace("LDK","") + "_free);" extra_docs = "" @@ -1336,7 +1428,7 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ /**{extra_docs} * {formatted_doc_comment} */ -export class {hu_name} extends CommonBase {implementations}{{ +export class {hu_name} extends CommonBase {{ /* @internal */ public constructor(_dummy: null, ptr: bigint) {{ {constructor_body} @@ -1600,14 +1692,21 @@ js_invoke = function(obj_ptr: number, fn_id: number, arg1: bigint|number, arg2: bindings.write(f"\t\tcase {str(f)}: fn = Object.getOwnPropertyDescriptor(obj, \"{self.function_ptrs[f][1]}\"); break;\n") bindings.write("""\t\tdefault: - console.error("Got unknown function call from C!"); - throw new Error("Got unknown function call from C!"); + console.error("Got unknown function call with id " + fn_id + " from C!"); + throw new Error("Got unknown function call with id " + fn_id + " from C!"); } if (fn == null || fn == undefined) { - console.error("Got function call on incorrect JS object!"); - throw new Error("Got function call on incorrect JS object!"); + console.error("Got function call with id " + fn_id + " on incorrect JS object: " + obj); + throw new Error("Got function call with id " + fn_id + " on incorrect JS object: " + obj); + } + var ret; + try { + ret = fn.value.bind(obj)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + } catch (e) { + console.error("Got an exception calling function with id " + fn_id + "! This is fatal."); + console.error(e); + throw e; } - const ret = fn.value.bind(obj)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); if (ret === undefined || ret === null) return BigInt(0); return BigInt(ret); }""")