From: Arik Sosman Date: Wed, 27 Jan 2021 09:21:17 +0000 (-0800) Subject: make typescript bindings rely on wasm type codec methods X-Git-Tag: v0.0.1~36^2 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=25679cbd668dff86345d5e1e8eeda6fbb7e5abfc;p=ldk-java make typescript bindings rely on wasm type codec methods --- diff --git a/genbindings.py b/genbindings.py index 3a655143..21ca0aee 100755 --- a/genbindings.py +++ b/genbindings.py @@ -361,175 +361,62 @@ write_c("static inline struct LDKThirtyTwoBytes ThirtyTwoBytes_clone(const struc java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: - def map_fn(line, re_match, ret_arr_len, c_call_string): - out_java.write("\t// " + line) - out_java.write("\tpublic static native ") - write_c(consts.c_fn_ty_pfx) - is_free = re_match.group(2).endswith("_free") - struct_meth = re_match.group(2).split("_")[0] + # Map a top-level function + def map_fn(line, re_match, ret_arr_len, c_call_string): - ret_info = type_mapping_generator.map_type(re_match.group(1), True, ret_arr_len, False, False) - write_c(ret_info.c_ty) - out_java.write(ret_info.java_ty) + # PARSING START + method_return_type = re_match.group(1) + method_name = re_match.group(2) + method_comma_separated_arguments = re_match.group(3) + method_arguments = method_comma_separated_arguments.split(',') - if ret_info.ret_conv is not None: - ret_conv_pfx, ret_conv_sfx = ret_info.ret_conv + is_free = method_name.endswith("_free") + struct_meth = method_name.split("_")[0] - out_java.write(" " + re_match.group(2) + "(") - write_c(" " + consts.c_fn_name_pfx + re_match.group(2).replace('_', '_1') + "(" + consts.c_fn_args_pfx) + return_type_info = type_mapping_generator.map_type(method_return_type, True, ret_arr_len, False, False) - arg_names = [] + argument_types = [] default_constructor_args = {} takes_self = False args_known = True - for idx, arg in enumerate(re_match.group(3).split(',')): - if idx != 0: - out_java.write(", ") - if arg != "void": - write_c(", ") - arg_conv_info = type_mapping_generator.map_type(arg, False, None, is_free, True) - if arg_conv_info.c_ty != "void": - write_c(arg_conv_info.c_ty + " " + arg_conv_info.arg_name) - out_java.write(arg_conv_info.java_ty + " " + arg_conv_info.arg_name) - if idx == 0 and arg_conv_info.java_hu_ty == struct_meth: + + for argument_index, argument in enumerate(method_arguments): + argument_conversion_info = type_mapping_generator.map_type(argument, False, None, is_free, True) + if argument_index == 0 and argument_conversion_info.java_hu_ty == struct_meth: takes_self = True - if arg_conv_info.arg_conv is not None and "Warning" in arg_conv_info.arg_conv: - if arg_conv_info.rust_obj in constructor_fns: + if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv: + if argument_conversion_info.rust_obj in constructor_fns: assert not is_free - for explode_arg in constructor_fns[arg_conv_info.rust_obj].split(','): + for explode_arg in constructor_fns[argument_conversion_info.rust_obj].split(','): explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True) if explode_arg_conv.c_ty == "void": # We actually want to handle this case, but for now its only used in NetGraphMsgHandler::new() # which ends up resulting in a redundant constructor - both without arguments for the NetworkGraph. args_known = False pass - if not arg_conv_info.arg_name in default_constructor_args: - default_constructor_args[arg_conv_info.arg_name] = [] - default_constructor_args[arg_conv_info.arg_name].append(explode_arg_conv) - arg_names.append(arg_conv_info) + if not argument_conversion_info.arg_name in default_constructor_args: + default_constructor_args[argument_conversion_info.arg_name] = [] + default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv) + argument_types.append(argument_conversion_info) - out_java_struct = None - if ("LDK" + struct_meth in opaque_structs or "LDK" + struct_meth in trait_structs) and not is_free: - out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a") - if not args_known: - out_java_struct.write("\t// Skipped " + re_match.group(2) + "\n") - out_java_struct.close() - out_java_struct = None - else: - meth_n = re_match.group(2)[len(struct_meth) + 1:] - if not takes_self: - out_java_struct.write("\tpublic static " + ret_info.java_hu_ty + " constructor_" + meth_n + "(") - else: - out_java_struct.write("\tpublic " + ret_info.java_hu_ty + " " + meth_n + "(") - for idx, arg in enumerate(arg_names): - if idx != 0: - if not takes_self or idx > 1: - out_java_struct.write(", ") - elif takes_self: - continue - if arg.java_ty != "void": - if arg.arg_name in default_constructor_args: - for explode_idx, explode_arg in enumerate(default_constructor_args[arg.arg_name]): - if explode_idx != 0: - out_java_struct.write(", ") - out_java_struct.write(explode_arg.java_hu_ty + " " + arg.arg_name + "_" + explode_arg.arg_name) - else: - out_java_struct.write(arg.java_hu_ty + " " + arg.arg_name) + has_out_java_struct = ("LDK" + struct_meth in opaque_structs or "LDK" + struct_meth in trait_structs) and not is_free + # PARSING END + out_java.write("\t// " + line) - out_java.write(");\n") - write_c(") {\n") - if out_java_struct is not None: - out_java_struct.write(") {\n") + (out_java_delta, out_c_delta, out_java_struct_delta) = consts.map_function(argument_types, c_call_string, is_free, method_name, return_type_info, struct_meth, default_constructor_args, takes_self, args_known, has_out_java_struct, type_mapping_generator) - for info in arg_names: - if info.arg_conv is not None: - write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n") + out_java.write(out_java_delta) + write_c(out_c_delta) + + if has_out_java_struct: + out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a") + out_java_struct.write(out_java_struct_delta) - if ret_info.ret_conv is not None: - write_c("\t" + ret_conv_pfx.replace('\n', '\n\t')) - elif ret_info.c_ty != "void": - write_c("\t" + ret_info.c_ty + " ret_val = ") - else: - write_c("\t") - if c_call_string is None: - write_c(re_match.group(2) + "(") - else: - write_c(c_call_string) - for idx, info in enumerate(arg_names): - if info.arg_conv_name is not None: - if idx != 0: - write_c(", ") - elif c_call_string is not None: - continue - write_c(info.arg_conv_name) - write_c(")") - if ret_info.ret_conv is not None: - write_c(ret_conv_sfx.replace('\n', '\n\t')) - else: - write_c(";") - for info in arg_names: - if info.arg_conv_cleanup is not None: - write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t")) - if ret_info.ret_conv is not None: - write_c("\n\treturn " + ret_info.ret_conv_name + ";") - elif ret_info.c_ty != "void": - write_c("\n\treturn ret_val;") - write_c("\n}\n\n") - if out_java_struct is not None: - out_java_struct.write("\t\t") - if ret_info.java_ty != "void": - out_java_struct.write(ret_info.java_ty + " ret = ") - out_java_struct.write("bindings." + re_match.group(2) + "(") - for idx, info in enumerate(arg_names): - if idx != 0: - out_java_struct.write(", ") - if idx == 0 and takes_self: - out_java_struct.write("this.ptr") - elif info.arg_name in default_constructor_args: - out_java_struct.write("bindings." + info.java_hu_ty + "_new(") - for explode_idx, explode_arg in enumerate(default_constructor_args[info.arg_name]): - if explode_idx != 0: - out_java_struct.write(", ") - expl_arg_name = info.arg_name + "_" + explode_arg.arg_name - if explode_arg.from_hu_conv is not None: - out_java_struct.write(explode_arg.from_hu_conv[0].replace(explode_arg.arg_name, expl_arg_name)) - else: - out_java_struct.write(expl_arg_name) - out_java_struct.write(")") - elif info.from_hu_conv is not None: - out_java_struct.write(info.from_hu_conv[0]) - else: - out_java_struct.write(info.arg_name) - out_java_struct.write(");\n") - if ret_info.to_hu_conv is not None: - if not takes_self: - out_java_struct.write("\t\t" + ret_info.to_hu_conv.replace("\n", "\n\t\t").replace("this", ret_info.to_hu_conv_name) + "\n") - else: - out_java_struct.write("\t\t" + ret_info.to_hu_conv.replace("\n", "\n\t\t") + "\n") - for idx, info in enumerate(arg_names): - if idx == 0 and takes_self: - pass - elif info.arg_name in default_constructor_args: - for explode_arg in default_constructor_args[info.arg_name]: - expl_arg_name = info.arg_name + "_" + explode_arg.arg_name - if explode_arg.from_hu_conv is not None and ret_info.to_hu_conv_name: - out_java_struct.write("\t\t" + explode_arg.from_hu_conv[1].replace(explode_arg.arg_name, expl_arg_name).replace("this", ret_info.to_hu_conv_name) + ";\n") - elif info.from_hu_conv is not None and info.from_hu_conv[1] != "": - if not takes_self and ret_info.to_hu_conv_name is not None: - out_java_struct.write("\t\t" + info.from_hu_conv[1].replace("this", ret_info.to_hu_conv_name) + ";\n") - else: - out_java_struct.write("\t\t" + info.from_hu_conv[1] + ";\n") - if ret_info.to_hu_conv_name is not None: - out_java_struct.write("\t\treturn " + ret_info.to_hu_conv_name + ";\n") - elif ret_info.java_ty != "void" and ret_info.rust_obj != "LDK" + struct_meth: - out_java_struct.write("\t\treturn ret;\n") - out_java_struct.write("\t}\n\n") - out_java_struct.close() def map_unitary_enum(struct_name, field_lines): with open(f"{sys.argv[3]}/enums/{struct_name}{consts.file_ext}", "w") as out_java_enum: @@ -1035,13 +922,14 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java: else: assert(line == "\n") - out_java.write("}\n") + out_java.write(consts.bindings_footer) for struct_name in opaque_structs: with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct: out_java_struct.write("}\n") for struct_name in trait_structs: with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct: out_java_struct.write("}\n") + with open(sys.argv[4], "w") as out_c: out_c.write(consts.c_file_pfx) out_c.write(consts.init_str()) diff --git a/java_strings.py b/java_strings.py index 587d8281..d9b7b4b7 100644 --- a/java_strings.py +++ b/java_strings.py @@ -49,6 +49,8 @@ public class bindings { """ + self.bindings_footer = "}\n" + self.common_base = """package org.ldk.structs; import java.util.LinkedList; class CommonBase { @@ -816,3 +818,151 @@ import java.util.Arrays; out_opaque_struct_human += ("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); }\n") out_opaque_struct_human += ("\t}\n\n") return out_opaque_struct_human + + + def map_function(self, argument_types, c_call_string, is_free, method_name, return_type_info, struct_meth, default_constructor_args, takes_self, args_known, has_out_java_struct: bool, type_mapping_generator): + out_java = "" + out_c = "" + out_java_struct = None + + out_java += ("\tpublic static native ") + out_c += (self.c_fn_ty_pfx) + out_c += (return_type_info.c_ty) + out_java += (return_type_info.java_ty) + if return_type_info.ret_conv is not None: + ret_conv_pfx, ret_conv_sfx = return_type_info.ret_conv + out_java += (" " + method_name + "(") + out_c += (" " + self.c_fn_name_pfx + method_name.replace('_', '_1') + "(" + self.c_fn_args_pfx) + + for idx, arg_conv_info in enumerate(argument_types): + if idx != 0: + out_java += (", ") + if arg_conv_info.c_ty != "void": + out_c += (", ") + if arg_conv_info.c_ty != "void": + out_c += (arg_conv_info.c_ty + " " + arg_conv_info.arg_name) + out_java += (arg_conv_info.java_ty + " " + arg_conv_info.arg_name) + + if has_out_java_struct: + out_java_struct = "" + if not args_known: + out_java_struct += ("\t// Skipped " + method_name + "\n") + has_out_java_struct = False + else: + meth_n = method_name[len(struct_meth) + 1:] + if not takes_self: + out_java_struct += ( + "\tpublic static " + return_type_info.java_hu_ty + " constructor_" + meth_n + "(") + else: + out_java_struct += ("\tpublic " + return_type_info.java_hu_ty + " " + meth_n + "(") + for idx, arg in enumerate(argument_types): + if idx != 0: + if not takes_self or idx > 1: + out_java_struct += (", ") + elif takes_self: + continue + if arg.java_ty != "void": + if arg.arg_name in default_constructor_args: + for explode_idx, explode_arg in enumerate(default_constructor_args[arg.arg_name]): + if explode_idx != 0: + out_java_struct += (", ") + out_java_struct += ( + explode_arg.java_hu_ty + " " + arg.arg_name + "_" + explode_arg.arg_name) + else: + out_java_struct += (arg.java_hu_ty + " " + arg.arg_name) + out_java += (");\n") + out_c += (") {\n") + if out_java_struct is not None: + out_java_struct += (") {\n") + for info in argument_types: + if info.arg_conv is not None: + out_c += ("\t" + info.arg_conv.replace('\n', "\n\t") + "\n") + if return_type_info.ret_conv is not None: + out_c += ("\t" + ret_conv_pfx.replace('\n', '\n\t')) + elif return_type_info.c_ty != "void": + out_c += ("\t" + return_type_info.c_ty + " ret_val = ") + else: + out_c += ("\t") + if c_call_string is None: + out_c += (method_name + "(") + else: + out_c += (c_call_string) + for idx, info in enumerate(argument_types): + if info.arg_conv_name is not None: + if idx != 0: + out_c += (", ") + elif c_call_string is not None: + continue + out_c += (info.arg_conv_name) + out_c += (")") + if return_type_info.ret_conv is not None: + out_c += (ret_conv_sfx.replace('\n', '\n\t')) + else: + out_c += (";") + for info in argument_types: + if info.arg_conv_cleanup is not None: + out_c += ("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t")) + if return_type_info.ret_conv is not None: + out_c += ("\n\treturn " + return_type_info.ret_conv_name + ";") + elif return_type_info.c_ty != "void": + out_c += ("\n\treturn ret_val;") + out_c += ("\n}\n\n") + + if has_out_java_struct: + out_java_struct += ("\t\t") + if return_type_info.java_ty != "void": + out_java_struct += (return_type_info.java_ty + " ret = ") + out_java_struct += ("bindings." + method_name + "(") + for idx, info in enumerate(argument_types): + if idx != 0: + out_java_struct += (", ") + if idx == 0 and takes_self: + out_java_struct += ("this.ptr") + elif info.arg_name in default_constructor_args: + out_java_struct += ("bindings." + info.java_hu_ty + "_new(") + for explode_idx, explode_arg in enumerate(default_constructor_args[info.arg_name]): + if explode_idx != 0: + out_java_struct += (", ") + expl_arg_name = info.arg_name + "_" + explode_arg.arg_name + if explode_arg.from_hu_conv is not None: + out_java_struct += ( + explode_arg.from_hu_conv[0].replace(explode_arg.arg_name, expl_arg_name)) + else: + out_java_struct += (expl_arg_name) + out_java_struct += (")") + elif info.from_hu_conv is not None: + out_java_struct += (info.from_hu_conv[0]) + else: + out_java_struct += (info.arg_name) + out_java_struct += (");\n") + if return_type_info.to_hu_conv is not None: + if not takes_self: + out_java_struct += ("\t\t" + return_type_info.to_hu_conv.replace("\n", "\n\t\t").replace("this", + return_type_info.to_hu_conv_name) + "\n") + else: + out_java_struct += ("\t\t" + return_type_info.to_hu_conv.replace("\n", "\n\t\t") + "\n") + + for idx, info in enumerate(argument_types): + if idx == 0 and takes_self: + pass + elif info.arg_name in default_constructor_args: + for explode_arg in default_constructor_args[info.arg_name]: + expl_arg_name = info.arg_name + "_" + explode_arg.arg_name + if explode_arg.from_hu_conv is not None and return_type_info.to_hu_conv_name: + out_java_struct += ("\t\t" + explode_arg.from_hu_conv[1].replace(explode_arg.arg_name, + expl_arg_name).replace( + "this", return_type_info.to_hu_conv_name) + ";\n") + elif info.from_hu_conv is not None and info.from_hu_conv[1] != "": + if not takes_self and return_type_info.to_hu_conv_name is not None: + out_java_struct += ( + "\t\t" + info.from_hu_conv[1].replace("this", return_type_info.to_hu_conv_name) + ";\n") + else: + out_java_struct += ("\t\t" + info.from_hu_conv[1] + ";\n") + + if return_type_info.to_hu_conv_name is not None: + out_java_struct += ("\t\treturn " + return_type_info.to_hu_conv_name + ";\n") + elif return_type_info.java_ty != "void" and return_type_info.rust_obj != "LDK" + struct_meth: + out_java_struct += ("\t\treturn ret;\n") + out_java_struct += ("\t}\n\n") + + return (out_java, out_c, out_java_struct) diff --git a/lab/minimal.h b/lab/minimal.h new file mode 100644 index 00000000..37610007 --- /dev/null +++ b/lab/minimal.h @@ -0,0 +1,20 @@ +typedef struct LDKPublicKey { + uint8_t compressed_form[33]; +} LDKPublicKey; + +typedef struct LDKMessageSendEvent_LDKSendAcceptChannel_Body { + struct LDKPublicKey node_id; +} LDKMessageSendEvent_LDKSendAcceptChannel_Body; + +typedef struct LDKChannelKeys { + void *this_arg; + /** + * Gets the per-commitment point for a specific commitment number + * + * Note that the commitment number starts at (1 << 48) - 1 and counts backwards. + */ + struct LDKPublicKey (*get_per_commitment_point)(const void *this_arg, uint64_t idx); + void (*free)(void *this_arg); +} LDKChannelKeys; + +void ChannelDetails_set_remote_network_id(struct LDKPublicKey remote_public_key); diff --git a/typescript_strings.py b/typescript_strings.py index c9f181e2..5820e0a6 100644 --- a/typescript_strings.py +++ b/typescript_strings.py @@ -20,6 +20,14 @@ class Consts: uint64_t = ['number'], ) + self.wasm_decoding_map = dict( + int8_tArray = 'decodeArray' + ) + + self.wasm_encoding_map = dict( + int8_tArray = 'encodeArray', + ) + self.to_hu_conv_templates = dict( ptr = 'const {var_name}_hu_conv: {human_type} = new {human_type}(null, {var_name});', default = 'const {var_name}_hu_conv: {human_type} = new {human_type}(null, {var_name});', @@ -63,6 +71,8 @@ public static native long new_empty_slice_vec(); """ + self.bindings_footer = "" + self.common_base = """ export default class CommonBase { ptr: number; @@ -271,17 +281,95 @@ import * as bindings from '../bindings' // TODO: figure out location def wasm_import_header(self, target): if target == Target.NODEJS: return """ -const path = require('path').join(__dirname, 'bindings.wasm'); -const bytes = require('fs').readFileSync(path); -let imports = {}; -// add all exports to dictionary and move down? -// use `module.exports`? -// imports['./bindings.js'] = require('./bindings.js'); - -const wasmModule = new WebAssembly.Module(bytes); -const wasmInstance = new WebAssembly.Instance(wasmModule, imports); -// module.exports = wasmInstance.exports; +import * as fs from 'fs'; +const source = fs.readFileSync('./ldk.wasm'); + +const memory = new WebAssembly.Memory({initial: 256}); +const wasmModule = new WebAssembly.Module(source); + +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'}); + +imports.env["abort"] = function () { + console.error("ABORT"); +}; + +const wasmInstance = await WebAssembly.instantiate(wasmModule, imports) const wasm = wasmInstance.exports; + +// WASM CODEC + +const nextMultipleOfFour = (value: number) => { + return Math.ceil(value / 4) * 4; +} + +const encodeArray = (inputArray) => { + // TODO: (matt) is this correct, or should it go back to length * 4? + // const cArrayPointer = wasm.wasm_malloc(inputArray.length * 4); + const cArrayPointer = wasm.wasm_malloc(nextMultipleOfFour(inputArray.length)); + + const arrayMemoryView = new Uint32Array(memory.buffer, cArrayPointer, inputArray.length); + arrayMemoryView.set(inputArray); + return cArrayPointer; +} + +const decodeArray = (arrayPointer, free = true) => { + const arraySizeViewer = new Uint32Array( + memory.buffer, // value + arrayPointer, // offset + 1 // one int + ); + const arraySize = arraySizeViewer[0]; + const actualArrayViewer = new Uint32Array( + memory.buffer, // value + arrayPointer, // offset + arraySize + 1 + ); + const actualArray = actualArrayViewer.slice(1, arraySize + 1); + if (free) { + // wasm.free_array(arrayPointer); + wasm.wasm_free(arrayPointer); // TODO: check if passing *void still captures remaining values + } + return actualArray; +} + +const encodeString = (string) => { + // make malloc count divisible by 4 + const memoryNeed = nextMultipleOfFour(string.length + 1); + const stringPointer = wasm.wasm_malloc(memoryNeed); + const stringMemoryView = new Uint8Array( + memory.buffer, // value + stringPointer, // offset + string.length + 1 // length + ); + for (let i = 0; i < string.length; i++) { + stringMemoryView[i] = string.charCodeAt(i); + } + stringMemoryView[string.length] = 0; + return stringPointer; +} + +const decodeString = (stringPointer, free = true) => { + const memoryView = new Uint8Array(memory.buffer, stringPointer); + let cursor = 0; + let result = ''; + + while (memoryView[cursor] !== 0) { + result += String.fromCharCode(memoryView[cursor]); + cursor++; + } + + if (free) { + wasm.wasm_free(stringPointer); + } + + return result; +}; """ return '' @@ -748,3 +836,173 @@ const wasm = wasmInstance.exports; }} """ return out_opaque_struct_human + + def map_function(self, argument_types, c_call_string, is_free, method_name, return_type_info, struct_meth, default_constructor_args, takes_self, args_known, has_out_java_struct: bool, type_mapping_generator): + out_java = "" + out_c = "" + out_java_struct = None + + out_java += ("\tpublic static native ") + out_c += (self.c_fn_ty_pfx) + out_c += (return_type_info.c_ty) + out_java += (return_type_info.java_ty) + if return_type_info.ret_conv is not None: + ret_conv_pfx, ret_conv_sfx = return_type_info.ret_conv + out_java += (" " + method_name + "(") + out_c += (" " + self.c_fn_name_pfx + method_name.replace('_', '_1') + "(" + self.c_fn_args_pfx) + + method_argument_string = "" + native_call_argument_string = "" + for idx, arg_conv_info in enumerate(argument_types): + if idx != 0: + method_argument_string += (", ") + native_call_argument_string += ', ' + if arg_conv_info.c_ty != "void": + out_c += (", ") + if arg_conv_info.c_ty != "void": + out_c += (arg_conv_info.c_ty + " " + arg_conv_info.arg_name) + needs_encoding = arg_conv_info.c_ty in self.wasm_encoding_map + native_argument = arg_conv_info.arg_name + if needs_encoding: + converter = self.wasm_encoding_map[arg_conv_info.c_ty] + native_argument = f"{converter}({arg_conv_info.arg_name})" + method_argument_string += f"{arg_conv_info.arg_name}: {arg_conv_info.java_ty}" + native_call_argument_string += native_argument + + needs_decoding = return_type_info.c_ty in self.wasm_decoding_map + return_value = 'nativeResponseValue' + if needs_decoding: + converter = self.wasm_decoding_map[return_type_info.c_ty] + return_value = f"{converter}(nativeResponseValue)" + + out_java = f"""\texport function {method_name}({method_argument_string}): {return_type_info.java_ty} {{ + const nativeResponseValue = wasm.{method_name}({native_call_argument_string}); + return {return_value}; + \n\t}} + \n""" + + + + if has_out_java_struct: + out_java_struct = "" + if not args_known: + out_java_struct += ("\t// Skipped " + method_name + "\n") + has_out_java_struct = False + else: + meth_n = method_name[len(struct_meth) + 1:] + if not takes_self: + out_java_struct += ( + "\tpublic static " + return_type_info.java_hu_ty + " constructor_" + meth_n + "(") + else: + out_java_struct += ("\tpublic " + return_type_info.java_hu_ty + " " + meth_n + "(") + for idx, arg in enumerate(argument_types): + if idx != 0: + if not takes_self or idx > 1: + out_java_struct += (", ") + elif takes_self: + continue + if arg.java_ty != "void": + if arg.arg_name in default_constructor_args: + for explode_idx, explode_arg in enumerate(default_constructor_args[arg.arg_name]): + if explode_idx != 0: + out_java_struct += (", ") + out_java_struct += ( + explode_arg.java_hu_ty + " " + arg.arg_name + "_" + explode_arg.arg_name) + else: + out_java_struct += (arg.java_hu_ty + " " + arg.arg_name) + + out_c += (") {\n") + if out_java_struct is not None: + out_java_struct += (") {\n") + for info in argument_types: + if info.arg_conv is not None: + out_c += ("\t" + info.arg_conv.replace('\n', "\n\t") + "\n") + if return_type_info.ret_conv is not None: + out_c += ("\t" + ret_conv_pfx.replace('\n', '\n\t')) + elif return_type_info.c_ty != "void": + out_c += ("\t" + return_type_info.c_ty + " ret_val = ") + else: + out_c += ("\t") + if c_call_string is None: + out_c += (method_name + "(") + else: + out_c += (c_call_string) + for idx, info in enumerate(argument_types): + if info.arg_conv_name is not None: + if idx != 0: + out_c += (", ") + elif c_call_string is not None: + continue + out_c += (info.arg_conv_name) + out_c += (")") + if return_type_info.ret_conv is not None: + out_c += (ret_conv_sfx.replace('\n', '\n\t')) + else: + out_c += (";") + for info in argument_types: + if info.arg_conv_cleanup is not None: + out_c += ("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t")) + if return_type_info.ret_conv is not None: + out_c += ("\n\treturn " + return_type_info.ret_conv_name + ";") + elif return_type_info.c_ty != "void": + out_c += ("\n\treturn ret_val;") + out_c += ("\n}\n\n") + + if has_out_java_struct: + out_java_struct += ("\t\t") + if return_type_info.java_ty != "void": + out_java_struct += (return_type_info.java_ty + " ret = ") + out_java_struct += ("bindings." + method_name + "(") + for idx, info in enumerate(argument_types): + if idx != 0: + out_java_struct += (", ") + if idx == 0 and takes_self: + out_java_struct += ("this.ptr") + elif info.arg_name in default_constructor_args: + out_java_struct += ("bindings." + info.java_hu_ty + "_new(") + for explode_idx, explode_arg in enumerate(default_constructor_args[info.arg_name]): + if explode_idx != 0: + out_java_struct += (", ") + expl_arg_name = info.arg_name + "_" + explode_arg.arg_name + if explode_arg.from_hu_conv is not None: + out_java_struct += ( + explode_arg.from_hu_conv[0].replace(explode_arg.arg_name, expl_arg_name)) + else: + out_java_struct += (expl_arg_name) + out_java_struct += (")") + elif info.from_hu_conv is not None: + out_java_struct += (info.from_hu_conv[0]) + else: + out_java_struct += (info.arg_name) + out_java_struct += (");\n") + if return_type_info.to_hu_conv is not None: + if not takes_self: + out_java_struct += ("\t\t" + return_type_info.to_hu_conv.replace("\n", "\n\t\t").replace("this", + return_type_info.to_hu_conv_name) + "\n") + else: + out_java_struct += ("\t\t" + return_type_info.to_hu_conv.replace("\n", "\n\t\t") + "\n") + + for idx, info in enumerate(argument_types): + if idx == 0 and takes_self: + pass + elif info.arg_name in default_constructor_args: + for explode_arg in default_constructor_args[info.arg_name]: + expl_arg_name = info.arg_name + "_" + explode_arg.arg_name + if explode_arg.from_hu_conv is not None and return_type_info.to_hu_conv_name: + out_java_struct += ("\t\t" + explode_arg.from_hu_conv[1].replace(explode_arg.arg_name, + expl_arg_name).replace( + "this", return_type_info.to_hu_conv_name) + ";\n") + elif info.from_hu_conv is not None and info.from_hu_conv[1] != "": + if not takes_self and return_type_info.to_hu_conv_name is not None: + out_java_struct += ( + "\t\t" + info.from_hu_conv[1].replace("this", return_type_info.to_hu_conv_name) + ";\n") + else: + out_java_struct += ("\t\t" + info.from_hu_conv[1] + ";\n") + + if return_type_info.to_hu_conv_name is not None: + out_java_struct += ("\t\treturn " + return_type_info.to_hu_conv_name + ";\n") + elif return_type_info.java_ty != "void" and return_type_info.rust_obj != "LDK" + struct_meth: + out_java_struct += ("\t\treturn ret;\n") + out_java_struct += ("\t}\n\n") + + return (out_java, out_c, out_java_struct)