Somewhat redundant changes (new file_ext, arg parse, etc)
[ldk-java] / genbindings.py
1 #!/usr/bin/env python3
2 import sys, re
3
4 import config
5 from config import Language
6 import os
7
8 configuration = config.setup()
9
10 output_language = configuration.language
11 if output_language == Language.Java:
12     from java_strings import Consts
13 elif output_language == Language.TypeScript:
14     from typescript_strings import Consts
15 else:
16     print("Only java or typescript can be set for lang")
17     sys.exit(1)
18
19 consts = Consts(configuration.debug)
20
21 path_to_lightning_header = configuration.lightning_h_path
22 path_to_output_blob = configuration.output_blob_path
23 path_to_bindings_directory = configuration.bindings_output_directory_path
24 path_to_c_file = configuration.output_c_path
25
26
27
28
29
30 from bindingstypes import *
31
32 c_file = ""
33 def write_c(s):
34     global c_file
35     c_file += s
36
37 def camel_to_snake(s):
38     # Convert camel case to snake case, in a way that appears to match cbindgen
39     con = "_"
40     ret = ""
41     lastchar = ""
42     lastund = False
43     for char in s:
44         if lastchar.isupper():
45             if not char.isupper() and not lastund:
46                 ret = ret + "_"
47                 lastund = True
48             else:
49                 lastund = False
50             ret = ret + lastchar.lower()
51         else:
52             ret = ret + lastchar
53             if char.isupper() and not lastund:
54                 ret = ret + "_"
55                 lastund = True
56             else:
57                 lastund = False
58         lastchar = char
59         if char.isnumeric():
60             lastund = True
61     return (ret + lastchar.lower()).strip("_")
62
63
64 def recursiveOpenFile(path, *args):
65     output_directory_path = os.path.dirname(path)
66     if not os.path.isdir(output_directory_path):
67         os.makedirs(output_directory_path)
68     return open(path, *args)
69
70
71 unitary_enums = set()
72 complex_enums = set()
73 opaque_structs = set()
74 trait_structs = set()
75 result_types = set()
76 tuple_types = {}
77
78 var_is_arr_regex = re.compile("\(\*([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
79 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
80 java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
81 def java_c_types(fn_arg, ret_arr_len):
82     fn_arg = fn_arg.strip()
83     if fn_arg.startswith("MUST_USE_RES "):
84         fn_arg = fn_arg[13:]
85     is_const = False
86     if fn_arg.startswith("const "):
87         fn_arg = fn_arg[6:]
88         is_const = True
89     if fn_arg.startswith("struct "):
90         fn_arg = fn_arg[7:]
91     if fn_arg.startswith("enum "):
92         fn_arg = fn_arg[5:]
93     fn_arg = fn_arg.replace("NONNULL_PTR", "")
94
95     is_ptr = False
96     take_by_ptr = False
97     rust_obj = None
98     arr_access = None
99     java_hu_ty = None
100     if fn_arg.startswith("LDKThirtyTwoBytes"):
101         fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
102         assert var_is_arr_regex.match(fn_arg[8:])
103         rust_obj = "LDKThirtyTwoBytes"
104         arr_access = "data"
105     elif fn_arg.startswith("LDKPublicKey"):
106         fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
107         assert var_is_arr_regex.match(fn_arg[8:])
108         rust_obj = "LDKPublicKey"
109         arr_access = "compressed_form"
110     elif fn_arg.startswith("LDKSecretKey"):
111         fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
112         assert var_is_arr_regex.match(fn_arg[8:])
113         rust_obj = "LDKSecretKey"
114         arr_access = "bytes"
115     elif fn_arg.startswith("LDKSignature"):
116         fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
117         assert var_is_arr_regex.match(fn_arg[8:])
118         rust_obj = "LDKSignature"
119         arr_access = "compact_form"
120     elif fn_arg.startswith("LDKThreeBytes"):
121         fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
122         assert var_is_arr_regex.match(fn_arg[8:])
123         rust_obj = "LDKThreeBytes"
124         arr_access = "data"
125     elif fn_arg.startswith("LDKFourBytes"):
126         fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
127         assert var_is_arr_regex.match(fn_arg[8:])
128         rust_obj = "LDKFourBytes"
129         arr_access = "data"
130     elif fn_arg.startswith("LDKSixteenBytes"):
131         fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
132         assert var_is_arr_regex.match(fn_arg[8:])
133         rust_obj = "LDKSixteenBytes"
134         arr_access = "data"
135     elif fn_arg.startswith("LDKTenBytes"):
136         fn_arg = "uint8_t (*" + fn_arg[12:] + ")[10]"
137         assert var_is_arr_regex.match(fn_arg[8:])
138         rust_obj = "LDKTenBytes"
139         arr_access = "data"
140     elif fn_arg.startswith("LDKu8slice"):
141         fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
142         assert var_is_arr_regex.match(fn_arg[8:])
143         rust_obj = "LDKu8slice"
144         arr_access = "data"
145     elif fn_arg.startswith("LDKCVec_u8Z"):
146         fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
147         rust_obj = "LDKCVec_u8Z"
148         assert var_is_arr_regex.match(fn_arg[8:])
149         arr_access = "data"
150     elif fn_arg.startswith("LDKTransaction"):
151         fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
152         rust_obj = "LDKTransaction"
153         assert var_is_arr_regex.match(fn_arg[8:])
154         arr_access = "data"
155     elif fn_arg.startswith("LDKCVec_"):
156         is_ptr = False
157         if "*" in fn_arg:
158             fn_arg = fn_arg.replace("*", "")
159             is_ptr = True
160
161         tyn = fn_arg[8:].split(" ")
162         assert tyn[0].endswith("Z")
163         if tyn[0] == "u64Z":
164             new_arg = "uint64_t"
165         else:
166             new_arg = "LDK" + tyn[0][:-1]
167         for a in tyn[1:]:
168             new_arg = new_arg + " " + a
169         res = java_c_types(new_arg, ret_arr_len)
170         if res is None:
171             assert java_c_types_none_allowed
172             return None
173         if is_ptr:
174             res.pass_by_ref = True
175         if res.is_native_primitive or res.passed_as_ptr:
176             return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=res.java_ty + "[]", java_hu_ty=res.java_hu_ty + "[]",
177                 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr, is_const=is_const,
178                 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
179         else:
180             return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=res.java_ty + "[]", java_hu_ty=res.java_hu_ty + "[]",
181                 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr, is_const=is_const,
182                 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
183
184     is_primitive = False
185     arr_len = None
186     if fn_arg.startswith("void"):
187         java_ty = "void"
188         c_ty = "void"
189         fn_ty_arg = "V"
190         fn_arg = fn_arg[4:].strip()
191         is_primitive = True
192     elif fn_arg.startswith("bool"):
193         java_ty = "boolean"
194         c_ty = "jboolean"
195         fn_ty_arg = "Z"
196         fn_arg = fn_arg[4:].strip()
197         is_primitive = True
198     elif fn_arg.startswith("uint8_t"):
199         java_ty = "byte"
200         c_ty = "int8_t"
201         fn_ty_arg = "B"
202         fn_arg = fn_arg[7:].strip()
203         is_primitive = True
204     elif fn_arg.startswith("uint16_t"):
205         java_ty = "short"
206         c_ty = "jshort"
207         fn_ty_arg = "S"
208         fn_arg = fn_arg[8:].strip()
209         is_primitive = True
210     elif fn_arg.startswith("uint32_t"):
211         java_ty = "int"
212         c_ty = "int32_t"
213         fn_ty_arg = "I"
214         fn_arg = fn_arg[8:].strip()
215         is_primitive = True
216     elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
217         # TODO: uintptr_t is arch-dependent :(
218         java_ty = "long"
219         c_ty = "int64_t"
220         fn_ty_arg = "J"
221         if fn_arg.startswith("uint64_t"):
222             fn_arg = fn_arg[8:].strip()
223         else:
224             fn_arg = fn_arg[9:].strip()
225         is_primitive = True
226     elif is_const and fn_arg.startswith("char *"):
227         java_ty = "String"
228         c_ty = "const char*"
229         fn_ty_arg = "Ljava/lang/String;"
230         fn_arg = fn_arg[6:].strip()
231     elif fn_arg.startswith("LDKStr"):
232         java_ty = "String"
233         c_ty = "jstring"
234         fn_ty_arg = "Ljava/lang/String;"
235         fn_arg = fn_arg[6:].strip()
236         arr_access = "chars"
237         arr_len = "len"
238     else:
239         ma = var_ty_regex.match(fn_arg)
240         if ma.group(1).strip() in unitary_enums:
241             java_ty = ma.group(1).strip()
242             c_ty = consts.result_c_ty
243             fn_ty_arg = "Lorg/ldk/enums/" + ma.group(1).strip() + ";"
244             fn_arg = ma.group(2).strip()
245             rust_obj = ma.group(1).strip()
246         elif ma.group(1).strip().startswith("LDKC2Tuple"):
247             c_ty = consts.ptr_c_ty
248             java_ty = consts.ptr_native_ty
249             java_hu_ty = "TwoTuple<"
250             if not ma.group(1).strip() in tuple_types:
251                 assert java_c_types_none_allowed
252                 return None
253             for idx, ty_info in enumerate(tuple_types[ma.group(1).strip()][0]):
254                 if idx != 0:
255                     java_hu_ty = java_hu_ty + ", "
256                 if ty_info.is_native_primitive:
257                     if ty_info.java_hu_ty == "int":
258                         java_hu_ty = java_hu_ty + "Integer" # Java concrete integer type is Integer, not Int
259                     else:
260                         java_hu_ty = java_hu_ty + ty_info.java_hu_ty.title() # If we're a primitive, capitalize the first letter
261                 else:
262                     java_hu_ty = java_hu_ty + ty_info.java_hu_ty
263             java_hu_ty = java_hu_ty + ">"
264             fn_ty_arg = "J"
265             fn_arg = ma.group(2).strip()
266             rust_obj = ma.group(1).strip()
267             take_by_ptr = True
268         elif ma.group(1).strip().startswith("LDKC3Tuple"):
269             c_ty = consts.ptr_c_ty
270             java_ty = consts.ptr_native_ty
271             java_hu_ty = "ThreeTuple<"
272             if not ma.group(1).strip() in tuple_types:
273                 assert java_c_types_none_allowed
274                 return None
275             for idx, ty_info in enumerate(tuple_types[ma.group(1).strip()][0]):
276                 if idx != 0:
277                     java_hu_ty = java_hu_ty + ", "
278                 if ty_info.is_native_primitive:
279                     if ty_info.java_hu_ty == "int":
280                         java_hu_ty = java_hu_ty + "Integer" # Java concrete integer type is Integer, not Int
281                     else:
282                         java_hu_ty = java_hu_ty + ty_info.java_hu_ty.title() # If we're a primitive, capitalize the first letter
283                 else:
284                     java_hu_ty = java_hu_ty + ty_info.java_hu_ty
285             java_hu_ty = java_hu_ty + ">"
286             fn_ty_arg = "J"
287             fn_arg = ma.group(2).strip()
288             rust_obj = ma.group(1).strip()
289             take_by_ptr = True
290         else:
291             c_ty = consts.ptr_c_ty
292             java_ty = consts.ptr_native_ty
293             java_hu_ty = ma.group(1).strip().replace("LDKCResult", "Result").replace("LDK", "")
294             fn_ty_arg = "J"
295             fn_arg = ma.group(2).strip()
296             rust_obj = ma.group(1).strip()
297             take_by_ptr = True
298
299     if fn_arg.startswith(" *") or fn_arg.startswith("*"):
300         fn_arg = fn_arg.replace("*", "").strip()
301         is_ptr = True
302         c_ty = consts.ptr_c_ty
303         java_ty = consts.ptr_native_ty
304         fn_ty_arg = "J"
305         is_primitive = False
306
307     var_is_arr = var_is_arr_regex.match(fn_arg)
308     if var_is_arr is not None or ret_arr_len is not None:
309         assert(not take_by_ptr)
310         assert(not is_ptr)
311         java_ty = java_ty + "[]"
312         c_ty = c_ty + "Array"
313         if var_is_arr is not None:
314             if var_is_arr.group(1) == "":
315                 return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
316                     passed_as_ptr=False, is_ptr=False, var_name="arg", arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False)
317             return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
318                 passed_as_ptr=False, is_ptr=False, var_name=var_is_arr.group(1), arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False)
319
320     if java_hu_ty is None:
321         java_hu_ty = java_ty
322     return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg=fn_ty_arg, c_ty=c_ty, passed_as_ptr=is_ptr or take_by_ptr,
323         is_const=is_const, is_ptr=is_ptr, var_name=fn_arg, arr_len=arr_len, arr_access=arr_access, is_native_primitive=is_primitive)
324
325 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
326 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
327 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
328 clone_fns = set()
329 constructor_fns = {}
330 c_array_class_caches = set()
331 with open(path_to_lightning_header) as in_h:
332     for line in in_h:
333         reg_fn = reg_fn_regex.match(line)
334         if reg_fn is not None:
335             if reg_fn.group(2).endswith("_clone"):
336                 clone_fns.add(reg_fn.group(2))
337             else:
338                 rty = java_c_types(reg_fn.group(1), None)
339                 if rty is not None and rty.rust_obj is not None and reg_fn.group(2) == rty.java_hu_ty + "_new":
340                     constructor_fns[rty.rust_obj] = reg_fn.group(3)
341             continue
342         arr_fn = fn_ret_arr_regex.match(line)
343         if arr_fn is not None:
344             if arr_fn.group(2).endswith("_clone"):
345                 clone_fns.add(arr_fn.group(2))
346             # No object constructors return arrays, as then they wouldn't be an object constructor
347             continue
348
349 # Define some manual clones...
350 clone_fns.add("ThirtyTwoBytes_clone")
351 write_c("static inline struct LDKThirtyTwoBytes ThirtyTwoBytes_clone(const struct LDKThirtyTwoBytes *orig) { struct LDKThirtyTwoBytes ret; memcpy(ret.data, orig->data, 32); return ret; }\n")
352
353 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
354
355 with open(path_to_lightning_header) as in_h, open(path_to_output_blob, "w") as out_java:
356     def map_type(fn_arg, print_void, ret_arr_len, is_free, holds_ref):
357         ty_info = java_c_types(fn_arg, ret_arr_len)
358         return map_type_with_info(ty_info, print_void, ret_arr_len, is_free, holds_ref)
359
360     def map_type_with_info(ty_info, print_void, ret_arr_len, is_free, holds_ref):
361         if ty_info.c_ty == "void":
362             if not print_void:
363                 return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
364                     arg_conv = None, arg_conv_name = None, arg_conv_cleanup = None,
365                     ret_conv = None, ret_conv_name = None, to_hu_conv = None, to_hu_conv_name = None, from_hu_conv = None)
366         if ty_info.c_ty.endswith("Array"):
367             arr_len = ty_info.arr_len
368             if arr_len is not None:
369                 arr_name = ty_info.var_name
370             else:
371                 arr_name = "ret"
372                 arr_len = ret_arr_len
373             if ty_info.c_ty == "int8_tArray":
374                 (set_pfx, set_sfx) = consts.set_native_arr_contents(arr_name + "_arr", arr_len, ty_info)
375                 ret_conv = ("int8_tArray " + arr_name + "_arr = " + consts.create_native_arr_call(arr_len, ty_info) + ";\n" + set_pfx, "")
376                 arg_conv_cleanup = None
377                 if not arr_len.isdigit():
378                     arg_conv = ty_info.rust_obj + " " + arr_name + "_ref;\n"
379                     arg_conv = arg_conv + arr_name + "_ref." + arr_len + " = " +  consts.get_native_arr_len_call[0] + arr_name + consts.get_native_arr_len_call[1] + ";\n"
380                     if (not ty_info.is_ptr or not holds_ref) and ty_info.rust_obj != "LDKu8slice":
381                         arg_conv = arg_conv + arr_name + "_ref." + ty_info.arr_access + " = MALLOC(" + arr_name + "_ref." + arr_len + ", \"" + ty_info.rust_obj + " Bytes\");\n"
382                         arg_conv = arg_conv + consts.get_native_arr_contents(arr_name, arr_name + "_ref." + ty_info.arr_access, arr_name + "_ref." + arr_len, ty_info, True) + ";"
383                     else:
384                         arg_conv = arg_conv + arr_name + "_ref." + ty_info.arr_access + " = " + consts.get_native_arr_contents(arr_name, "NO_DEST", arr_name + "_ref." + arr_len, ty_info, False) + ";"
385                         arg_conv_cleanup = consts.cleanup_native_arr_ref_contents(arr_name, arr_name + "_ref." + ty_info.arr_access, arr_name + "_ref." + arr_len, ty_info)
386                     if ty_info.rust_obj == "LDKTransaction":
387                         arg_conv = arg_conv + "\n" + arr_name + "_ref.data_is_owned = " + str(holds_ref).lower() + ";"
388                     ret_conv = (ty_info.rust_obj + " " + arr_name + "_var = ", "")
389                     ret_conv = (ret_conv[0], ";\nint8_tArray " + arr_name + "_arr = " + consts.create_native_arr_call(arr_name + "_var." + arr_len, ty_info) + ";\n")
390                     (pfx, sfx) = consts.set_native_arr_contents(arr_name + "_arr", arr_name + "_var." + arr_len, ty_info)
391                     ret_conv = (ret_conv[0], ret_conv[1] + pfx + arr_name + "_var." + ty_info.arr_access + sfx + ";")
392                     if not holds_ref and ty_info.rust_obj != "LDKu8slice":
393                         ret_conv = (ret_conv[0], ret_conv[1] + "\n" + ty_info.rust_obj.replace("LDK", "") + "_free(" + arr_name + "_var);")
394                 elif ty_info.rust_obj is not None:
395                     arg_conv = ty_info.rust_obj + " " + arr_name + "_ref;\n"
396                     arg_conv = arg_conv + "CHECK(" + consts.get_native_arr_len_call[0] + arr_name + consts.get_native_arr_len_call[1] + " == " + arr_len + ");\n"
397                     arg_conv = arg_conv + consts.get_native_arr_contents(arr_name, arr_name + "_ref." + ty_info.arr_access, arr_len, ty_info, True) + ";"
398                     ret_conv = (ret_conv[0], "." + ty_info.arr_access + set_sfx + ";")
399                 else:
400                     arg_conv = "unsigned char " + arr_name + "_arr[" + arr_len + "];\n"
401                     arg_conv = arg_conv + "CHECK(" + consts.get_native_arr_len_call[0] + arr_name + consts.get_native_arr_len_call[1] + " == " + arr_len + ");\n"
402                     arg_conv = arg_conv + consts.get_native_arr_contents(arr_name, arr_name + "_arr", arr_len, ty_info, True) + ";\n"
403                     arg_conv = arg_conv + "unsigned char (*" + arr_name + "_ref)[" + arr_len + "] = &" + arr_name + "_arr;"
404                     ret_conv = (ret_conv[0] + "*", set_sfx + ";")
405                 return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
406                     arg_conv = arg_conv, arg_conv_name = arr_name + "_ref", arg_conv_cleanup = arg_conv_cleanup,
407                     ret_conv = ret_conv, ret_conv_name = arr_name + "_arr", to_hu_conv = None, to_hu_conv_name = None, from_hu_conv = None)
408             else:
409                 assert not arr_len.isdigit() # fixed length arrays not implemented
410                 assert ty_info.java_ty[len(ty_info.java_ty) - 2:] == "[]"
411                 conv_name = "arr_conv_" + str(len(ty_info.java_hu_ty))
412                 idxc = chr(ord('a') + (len(ty_info.java_hu_ty) % 26))
413                 ty_info.subty.var_name = conv_name
414                 #XXX: We'd really prefer to only ever set to False, avoiding lots of clone, but need smarter free logic
415                 #if ty_info.is_ptr or holds_ref:
416                 #    ty_info.subty.requires_clone = False
417                 ty_info.subty.requires_clone = not ty_info.is_ptr or not holds_ref
418                 subty = map_type_with_info(ty_info.subty, False, None, is_free, holds_ref)
419                 if arr_name == "":
420                     arr_name = "arg"
421                 arg_conv = ty_info.rust_obj + " " + arr_name + "_constr;\n"
422                 arg_conv = arg_conv + arr_name + "_constr." + arr_len + " = " + consts.get_native_arr_len_call[0] + arr_name + consts.get_native_arr_len_call[1] + ";\n"
423                 arg_conv = arg_conv + "if (" + arr_name + "_constr." + arr_len + " > 0)\n"
424                 if subty.rust_obj is None:
425                     szof = subty.c_ty
426                 else:
427                     szof = subty.rust_obj
428                 arg_conv = arg_conv + "\t" + arr_name + "_constr." + ty_info.arr_access + " = MALLOC(" + arr_name + "_constr." + arr_len + " * sizeof(" + szof + "), \"" + ty_info.rust_obj + " Elements\");\n"
429                 arg_conv = arg_conv + "else\n"
430                 arg_conv = arg_conv + "\t" + arr_name + "_constr." + ty_info.arr_access + " = NULL;\n"
431                 get_arr = consts.get_native_arr_contents(arr_name, "NO_DEST", arr_name + "_constr." + arr_len, ty_info, False)
432                 if get_arr != None:
433                     arg_conv = arg_conv + subty.c_ty + "* " + arr_name + "_vals = " + get_arr + ";\n"
434                 arg_conv = arg_conv + "for (size_t " + idxc + " = 0; " + idxc + " < " + arr_name + "_constr." + arr_len + "; " + idxc + "++) {\n"
435                 if get_arr != None:
436                     arg_conv = arg_conv + "\t" + subty.c_ty + " " + conv_name + " = " + arr_name + "_vals[" + idxc + "];"
437                     if subty.arg_conv is not None:
438                         arg_conv = arg_conv + "\n\t" + subty.arg_conv.replace("\n", "\n\t")
439                 else:
440                     arg_conv = arg_conv + "\t" + subty.c_ty + " " + conv_name + " = " + consts.get_native_arr_elem(arr_name, idxc, ty_info) + ";\n"
441                     arg_conv = arg_conv + "\t" + subty.arg_conv.replace("\n", "\n\t")
442                 arg_conv = arg_conv + "\n\t" + arr_name + "_constr." + ty_info.arr_access + "[" + idxc + "] = " + subty.arg_conv_name + ";\n}"
443                 if get_arr != None:
444                     cleanup = consts.cleanup_native_arr_ref_contents(arr_name, arr_name + "_vals", arr_name + "_constr." + arr_len, ty_info)
445                     if cleanup is not None:
446                         arg_conv = arg_conv + "\n" + cleanup + ";"
447                 if ty_info.is_ptr:
448                     arg_conv_name = "&" + arr_name + "_constr"
449                 else:
450                     arg_conv_name = arr_name + "_constr"
451                 arg_conv_cleanup = None
452                 if ty_info.is_ptr:
453                     arg_conv_cleanup = "FREE(" + arr_name + "_constr." + ty_info.arr_access + ");"
454
455                 if arr_name == "arg":
456                     arr_name = "ret"
457                 ret_conv = (ty_info.rust_obj + " " + arr_name + "_var = ", "")
458                 if subty.ret_conv is None:
459                     ret_conv = ("DUMMY", "DUMMY")
460                 elif not ty_info.java_ty[:len(ty_info.java_ty) - 2].endswith("[]"):
461                     ret_conv = (ret_conv[0], ";\n" + ty_info.c_ty + " " + arr_name + "_arr = " + consts.create_native_arr_call(arr_name + "_var." + arr_len, ty_info) + ";\n")
462                     ret_conv = (ret_conv[0], ret_conv[1] + subty.c_ty + " *" + arr_name + "_arr_ptr = " + consts.get_native_arr_ptr_call[0] + arr_name + "_arr" + consts.get_native_arr_ptr_call[1] + ";\n")
463                     ret_conv = (ret_conv[0], ret_conv[1] + "for (size_t " + idxc + " = 0; " + idxc + " < " + arr_name + "_var." + arr_len + "; " + idxc + "++) {\n")
464                     ret_conv = (ret_conv[0], ret_conv[1] + "\t" + subty.ret_conv[0].replace("\n", "\n\t"))
465                     ret_conv = (ret_conv[0], ret_conv[1] + arr_name + "_var." + ty_info.arr_access + "[" + idxc + "]" + subty.ret_conv[1].replace("\n", "\n\t"))
466                     ret_conv = (ret_conv[0], ret_conv[1] + "\n\t" + arr_name + "_arr_ptr[" + idxc + "] = " + subty.ret_conv_name + ";\n}")
467                     cleanup = consts.release_native_arr_ptr_call(arr_name + "_arr", arr_name + "_arr_ptr")
468                     if cleanup is not None:
469                         ret_conv = (ret_conv[0], ret_conv[1] + "\n" + cleanup + ";")
470                 else:
471                     assert ty_info.java_fn_ty_arg.startswith("[")
472                     clz_var = ty_info.java_fn_ty_arg[1:].replace("[", "arr_of_")
473                     c_array_class_caches.add(clz_var)
474                     ret_conv = (ret_conv[0], ";\n" + ty_info.c_ty + " " + arr_name + "_arr = (*env)->NewObjectArray(env, " + arr_name + "_var." + arr_len + ", " + clz_var + "_clz, NULL);\n")
475                     ret_conv = (ret_conv[0], ret_conv[1] + "for (size_t " + idxc + " = 0; " + idxc + " < " + arr_name + "_var." + arr_len + "; " + idxc + "++) {\n")
476                     ret_conv = (ret_conv[0], ret_conv[1] + "\t" + subty.ret_conv[0].replace("\n", "\n\t"))
477                     ret_conv = (ret_conv[0], ret_conv[1] + arr_name + "_var." + ty_info.arr_access + "[" + idxc + "]" + subty.ret_conv[1].replace("\n", "\n\t"))
478                     ret_conv = (ret_conv[0], ret_conv[1] + "\n\t(*env)->SetObjectArrayElement(env, " + arr_name + "_arr, " + idxc + ", " + subty.ret_conv_name + ");\n")
479                     ret_conv = (ret_conv[0], ret_conv[1] + "}")
480                 if not holds_ref:
481                     # XXX: The commented if's are a bit smarter freeing, but we need to be a nudge smarter still
482                     # Note that we don't drop the full vec here - we're passing ownership to java (or have cloned) or free'd by now!
483                     ret_conv = (ret_conv[0], ret_conv[1] + "\nFREE(" + arr_name + "_var." + ty_info.arr_access + ");")
484                     #if subty.rust_obj is not None and subty.rust_obj in opaque_structs:
485                     #    ret_conv = (ret_conv[0], ret_conv[1] + "\nFREE(" + arr_name + "_var." + ty_info.arr_access + ");")
486                     #else:
487                     #    ret_conv = (ret_conv[0], ret_conv[1] + "\n" + ty_info.rust_obj.replace("LDK", "") + "_free(" + arr_name + "_var);")
488
489                 to_hu_conv = None
490                 to_hu_conv_name = None
491                 if subty.to_hu_conv is not None:
492                     to_hu_conv = ty_info.java_hu_ty + " " + conv_name + "_arr = new " + ty_info.subty.java_hu_ty.split("<")[0] + "[" + arr_name + ".length];\n"
493                     to_hu_conv = to_hu_conv + "for (int " + idxc + " = 0; " + idxc + " < " + arr_name + ".length; " + idxc + "++) {\n"
494                     to_hu_conv = to_hu_conv + "\t" + subty.java_ty + " " + conv_name + " = " + arr_name + "[" + idxc + "];\n"
495                     to_hu_conv = to_hu_conv + "\t" + subty.to_hu_conv.replace("\n", "\n\t") + "\n"
496                     to_hu_conv = to_hu_conv + "\t" + conv_name + "_arr[" + idxc + "] = " + subty.to_hu_conv_name + ";\n}"
497                     to_hu_conv_name = conv_name + "_arr"
498                 from_hu_conv = None
499                 if subty.from_hu_conv is not None:
500                     if subty.java_ty == "long" and subty.java_hu_ty != "long":
501                         from_hu_conv = ("Arrays.stream(" + arr_name + ").mapToLong(" + conv_name + " -> " + subty.from_hu_conv[0] + ").toArray()", "/* TODO 2 " + subty.java_hu_ty + "  */")
502                     elif subty.java_ty == "long":
503                         from_hu_conv = ("Arrays.stream(" + arr_name + ").map(" + conv_name + " -> " + subty.from_hu_conv[0] + ").toArray()", "/* TODO 2 " + subty.java_hu_ty + "  */")
504                     else:
505                         from_hu_conv = ("(" + ty_info.java_ty + ")Arrays.stream(" + arr_name + ").map(" + conv_name + " -> " + subty.from_hu_conv[0] + ").toArray()", "/* TODO 2 " + subty.java_hu_ty + "  */")
506
507                 return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
508                     arg_conv = arg_conv, arg_conv_name = arg_conv_name, arg_conv_cleanup = arg_conv_cleanup,
509                     ret_conv = ret_conv, ret_conv_name = arr_name + "_arr", to_hu_conv = to_hu_conv, to_hu_conv_name = to_hu_conv_name, from_hu_conv = from_hu_conv)
510         elif ty_info.java_ty == "String":
511             if ty_info.arr_access is None:
512                 return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
513                     arg_conv = None, arg_conv_name = None, arg_conv_cleanup = None,
514                     ret_conv = ("jstring " + ty_info.var_name + "_conv = (*env)->NewStringUTF(env, ", ");"), ret_conv_name = ty_info.var_name + "_conv",
515                     to_hu_conv = None, to_hu_conv_name = None, from_hu_conv = None)
516             else:
517                 return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
518                     arg_conv = None, arg_conv_name = None, arg_conv_cleanup = None,
519                     ret_conv = ("LDKStr " + ty_info.var_name + "_str = ",
520                         ";\nchar* " + ty_info.var_name + "_buf = MALLOC(" + ty_info.var_name + "_str." + ty_info.arr_len + " + 1, \"str conv buf\");\n" +
521                         "memcpy(" + ty_info.var_name + "_buf, " + ty_info.var_name + "_str." + ty_info.arr_access + ", " + ty_info.var_name + "_str." + ty_info.arr_len + ");\n" +
522                         ty_info.var_name + "_buf[" + ty_info.var_name + "_str." + ty_info.arr_len + "] = 0;\n" +
523                         "jstring " + ty_info.var_name + "_conv = (*env)->NewStringUTF(env, " + ty_info.var_name + "_str." + ty_info.arr_access + ");\n" +
524                         "FREE(" + ty_info.var_name + "_buf);"),
525                     ret_conv_name = ty_info.var_name + "_conv", to_hu_conv = None, to_hu_conv_name = None, from_hu_conv = None)
526         elif ty_info.var_name == "" and not print_void:
527             # We don't have a parameter name, and want one, just call it arg
528             if ty_info.rust_obj is not None:
529                 assert(not is_free or ty_info.rust_obj not in opaque_structs)
530                 return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
531                     arg_conv = ty_info.rust_obj + " arg_conv = *(" + ty_info.rust_obj + "*)arg;\nFREE((void*)arg);",
532                     arg_conv_name = "arg_conv", arg_conv_cleanup = None,
533                     ret_conv = None, ret_conv_name = None, to_hu_conv = "TODO 7", to_hu_conv_name = None, from_hu_conv = None)
534             else:
535                 assert(not is_free)
536                 return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
537                     arg_conv = None, arg_conv_name = "arg", arg_conv_cleanup = None,
538                     ret_conv = None, ret_conv_name = None, to_hu_conv = "TODO 8", to_hu_conv_name = None, from_hu_conv = None)
539         elif ty_info.rust_obj is None:
540             return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
541                 arg_conv = None, arg_conv_name = ty_info.var_name, arg_conv_cleanup = None,
542                 ret_conv = None, ret_conv_name = None, to_hu_conv = None, to_hu_conv_name = None, from_hu_conv = None)
543         else:
544             if ty_info.var_name == "":
545                 ty_info.var_name = "ret"
546
547             if ty_info.rust_obj in opaque_structs:
548                 opaque_arg_conv = ty_info.rust_obj + " " + ty_info.var_name + "_conv;\n"
549                 opaque_arg_conv = opaque_arg_conv + ty_info.var_name + "_conv.inner = (void*)(" + ty_info.var_name + " & (~1));\n"
550                 if ty_info.is_ptr and holds_ref:
551                     opaque_arg_conv = opaque_arg_conv + ty_info.var_name + "_conv.is_owned = false;"
552                 else:
553                     opaque_arg_conv = opaque_arg_conv + ty_info.var_name + "_conv.is_owned = (" + ty_info.var_name + " & 1) || (" + ty_info.var_name + " == 0);"
554                 if not is_free and (not ty_info.is_ptr or not holds_ref or ty_info.requires_clone == True) and ty_info.requires_clone != False:
555                     if (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
556                         # TODO: This is a bit too naive, even with the checks above, we really need to know if rust wants a ref or not, not just if its pass as a ptr.
557                         opaque_arg_conv = opaque_arg_conv + "\nif (" + ty_info.var_name + "_conv.inner != NULL)\n"
558                         opaque_arg_conv = opaque_arg_conv + "\t" + ty_info.var_name + "_conv = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&" + ty_info.var_name + "_conv);"
559                     elif ty_info.passed_as_ptr:
560                         opaque_arg_conv = opaque_arg_conv + "\n// Warning: we may need a move here but can't clone!"
561
562                 opaque_ret_conv_suf = ";\n"
563                 if not holds_ref and ty_info.is_ptr and (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns: # is_ptr, not holds_ref implies passing a pointed-to value to java, which needs copied
564                     opaque_ret_conv_suf = opaque_ret_conv_suf + "if (" + ty_info.var_name + "->inner != NULL)\n"
565                     opaque_ret_conv_suf = opaque_ret_conv_suf + "\t" + ty_info.var_name + "_var = " + ty_info.rust_obj.replace("LDK", "") + "_clone(" + ty_info.var_name + ");\n"
566                 elif not holds_ref and ty_info.is_ptr:
567                     opaque_ret_conv_suf = opaque_ret_conv_suf + "// Warning: we may need a move here but can't clone!\n"
568
569                 opaque_ret_conv_suf = opaque_ret_conv_suf + "CHECK((((long)" + ty_info.var_name + "_var.inner) & 1) == 0); // We rely on a free low bit, malloc guarantees this.\n"
570                 opaque_ret_conv_suf = opaque_ret_conv_suf + "CHECK((((long)&" + ty_info.var_name + "_var) & 1) == 0); // We rely on a free low bit, pointer alignment guarantees this.\n"
571                 if holds_ref:
572                     opaque_ret_conv_suf = opaque_ret_conv_suf + "long " + ty_info.var_name + "_ref = (long)" + ty_info.var_name + "_var.inner & ~1;"
573                 else:
574                     opaque_ret_conv_suf = opaque_ret_conv_suf + "long " + ty_info.var_name + "_ref = (long)" + ty_info.var_name + "_var.inner;\n"
575                     opaque_ret_conv_suf = opaque_ret_conv_suf + "if (" + ty_info.var_name + "_var.is_owned) {\n"
576                     opaque_ret_conv_suf = opaque_ret_conv_suf + "\t" + ty_info.var_name + "_ref |= 1;\n"
577                     opaque_ret_conv_suf = opaque_ret_conv_suf + "}"
578
579                 if ty_info.is_ptr:
580                     return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
581                         arg_conv = opaque_arg_conv, arg_conv_name = "&" + ty_info.var_name + "_conv", arg_conv_cleanup = None,
582                         ret_conv = (ty_info.rust_obj + " " + ty_info.var_name + "_var = *", opaque_ret_conv_suf),
583                         ret_conv_name = ty_info.var_name + "_ref",
584                         to_hu_conv = ty_info.java_hu_ty + " " + ty_info.var_name + "_hu_conv = new " + ty_info.java_hu_ty + "(null, " + ty_info.var_name + ");",
585                         to_hu_conv_name = ty_info.var_name + "_hu_conv",
586                         from_hu_conv = (ty_info.var_name + " == null ? 0 : " + ty_info.var_name + ".ptr & ~1", "this.ptrs_to.add(" + ty_info.var_name + ")"))
587                 else:
588                     return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
589                         arg_conv = opaque_arg_conv, arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
590                         ret_conv = (ty_info.rust_obj + " " + ty_info.var_name + "_var = ", opaque_ret_conv_suf),
591                         ret_conv_name = ty_info.var_name + "_ref",
592                         to_hu_conv = ty_info.java_hu_ty + " " + ty_info.var_name + "_hu_conv = new " + ty_info.java_hu_ty + "(null, " + ty_info.var_name + ");",
593                         to_hu_conv_name = ty_info.var_name + "_hu_conv",
594                         from_hu_conv = (ty_info.var_name + " == null ? 0 : " + ty_info.var_name + ".ptr & ~1", "this.ptrs_to.add(" + ty_info.var_name + ")"))
595
596             if not ty_info.is_ptr:
597                 if ty_info.rust_obj in unitary_enums:
598                     (ret_pfx, ret_sfx) = consts.c_unitary_enum_to_native_call(ty_info)
599                     (arg_pfx, arg_sfx) = consts.native_unitary_enum_to_c_call(ty_info)
600                     return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
601                         arg_conv = ty_info.rust_obj + " " + ty_info.var_name + "_conv = " + arg_pfx + ty_info.var_name + arg_sfx + ";",
602                         arg_conv_name = ty_info.var_name + "_conv",
603                         arg_conv_cleanup = None,
604                         ret_conv = (ty_info.c_ty + " " + ty_info.var_name + "_conv = " + ret_pfx, ret_sfx + ";"),
605                         ret_conv_name = ty_info.var_name + "_conv", to_hu_conv = None, to_hu_conv_name = None, from_hu_conv = None)
606                 base_conv = ty_info.rust_obj + " " + ty_info.var_name + "_conv = *(" + ty_info.rust_obj + "*)" + ty_info.var_name + ";"
607                 if ty_info.rust_obj in trait_structs:
608                     if not is_free:
609                         needs_full_clone = not is_free and (not ty_info.is_ptr and not holds_ref or ty_info.requires_clone == True) and ty_info.requires_clone != False
610                         if needs_full_clone and (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
611                             base_conv = base_conv + "\n" + ty_info.var_name + "_conv = " + ty_info.rust_obj.replace("LDK", "") + "_clone(" + ty_info.var_name + ");"
612                         else:
613                             base_conv = base_conv + "\nif (" + ty_info.var_name + "_conv.free == " + ty_info.rust_obj + "_JCalls_free) {\n"
614                             base_conv = base_conv + "\t// If this_arg is a JCalls struct, then we need to increment the refcnt in it.\n"
615                             base_conv = base_conv + "\t" + ty_info.rust_obj + "_JCalls_clone(" + ty_info.var_name + "_conv.this_arg);\n}"
616                             if needs_full_clone:
617                                 base_conv = base_conv + "// Warning: we may need a move here but can't do a full clone!\n"
618
619                     else:
620                         base_conv = base_conv + "\n" + "FREE((void*)" + ty_info.var_name + ");"
621                     return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
622                         arg_conv = base_conv, arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
623                         ret_conv = (ty_info.rust_obj + "* ret = MALLOC(sizeof(" + ty_info.rust_obj + "), \"" + ty_info.rust_obj + "\");\n*ret = ", ";"),
624                         ret_conv_name = "(long)ret",
625                         to_hu_conv = ty_info.java_hu_ty + " ret_hu_conv = new " + ty_info.java_hu_ty + "(null, " + ty_info.var_name + ");\nret_hu_conv.ptrs_to.add(this);",
626                         to_hu_conv_name = "ret_hu_conv",
627                         from_hu_conv = (ty_info.var_name + " == null ? 0 : " + ty_info.var_name + ".ptr", "this.ptrs_to.add(" + ty_info.var_name + ")"))
628                 if ty_info.rust_obj != "LDKu8slice":
629                     # Don't bother free'ing slices passed in - Rust doesn't auto-free the
630                     # underlying unlike Vecs, and it gives Java more freedom.
631                     base_conv = base_conv + "\nFREE((void*)" + ty_info.var_name + ");";
632                 if ty_info.rust_obj in complex_enums:
633                     ret_conv = ("long " + ty_info.var_name + "_ref = (long)&", ";")
634                     if not holds_ref:
635                         ret_conv = (ty_info.rust_obj + " *" + ty_info.var_name + "_copy = MALLOC(sizeof(" + ty_info.rust_obj + "), \"" + ty_info.rust_obj + "\");\n", "")
636                         if ty_info.requires_clone == True: # Set in object array mapping
637                             if (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
638                                 ret_conv = (ret_conv[0] + "*" + ty_info.var_name + "_copy = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&", ");\n")
639                             else:
640                                 ret_conv = (ret_conv[0] + "*" + ty_info.var_name + "_copy = ", "; // XXX: We likely need to clone here, but no _clone fn is available!\n")
641                         else:
642                             ret_conv = (ret_conv[0] + "*" + ty_info.var_name + "_copy = ", ";\n")
643                         ret_conv = (ret_conv[0], ret_conv[1] + "long " + ty_info.var_name + "_ref = (long)" + ty_info.var_name + "_copy;")
644                     return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
645                         arg_conv = base_conv, arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
646                         ret_conv = ret_conv, ret_conv_name = ty_info.var_name + "_ref",
647                         to_hu_conv = ty_info.java_hu_ty + " " + ty_info.var_name + "_hu_conv = " + ty_info.java_hu_ty + ".constr_from_ptr(" + ty_info.var_name + ");\n" + ty_info.var_name + "_hu_conv.ptrs_to.add(this);",
648                         to_hu_conv_name = ty_info.var_name + "_hu_conv", from_hu_conv = (ty_info.var_name + ".ptr", ""))
649                 if ty_info.rust_obj in result_types:
650                     if holds_ref:
651                         # If we're trying to return a ref, we have to clone.
652                         # We just blindly assume its implemented and let the compiler fail if its not.
653                         ret_conv = (ty_info.rust_obj + "* " + ty_info.var_name + "_conv = MALLOC(sizeof(" + ty_info.rust_obj + "), \"" + ty_info.rust_obj + "\");\n*" + ty_info.var_name + "_conv = ", ";")
654                         ret_conv = (ret_conv[0], ret_conv[1] + "\n*" + ty_info.var_name + "_conv = " + ty_info.rust_obj.replace("LDK", "") + "_clone(" + ty_info.var_name + "_conv);")
655                     else:
656                         ret_conv = (ty_info.rust_obj + "* " + ty_info.var_name + "_conv = MALLOC(sizeof(" + ty_info.rust_obj + "), \"" + ty_info.rust_obj + "\");\n*" + ty_info.var_name + "_conv = ", ";")
657                     return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
658                         arg_conv = base_conv, arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
659                         ret_conv = ret_conv, ret_conv_name = "(long)" + ty_info.var_name + "_conv",
660                         to_hu_conv = ty_info.java_hu_ty + " " + ty_info.var_name + "_hu_conv = " + ty_info.java_hu_ty + ".constr_from_ptr(" + ty_info.var_name + ");",
661                         to_hu_conv_name = ty_info.var_name + "_hu_conv", from_hu_conv = (ty_info.var_name + " != null ? " + ty_info.var_name + ".ptr : 0", ""))
662                 if ty_info.rust_obj in tuple_types:
663                     from_hu_conv = "bindings." + tuple_types[ty_info.rust_obj][1].replace("LDK", "") + "_new("
664                     to_hu_conv_pfx = ""
665                     to_hu_conv_sfx = ty_info.java_hu_ty + " " + ty_info.var_name + "_conv = new " + ty_info.java_hu_ty + "("
666                     clone_ret_str = ""
667                     for idx, conv in enumerate(tuple_types[ty_info.rust_obj][0]):
668                         if idx != 0:
669                             to_hu_conv_sfx = to_hu_conv_sfx + ", "
670                             from_hu_conv = from_hu_conv + ", "
671                         conv.var_name = ty_info.var_name + "_" + chr(idx + ord("a"))
672                         conv_map = map_type_with_info(conv, False, None, is_free, holds_ref)
673                         to_hu_conv_pfx = to_hu_conv_pfx + conv.java_ty + " " + ty_info.var_name + "_" + chr(idx + ord("a")) + " = " + "bindings." + tuple_types[ty_info.rust_obj][1] + "_get_" + chr(idx + ord("a")) + "(" + ty_info.var_name + ");\n"
674                         if conv_map.to_hu_conv is not None:
675                             to_hu_conv_pfx = to_hu_conv_pfx + conv_map.to_hu_conv + ";\n"
676                             to_hu_conv_sfx = to_hu_conv_sfx + conv_map.to_hu_conv_name
677                         else:
678                             to_hu_conv_sfx = to_hu_conv_sfx + ty_info.var_name + "_" + chr(idx + ord("a"))
679                         if conv_map.from_hu_conv is not None:
680                             from_hu_conv = from_hu_conv + conv_map.from_hu_conv[0].replace(ty_info.var_name + "_" + chr(idx + ord("a")), ty_info.var_name + "." + chr(idx + ord("a")))
681                             if conv_map.from_hu_conv[1] != "":
682                                 from_hu_conv = from_hu_conv + "/*XXX: " + conv_map.from_hu_conv[1] + "*/"
683                         else:
684                             from_hu_conv = from_hu_conv + ty_info.var_name + "." + chr(idx + ord("a"))
685
686                         if conv.is_native_primitive:
687                             pass
688                         elif (conv_map.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
689                             accessor = ty_info.var_name + "_ref->" + chr(idx + ord("a"))
690                             clone_ret_str = clone_ret_str + "\n" + accessor + " = " + conv_map.rust_obj.replace("LDK", "") + "_clone(&" + accessor + ");"
691                         else:
692                             clone_ret_str = clone_ret_str + "\n// XXX: We likely need to clone here, but no _clone fn is available for " + conv_map.java_hu_ty
693                     if not ty_info.is_ptr and not holds_ref:
694                         ret_conv = (ty_info.rust_obj + "* " + ty_info.var_name + "_ref = MALLOC(sizeof(" + ty_info.rust_obj + "), \"" + ty_info.rust_obj + "\");\n*" + ty_info.var_name + "_ref = ", ";")
695                         if not is_free and (not ty_info.is_ptr and not holds_ref or ty_info.requires_clone == True) and ty_info.requires_clone != False:
696                             ret_conv = (ret_conv[0], ret_conv[1] + clone_ret_str)
697                         return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
698                             arg_conv = base_conv, arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
699                             ret_conv = ret_conv,
700                             ret_conv_name = "(long)" + ty_info.var_name + "_ref",
701                             to_hu_conv = to_hu_conv_pfx + to_hu_conv_sfx + ");", to_hu_conv_name = ty_info.var_name + "_conv", from_hu_conv = (from_hu_conv + ")", ""))
702                     return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
703                         arg_conv = base_conv, arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
704                         ret_conv = ("long " + ty_info.var_name + "_ref = (long)&", ";"), ret_conv_name = ty_info.var_name + "_ref",
705                         to_hu_conv = to_hu_conv_pfx + to_hu_conv_sfx + ");", to_hu_conv_name = ty_info.var_name + "_conv", from_hu_conv = (from_hu_conv + ")", ""))
706
707                 # The manually-defined types - TxOut and Transaction
708                 assert ty_info.rust_obj == "LDKTxOut"
709                 if not ty_info.is_ptr and not holds_ref:
710                     ret_conv = ("LDKTxOut* " + ty_info.var_name + "_ref = MALLOC(sizeof(LDKTxOut), \"LDKTxOut\");\n*" + ty_info.var_name + "_ref = ", ";")
711                 else:
712                     ret_conv = ("long " + ty_info.var_name + "_ref = (long)&", ";")
713                 return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
714                     arg_conv = base_conv, arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
715                     ret_conv = ret_conv, ret_conv_name = "(long)" + ty_info.var_name + "_ref",
716                     to_hu_conv = ty_info.java_hu_ty + " " + ty_info.var_name + "_conv = new " +ty_info.java_hu_ty + "(null, " + ty_info.var_name + ");",
717                     to_hu_conv_name = ty_info.var_name + "_conv", from_hu_conv = (ty_info.var_name + ".ptr", ""))
718             elif ty_info.is_ptr:
719                 assert(not is_free)
720                 if ty_info.rust_obj in complex_enums:
721                     return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
722                         arg_conv = ty_info.rust_obj + "* " + ty_info.var_name + "_conv = (" + ty_info.rust_obj + "*)" + ty_info.var_name + ";",
723                         arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
724                         ret_conv = ("long ret_" + ty_info.var_name + " = (long)", ";"), ret_conv_name = "ret_" + ty_info.var_name,
725                         to_hu_conv = ty_info.java_hu_ty + " " + ty_info.var_name + "_hu_conv = " + ty_info.java_hu_ty + ".constr_from_ptr(" + ty_info.var_name + ");",
726                         to_hu_conv_name = ty_info.var_name + "_hu_conv",
727                         from_hu_conv = (ty_info.var_name + " == null ? 0 : " + ty_info.var_name + ".ptr & ~1", "this.ptrs_to.add(" + ty_info.var_name + ")"))
728                 elif ty_info.rust_obj in trait_structs:
729                     if ty_info.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
730                         return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
731                             arg_conv = ty_info.rust_obj + "* " + ty_info.var_name + "_conv = (" + ty_info.rust_obj + "*)" + ty_info.var_name + ";",
732                             arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
733                             ret_conv = (ty_info.rust_obj + " *" + ty_info.var_name + "_clone = MALLOC(sizeof(" + ty_info.rust_obj + "), \"" + ty_info.rust_obj + "\");\n" +
734                                 "*" + ty_info.var_name + "_clone = " + ty_info.rust_obj.replace("LDK", "") + "_clone(", ");"),
735                             ret_conv_name = "(long)" + ty_info.var_name + "_clone",
736                             to_hu_conv = ty_info.java_hu_ty + " ret_hu_conv = new " + ty_info.java_hu_ty + "(null, " + ty_info.var_name + ");\nret_hu_conv.ptrs_to.add(this);",
737                             to_hu_conv_name = "ret_hu_conv",
738                             from_hu_conv = (ty_info.var_name + " == null ? 0 : " + ty_info.var_name + ".ptr", "this.ptrs_to.add(" + ty_info.var_name + ")"))
739                     else:
740                         return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
741                             arg_conv = ty_info.rust_obj + "* " + ty_info.var_name + "_conv = (" + ty_info.rust_obj + "*)" + ty_info.var_name + ";",
742                             arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
743                             ret_conv = ("long ret_" + ty_info.var_name + " = (long)", ";"), ret_conv_name = "ret_" + ty_info.var_name,
744                             to_hu_conv = ty_info.java_hu_ty + " ret_hu_conv = new " + ty_info.java_hu_ty + "(null, " + ty_info.var_name + ");\nret_hu_conv.ptrs_to.add(this);",
745                             to_hu_conv_name = "ret_hu_conv",
746                             from_hu_conv = (ty_info.var_name + " == null ? 0 : " + ty_info.var_name + ".ptr", "this.ptrs_to.add(" + ty_info.var_name + ")"))
747                 return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
748                     arg_conv = ty_info.rust_obj + "* " + ty_info.var_name + "_conv = (" + ty_info.rust_obj + "*)" + ty_info.var_name + ";",
749                     arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
750                     ret_conv = ("long ret_" + ty_info.var_name + " = (long)", ";"), ret_conv_name = "ret_" + ty_info.var_name,
751                     to_hu_conv = "TODO 3", to_hu_conv_name = None, from_hu_conv = None) # its a pointer, no conv needed
752             assert False # We should have handled every case by now.
753
754
755
756     def map_fn(line, re_match, ret_arr_len, c_call_string):
757         out_java.write("\t// " + line)
758         out_java.write("\tpublic static native ")
759         write_c(consts.c_fn_ty_pfx)
760
761         is_free = re_match.group(2).endswith("_free")
762         struct_meth = re_match.group(2).split("_")[0]
763
764         ret_info = map_type(re_match.group(1), True, ret_arr_len, False, False)
765         write_c(ret_info.c_ty)
766         out_java.write(ret_info.java_ty)
767
768         if ret_info.ret_conv is not None:
769             ret_conv_pfx, ret_conv_sfx = ret_info.ret_conv
770
771         out_java.write(" " + re_match.group(2) + "(")
772         write_c(" " + consts.c_fn_name_pfx + re_match.group(2).replace('_', '_1') + "(" + consts.c_fn_args_pfx)
773
774         arg_names = []
775         default_constructor_args = {}
776         takes_self = False
777         args_known = True
778         for idx, arg in enumerate(re_match.group(3).split(',')):
779             if idx != 0:
780                 out_java.write(", ")
781             if arg != "void":
782                 write_c(", ")
783             arg_conv_info = map_type(arg, False, None, is_free, True)
784             if arg_conv_info.c_ty != "void":
785                 write_c(arg_conv_info.c_ty + " " + arg_conv_info.arg_name)
786                 out_java.write(arg_conv_info.java_ty + " " + arg_conv_info.arg_name)
787             if idx == 0 and arg_conv_info.java_hu_ty == struct_meth:
788                 takes_self = True
789             if arg_conv_info.arg_conv is not None and "Warning" in arg_conv_info.arg_conv:
790                 if arg_conv_info.rust_obj in constructor_fns:
791                     assert not is_free
792                     for explode_arg in constructor_fns[arg_conv_info.rust_obj].split(','):
793                         explode_arg_conv = map_type(explode_arg, False, None, False, True)
794                         if explode_arg_conv.c_ty == "void":
795                             # We actually want to handle this case, but for now its only used in NetGraphMsgHandler::new()
796                             # which ends up resulting in a redundant constructor - both without arguments for the NetworkGraph.
797                             args_known = False
798                             pass
799                         if not arg_conv_info.arg_name in default_constructor_args:
800                             default_constructor_args[arg_conv_info.arg_name] = []
801                         default_constructor_args[arg_conv_info.arg_name].append(explode_arg_conv)
802             arg_names.append(arg_conv_info)
803
804         out_java_struct = None
805         if ("LDK" + struct_meth in opaque_structs or "LDK" + struct_meth in trait_structs) and not is_free:
806             out_java_struct = open(f"{path_to_bindings_directory}/structs/{struct_meth}.{consts.file_extension}", "a")
807             if not args_known:
808                 out_java_struct.write("\t// Skipped " + re_match.group(2) + "\n")
809                 out_java_struct.close()
810                 out_java_struct = None
811             else:
812                 meth_n = re_match.group(2)[len(struct_meth) + 1:]
813                 if not takes_self:
814                     out_java_struct.write("\tpublic static " + ret_info.java_hu_ty + " constructor_" + meth_n + "(")
815                 else:
816                     out_java_struct.write("\tpublic " + ret_info.java_hu_ty + " " + meth_n + "(")
817                 for idx, arg in enumerate(arg_names):
818                     if idx != 0:
819                         if not takes_self or idx > 1:
820                             out_java_struct.write(", ")
821                     elif takes_self:
822                         continue
823                     if arg.java_ty != "void":
824                         if arg.arg_name in default_constructor_args:
825                             for explode_idx, explode_arg in enumerate(default_constructor_args[arg.arg_name]):
826                                 if explode_idx != 0:
827                                     out_java_struct.write(", ")
828                                 out_java_struct.write(explode_arg.java_hu_ty + " " + arg.arg_name + "_" + explode_arg.arg_name)
829                         else:
830                             out_java_struct.write(arg.java_hu_ty + " " + arg.arg_name)
831
832
833         out_java.write(");\n")
834         write_c(") {\n")
835         if out_java_struct is not None:
836             out_java_struct.write(") {\n")
837
838         for info in arg_names:
839             if info.arg_conv is not None:
840                 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
841
842         if ret_info.ret_conv is not None:
843             write_c("\t" + ret_conv_pfx.replace('\n', '\n\t'))
844         elif ret_info.c_ty != "void":
845             write_c("\t" + ret_info.c_ty + " ret_val = ")
846         else:
847             write_c("\t")
848
849         if c_call_string is None:
850             write_c(re_match.group(2) + "(")
851         else:
852             write_c(c_call_string)
853         for idx, info in enumerate(arg_names):
854             if info.arg_conv_name is not None:
855                 if idx != 0:
856                     write_c(", ")
857                 elif c_call_string is not None:
858                     continue
859                 write_c(info.arg_conv_name)
860         write_c(")")
861         if ret_info.ret_conv is not None:
862             write_c(ret_conv_sfx.replace('\n', '\n\t'))
863         else:
864             write_c(";")
865         for info in arg_names:
866             if info.arg_conv_cleanup is not None:
867                 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
868         if ret_info.ret_conv is not None:
869             write_c("\n\treturn " + ret_info.ret_conv_name + ";")
870         elif ret_info.c_ty != "void":
871             write_c("\n\treturn ret_val;")
872         write_c("\n}\n\n")
873         if out_java_struct is not None:
874             out_java_struct.write("\t\t")
875             if ret_info.java_ty != "void":
876                 out_java_struct.write(ret_info.java_ty + " ret = ")
877             out_java_struct.write("bindings." + re_match.group(2) + "(")
878             for idx, info in enumerate(arg_names):
879                 if idx != 0:
880                     out_java_struct.write(", ")
881                 if idx == 0 and takes_self:
882                     out_java_struct.write("this.ptr")
883                 elif info.arg_name in default_constructor_args:
884                     out_java_struct.write("bindings." + info.java_hu_ty + "_new(")
885                     for explode_idx, explode_arg in enumerate(default_constructor_args[info.arg_name]):
886                         if explode_idx != 0:
887                             out_java_struct.write(", ")
888                         expl_arg_name = info.arg_name + "_" + explode_arg.arg_name
889                         if explode_arg.from_hu_conv is not None:
890                             out_java_struct.write(explode_arg.from_hu_conv[0].replace(explode_arg.arg_name, expl_arg_name))
891                         else:
892                             out_java_struct.write(expl_arg_name)
893                     out_java_struct.write(")")
894                 elif info.from_hu_conv is not None:
895                     out_java_struct.write(info.from_hu_conv[0])
896                 else:
897                     out_java_struct.write(info.arg_name)
898             out_java_struct.write(");\n")
899             if ret_info.to_hu_conv is not None:
900                 if not takes_self:
901                     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")
902                 else:
903                     out_java_struct.write("\t\t" + ret_info.to_hu_conv.replace("\n", "\n\t\t") + "\n")
904
905             for idx, info in enumerate(arg_names):
906                 if idx == 0 and takes_self:
907                     pass
908                 elif info.arg_name in default_constructor_args:
909                     for explode_arg in default_constructor_args[info.arg_name]:
910                         expl_arg_name = info.arg_name + "_" + explode_arg.arg_name
911                         if explode_arg.from_hu_conv is not None and ret_info.to_hu_conv_name:
912                             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")
913                 elif info.from_hu_conv is not None and info.from_hu_conv[1] != "":
914                     if not takes_self and ret_info.to_hu_conv_name is not None:
915                         out_java_struct.write("\t\t" + info.from_hu_conv[1].replace("this", ret_info.to_hu_conv_name) + ";\n")
916                     else:
917                         out_java_struct.write("\t\t" + info.from_hu_conv[1] + ";\n")
918
919             if ret_info.to_hu_conv_name is not None:
920                 out_java_struct.write("\t\treturn " + ret_info.to_hu_conv_name + ";\n")
921             elif ret_info.java_ty != "void" and ret_info.rust_obj != "LDK" + struct_meth:
922                 out_java_struct.write("\t\treturn ret;\n")
923             out_java_struct.write("\t}\n\n")
924             out_java_struct.close()
925
926     def map_unitary_enum(struct_name, field_lines):
927         with recursiveOpenFile(f"{path_to_bindings_directory}/enums/{struct_name}.{consts.file_extension}", "w") as out_java_enum:
928             unitary_enums.add(struct_name)
929             for idx, struct_line in enumerate(field_lines):
930                 if idx == 0:
931                     assert(struct_line == "typedef enum %s {" % struct_name)
932                 elif idx == len(field_lines) - 3:
933                     assert(struct_line.endswith("_Sentinel,"))
934                 elif idx == len(field_lines) - 2:
935                     assert(struct_line == "} %s;" % struct_name)
936                 elif idx == len(field_lines) - 1:
937                     assert(struct_line == "")
938             (c_out, native_file_out, native_out) = consts.native_c_unitary_enum_map(struct_name, [x.strip().strip(",") for x in field_lines[1:-3]])
939             write_c(c_out)
940             out_java_enum.write(native_file_out)
941             out_java.write(native_out)
942
943     def map_complex_enum(struct_name, union_enum_items):
944         java_hu_type = struct_name.replace("LDK", "")
945         complex_enums.add(struct_name)
946         with open(sys.argv[3] + "/structs/" + java_hu_type + ".java", "w") as out_java_enum:
947             out_java_enum.write(consts.hu_struct_file_prefix)
948             out_java_enum.write("public class " + java_hu_type + " extends CommonBase {\n")
949             out_java_enum.write("\tprivate " + java_hu_type + "(Object _dummy, long ptr) { super(ptr); }\n")
950             out_java_enum.write("\t@Override @SuppressWarnings(\"deprecation\")\n")
951             out_java_enum.write("\tprotected void finalize() throws Throwable {\n")
952             out_java_enum.write("\t\tsuper.finalize();\n")
953             out_java_enum.write("\t\tif (ptr != 0) { bindings." + java_hu_type + "_free(ptr); }\n")
954             out_java_enum.write("\t}\n")
955             out_java_enum.write("\tstatic " + java_hu_type + " constr_from_ptr(long ptr) {\n")
956             out_java_enum.write("\t\tbindings." + struct_name + " raw_val = bindings." + struct_name + "_ref_from_ptr(ptr);\n")
957             java_hu_subclasses = ""
958
959             tag_field_lines = union_enum_items["field_lines"]
960             init_meth_jty_strs = {}
961             for idx, struct_line in enumerate(tag_field_lines):
962                 if idx == 0:
963                     assert(struct_line == "typedef enum %s_Tag {" % struct_name)
964                 elif idx == len(tag_field_lines) - 3:
965                     assert(struct_line.endswith("_Sentinel,"))
966                 elif idx == len(tag_field_lines) - 2:
967                     assert(struct_line == "} %s_Tag;" % struct_name)
968                 elif idx == len(tag_field_lines) - 1:
969                     assert(struct_line == "")
970
971             out_java.write("\tpublic static class " + struct_name + " {\n")
972             out_java.write("\t\tprivate " + struct_name + "() {}\n")
973             for idx, struct_line in enumerate(tag_field_lines):
974                 if idx != 0 and idx < len(tag_field_lines) - 3:
975                     var_name = struct_line.strip(' ,')[len(struct_name) + 1:]
976                     out_java.write("\t\tpublic final static class " + var_name + " extends " + struct_name + " {\n")
977                     java_hu_subclasses = java_hu_subclasses + "\tpublic final static class " + var_name + " extends " + java_hu_type + " {\n"
978                     out_java_enum.write("\t\tif (raw_val.getClass() == bindings." + struct_name + "." + var_name + ".class) {\n")
979                     out_java_enum.write("\t\t\treturn new " + var_name + "(ptr, (bindings." + struct_name + "." + var_name + ")raw_val);\n")
980                     init_meth_jty_str = ""
981                     init_meth_params = ""
982                     init_meth_body = ""
983                     hu_conv_body = ""
984                     if "LDK" + var_name in union_enum_items:
985                         enum_var_lines = union_enum_items["LDK" + var_name]
986                         for idx, field in enumerate(enum_var_lines):
987                             if idx != 0 and idx < len(enum_var_lines) - 2:
988                                 field_ty = map_type(field.strip(' ;'), False, None, False, True)
989                                 out_java.write("\t\t\tpublic " + field_ty.java_ty + " " + field_ty.arg_name + ";\n")
990                                 java_hu_subclasses = java_hu_subclasses + "\t\tpublic final " + field_ty.java_hu_ty + " " + field_ty.arg_name + ";\n"
991                                 if field_ty.to_hu_conv is not None:
992                                     hu_conv_body = hu_conv_body + "\t\t\t" + field_ty.java_ty + " " + field_ty.arg_name + " = obj." + field_ty.arg_name + ";\n"
993                                     hu_conv_body = hu_conv_body + "\t\t\t" + field_ty.to_hu_conv.replace("\n", "\n\t\t\t") + "\n"
994                                     hu_conv_body = hu_conv_body + "\t\t\tthis." + field_ty.arg_name + " = " + field_ty.to_hu_conv_name + ";\n"
995                                 else:
996                                     hu_conv_body = hu_conv_body + "\t\t\tthis." + field_ty.arg_name + " = obj." + field_ty.arg_name + ";\n"
997                                 init_meth_jty_str = init_meth_jty_str + field_ty.java_fn_ty_arg
998                                 if idx > 1:
999                                     init_meth_params = init_meth_params + ", "
1000                                 init_meth_params = init_meth_params + field_ty.java_ty + " " + field_ty.arg_name
1001                                 init_meth_body = init_meth_body + "this." + field_ty.arg_name + " = " + field_ty.arg_name + "; "
1002                         out_java.write("\t\t\t" + var_name + "(" + init_meth_params + ") { ")
1003                         out_java.write(init_meth_body)
1004                         out_java.write("}\n")
1005                     out_java.write("\t\t}\n")
1006                     out_java_enum.write("\t\t}\n")
1007                     java_hu_subclasses = java_hu_subclasses + "\t\tprivate " + var_name + "(long ptr, bindings." + struct_name + "." + var_name + " obj) {\n\t\t\tsuper(null, ptr);\n"
1008                     java_hu_subclasses = java_hu_subclasses + hu_conv_body
1009                     java_hu_subclasses = java_hu_subclasses + "\t\t}\n\t}\n"
1010                     init_meth_jty_strs[var_name] = init_meth_jty_str
1011             out_java.write("\t\tstatic native void init();\n")
1012             out_java.write("\t}\n")
1013             out_java_enum.write("\t\tassert false; return null; // Unreachable without extending the (internal) bindings interface\n\t}\n\n")
1014             out_java_enum.write(java_hu_subclasses)
1015             out_java.write("\tstatic { " + struct_name + ".init(); }\n")
1016             out_java.write("\tpublic static native " + struct_name + " " + struct_name + "_ref_from_ptr(long ptr);\n");
1017
1018             write_c(consts.c_complex_enum_pfx(struct_name, [x.strip(", ")[len(struct_name) + 1:] for x in tag_field_lines[1:-3]], init_meth_jty_strs))
1019
1020             write_c(consts.c_fn_ty_pfx + consts.c_complex_enum_pass_ty(struct_name) + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1ref_1from_1ptr (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " ptr) {\n")
1021             write_c("\t" + struct_name + " *obj = (" + struct_name + "*)ptr;\n")
1022             write_c("\tswitch(obj->tag) {\n")
1023             for idx, struct_line in enumerate(tag_field_lines):
1024                 if idx != 0 and idx < len(tag_field_lines) - 3:
1025                     var_name = struct_line.strip(' ,')[len(struct_name) + 1:]
1026                     write_c("\t\tcase " + struct_name + "_" + var_name + ": {\n")
1027                     c_params = []
1028                     if "LDK" + var_name in union_enum_items:
1029                         enum_var_lines = union_enum_items["LDK" + var_name]
1030                         for idx, field in enumerate(enum_var_lines):
1031                             if idx != 0 and idx < len(enum_var_lines) - 2:
1032                                 field_map = map_type(field.strip(' ;'), False, None, False, True)
1033                                 if field_map.ret_conv is not None:
1034                                     write_c("\t\t\t" + field_map.ret_conv[0].replace("\n", "\n\t\t\t"))
1035                                     write_c("obj->" + camel_to_snake(var_name) + "." + field_map.arg_name)
1036                                     write_c(field_map.ret_conv[1].replace("\n", "\n\t\t\t") + "\n")
1037                                     c_params.append(field_map.ret_conv_name)
1038                                 else:
1039                                     c_params.append("obj->" + camel_to_snake(var_name) + "." + field_map.arg_name)
1040                     write_c("\t\t\treturn " + consts.c_constr_native_complex_enum(struct_name, var_name, c_params) + ";\n")
1041                     write_c("\t\t}\n")
1042             write_c("\t\tdefault: abort();\n")
1043             write_c("\t}\n}\n")
1044             out_java_enum.write("}\n")
1045
1046     def map_trait(struct_name, field_var_lines, trait_fn_lines):
1047         with open(f"{path_to_bindings_directory}/structs/{struct_name.replace('LDK', '')}.{consts.file_extension}", "w") as out_java_trait:
1048             field_var_convs = []
1049             for var_line in field_var_lines:
1050                 if var_line.group(1) in trait_structs:
1051                     field_var_convs.append((var_line.group(1), var_line.group(2)))
1052                 else:
1053                     field_var_convs.append(map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False))
1054
1055             field_fns = []
1056             for fn_line in trait_fn_lines:
1057                 ret_ty_info = map_type(fn_line.group(2), True, None, False, False)
1058                 is_const = fn_line.group(4) is not None
1059
1060                 arg_tys = []
1061                 for idx, arg in enumerate(fn_line.group(5).split(',')):
1062                     if arg == "":
1063                         continue
1064                     arg_conv_info = map_type(arg, True, None, False, False)
1065                     arg_tys.append(arg_conv_info)
1066                 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys))
1067
1068             write_c(consts.native_c_map_trait(struct_name, field_var_convs, field_fns)[1])
1069
1070             out_java_trait.write(consts.hu_struct_file_prefix)
1071             out_java_trait.write("public class " + struct_name.replace("LDK","") + " extends CommonBase {\n")
1072             out_java_trait.write("\tfinal bindings." + struct_name + " bindings_instance;\n")
1073             out_java_trait.write("\t" + struct_name.replace("LDK", "") + "(Object _dummy, long ptr) { super(ptr); bindings_instance = null; }\n")
1074             out_java_trait.write("\tprivate " + struct_name.replace("LDK", "") + "(bindings." + struct_name + " arg")
1075             for idx, var_line in enumerate(field_var_lines):
1076                 if var_line.group(1) in trait_structs:
1077                     out_java_trait.write(", bindings." + var_line.group(1) + " " + var_line.group(2))
1078                 else:
1079                     out_java_trait.write(", " + field_var_convs[idx].java_hu_ty + " " + var_line.group(2))
1080             out_java_trait.write(") {\n")
1081             out_java_trait.write("\t\tsuper(bindings." + struct_name + "_new(arg")
1082             for idx, var_line in enumerate(field_var_lines):
1083                 if var_line.group(1) in trait_structs:
1084                     out_java_trait.write(", " + var_line.group(2))
1085                 elif field_var_convs[idx].from_hu_conv is not None:
1086                     out_java_trait.write(", " + field_var_convs[idx].from_hu_conv[0])
1087                 else:
1088                     out_java_trait.write(", " + var_line.group(2))
1089             out_java_trait.write("));\n")
1090             out_java_trait.write("\t\tthis.ptrs_to.add(arg);\n")
1091             for idx, var_line in enumerate(field_var_lines):
1092                 if var_line.group(1) in trait_structs:
1093                     out_java_trait.write("\t\tthis.ptrs_to.add(" + var_line.group(2) + ");\n")
1094                 elif field_var_convs[idx].from_hu_conv is not None and field_var_convs[idx].from_hu_conv[1] != "":
1095                     out_java_trait.write("\t\t" + field_var_convs[idx].from_hu_conv[1] + ";\n")
1096             out_java_trait.write("\t\tthis.bindings_instance = arg;\n")
1097             out_java_trait.write("\t}\n")
1098             out_java_trait.write("\t@Override @SuppressWarnings(\"deprecation\")\n")
1099             out_java_trait.write("\tprotected void finalize() throws Throwable {\n")
1100             out_java_trait.write("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); } super.finalize();\n")
1101             out_java_trait.write("\t}\n\n")
1102
1103             java_trait_constr = "\tprivate static class " + struct_name + "Holder { " + struct_name.replace("LDK", "") + " held; }\n"
1104             java_trait_constr = java_trait_constr + "\tpublic static " + struct_name.replace("LDK", "") + " new_impl(" + struct_name.replace("LDK", "") + "Interface arg"
1105             for idx, var_line in enumerate(field_var_lines):
1106                 if var_line.group(1) in trait_structs:
1107                     # Ideally we'd be able to take any instance of the interface, but our C code can only represent
1108                     # Java-implemented version, so we require users pass a Java implementation here :/
1109                     java_trait_constr = java_trait_constr + ", " + var_line.group(1).replace("LDK", "") + "." + var_line.group(1).replace("LDK", "") + "Interface " + var_line.group(2) + "_impl"
1110                 else:
1111                     java_trait_constr = java_trait_constr + ", " + field_var_convs[idx].java_hu_ty + " " + var_line.group(2)
1112             java_trait_constr = java_trait_constr + ") {\n\t\tfinal " + struct_name + "Holder impl_holder = new " + struct_name + "Holder();\n"
1113             java_trait_constr = java_trait_constr + "\t\timpl_holder.held = new " + struct_name.replace("LDK", "") + "(new bindings." + struct_name + "() {\n"
1114             out_java_trait.write("\tpublic static interface " + struct_name.replace("LDK", "") + "Interface {\n")
1115             out_java.write("\tpublic interface " + struct_name + " {\n")
1116             java_meths = []
1117             for fn_line in trait_fn_lines:
1118                 java_meth_descr = "("
1119                 if fn_line.group(3) != "free" and fn_line.group(3) != "clone":
1120                     ret_ty_info = map_type(fn_line.group(2), True, None, False, False)
1121
1122                     out_java.write("\t\t " + ret_ty_info.java_ty + " " + fn_line.group(3) + "(")
1123                     java_trait_constr = java_trait_constr + "\t\t\t@Override public " + ret_ty_info.java_ty + " " + fn_line.group(3) + "("
1124                     out_java_trait.write("\t\t" + ret_ty_info.java_hu_ty + " " + fn_line.group(3) + "(")
1125                     is_const = fn_line.group(4) is not None
1126
1127                     arg_names = []
1128                     for idx, arg in enumerate(fn_line.group(5).split(',')):
1129                         if arg == "":
1130                             continue
1131                         if idx >= 2:
1132                             out_java.write(", ")
1133                             java_trait_constr = java_trait_constr + ", "
1134                             out_java_trait.write(", ")
1135                         arg_conv_info = map_type(arg, True, None, False, False)
1136                         out_java.write(arg_conv_info.java_ty + " " + arg_conv_info.arg_name)
1137                         out_java_trait.write(arg_conv_info.java_hu_ty + " " + arg_conv_info.arg_name)
1138                         java_trait_constr = java_trait_constr + arg_conv_info.java_ty + " " + arg_conv_info.arg_name
1139                         arg_names.append(arg_conv_info)
1140                         java_meth_descr = java_meth_descr + arg_conv_info.java_fn_ty_arg
1141                     java_meth_descr = java_meth_descr + ")" + ret_ty_info.java_fn_ty_arg
1142                     java_meths.append((fn_line, java_meth_descr))
1143
1144                     out_java.write(");\n")
1145                     out_java_trait.write(");\n")
1146                     java_trait_constr = java_trait_constr + ") {\n"
1147
1148                     for arg_info in arg_names:
1149                         if arg_info.to_hu_conv is not None:
1150                             java_trait_constr = java_trait_constr + "\t\t\t\t" + arg_info.to_hu_conv.replace("\n", "\n\t\t\t\t") + "\n"
1151
1152                     if ret_ty_info.java_ty != "void":
1153                         java_trait_constr = java_trait_constr + "\t\t\t\t" + ret_ty_info.java_hu_ty + " ret = arg." + fn_line.group(3) + "("
1154                     else:
1155                         java_trait_constr = java_trait_constr + "\t\t\t\targ." + fn_line.group(3) + "("
1156
1157                     for idx, arg_info in enumerate(arg_names):
1158                         if idx != 0:
1159                             java_trait_constr = java_trait_constr + ", "
1160                         if arg_info.to_hu_conv_name is not None:
1161                             java_trait_constr = java_trait_constr + arg_info.to_hu_conv_name
1162                         else:
1163                             java_trait_constr = java_trait_constr + arg_info.arg_name
1164
1165                     java_trait_constr = java_trait_constr + ");\n"
1166                     if ret_ty_info.java_ty != "void":
1167                         if ret_ty_info.from_hu_conv is not None:
1168                             java_trait_constr = java_trait_constr + "\t\t\t\t" + ret_ty_info.java_ty + " result = " + ret_ty_info.from_hu_conv[0] + ";\n"
1169                             if ret_ty_info.from_hu_conv[1] != "":
1170                                 java_trait_constr = java_trait_constr + "\t\t\t\t" + ret_ty_info.from_hu_conv[1].replace("this", "impl_holder.held") + ";\n"
1171                             if ret_ty_info.rust_obj in result_types:
1172                                 # Avoid double-free by breaking the result - we should learn to clone these and then we can be safe instead
1173                                 java_trait_constr = java_trait_constr + "\t\t\t\tret.ptr = 0;\n"
1174                             java_trait_constr = java_trait_constr + "\t\t\t\treturn result;\n"
1175                         else:
1176                             java_trait_constr = java_trait_constr + "\t\t\t\treturn ret;\n"
1177                     java_trait_constr = java_trait_constr + "\t\t\t}\n"
1178             java_trait_constr = java_trait_constr + "\t\t}"
1179             for var_line in field_var_lines:
1180                 if var_line.group(1) in trait_structs:
1181                     java_trait_constr = java_trait_constr + ", " + var_line.group(2) + ".new_impl(" + var_line.group(2) + "_impl).bindings_instance"
1182                 else:
1183                     java_trait_constr = java_trait_constr + ", " + var_line.group(2)
1184             out_java_trait.write("\t}\n")
1185             out_java_trait.write(java_trait_constr + ");\n\t\treturn impl_holder.held;\n\t}\n")
1186
1187             # Write out a clone function whether we need one or not, as we use them in moving to rust
1188             write_c("static void* " + struct_name + "_JCalls_clone(const void* this_arg) {\n")
1189             write_c("\t" + struct_name + "_JCalls *j_calls = (" + struct_name + "_JCalls*) this_arg;\n")
1190             write_c("\tatomic_fetch_add_explicit(&j_calls->refcnt, 1, memory_order_release);\n")
1191             for var_line in field_var_lines:
1192                 if var_line.group(1) in trait_structs:
1193                     write_c("\tatomic_fetch_add_explicit(&j_calls->" + var_line.group(2) + "->refcnt, 1, memory_order_release);\n")
1194             write_c("\treturn (void*) this_arg;\n")
1195             write_c("}\n")
1196
1197             out_java.write("\t}\n")
1198
1199             out_java.write("\tpublic static native long " + struct_name + "_new(" + struct_name + " impl")
1200             write_c("static inline " + struct_name + " " + struct_name + "_init (" + consts.c_fn_args_pfx + ", jobject o")
1201             for idx, var_line in enumerate(field_var_lines):
1202                 if var_line.group(1) in trait_structs:
1203                     out_java.write(", " + var_line.group(1) + " " + var_line.group(2))
1204                     write_c(", jobject " + var_line.group(2))
1205                 else:
1206                     out_java.write(", " + field_var_convs[idx].java_ty + " " + var_line.group(2))
1207                     write_c(", " + field_var_convs[idx].c_ty + " " + var_line.group(2))
1208             out_java.write(");\n")
1209             write_c(") {\n")
1210
1211             write_c("\tjclass c = (*env)->GetObjectClass(env, o);\n")
1212             write_c("\tCHECK(c != NULL);\n")
1213             write_c("\t" + struct_name + "_JCalls *calls = MALLOC(sizeof(" + struct_name + "_JCalls), \"" + struct_name + "_JCalls\");\n")
1214             write_c("\tatomic_init(&calls->refcnt, 1);\n")
1215             write_c("\tDO_ASSERT((*env)->GetJavaVM(env, &calls->vm) == 0);\n")
1216             write_c("\tcalls->o = (*env)->NewWeakGlobalRef(env, o);\n")
1217             for (fn_line, java_meth_descr) in java_meths:
1218                 if fn_line.group(3) != "free" and fn_line.group(3) != "clone":
1219                     write_c("\tcalls->" + fn_line.group(3) + "_meth = (*env)->GetMethodID(env, c, \"" + fn_line.group(3) + "\", \"" + java_meth_descr + "\");\n")
1220                     write_c("\tCHECK(calls->" + fn_line.group(3) + "_meth != NULL);\n")
1221             for idx, var_line in enumerate(field_var_lines):
1222                 if var_line.group(1) not in trait_structs and field_var_convs[idx].arg_conv is not None:
1223                     write_c("\n\t" + field_var_convs[idx].arg_conv.replace("\n", "\n\t") +"\n")
1224             write_c("\n\t" + struct_name + " ret = {\n")
1225             write_c("\t\t.this_arg = (void*) calls,\n")
1226             for fn_line in trait_fn_lines:
1227                 if fn_line.group(3) != "free" and fn_line.group(3) != "clone":
1228                     write_c("\t\t." + fn_line.group(3) + " = " + fn_line.group(3) + "_jcall,\n")
1229                 elif fn_line.group(3) == "free":
1230                     write_c("\t\t.free = " + struct_name + "_JCalls_free,\n")
1231                 else:
1232                     write_c("\t\t.clone = " + struct_name + "_JCalls_clone,\n")
1233             for idx, var_line in enumerate(field_var_lines):
1234                 if var_line.group(1) in trait_structs:
1235                     write_c("\t\t." + var_line.group(2) + " = " + var_line.group(1) + "_init(env, clz, " + var_line.group(2) + "),\n")
1236                 elif field_var_convs[idx].arg_conv_name is not None:
1237                     write_c("\t\t." + var_line.group(2) + " = " + field_var_convs[idx].arg_conv_name + ",\n")
1238                     write_c("\t\t.set_" + var_line.group(2) + " = NULL,\n")
1239                 else:
1240                     write_c("\t\t." + var_line.group(2) + " = " + var_line.group(2) + ",\n")
1241                     write_c("\t\t.set_" + var_line.group(2) + " = NULL,\n")
1242             write_c("\t};\n")
1243             for var_line in field_var_lines:
1244                 if var_line.group(1) in trait_structs:
1245                     write_c("\tcalls->" + var_line.group(2) + " = ret." + var_line.group(2) + ".this_arg;\n")
1246             write_c("\treturn ret;\n")
1247             write_c("}\n")
1248
1249             write_c(consts.c_fn_ty_pfx + "long " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1new (" + consts.c_fn_args_pfx + ", jobject o")
1250             for idx, var_line in enumerate(field_var_lines):
1251                 if var_line.group(1) in trait_structs:
1252                     write_c(", jobject " + var_line.group(2))
1253                 else:
1254                     write_c(", " + field_var_convs[idx].c_ty + " " + var_line.group(2))
1255             write_c(") {\n")
1256             write_c("\t" + struct_name + " *res_ptr = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n")
1257             write_c("\t*res_ptr = " + struct_name + "_init(env, clz, o")
1258             for var_line in field_var_lines:
1259                 write_c(", " + var_line.group(2))
1260             write_c(");\n")
1261             write_c("\treturn (long)res_ptr;\n")
1262             write_c("}\n")
1263
1264             out_java.write("\tpublic static native " + struct_name + " " + struct_name + "_get_obj_from_jcalls(long val);\n")
1265             write_c(consts.c_fn_ty_pfx + "jobject " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1obj_1from_1jcalls (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " val) {\n")
1266             write_c("\tjobject ret = (*env)->NewLocalRef(env, ((" + struct_name + "_JCalls*)val)->o);\n")
1267             write_c("\tCHECK(ret != NULL);\n")
1268             write_c("\treturn ret;\n")
1269             write_c("}\n")
1270
1271         for fn_line in trait_fn_lines:
1272             # For now, just disable enabling the _call_log - we don't know how to inverse-map String
1273             is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
1274             if fn_line.group(3) != "free" and fn_line.group(3) != "clone" and fn_line.group(3) != "eq" and not is_log:
1275                 dummy_line = fn_line.group(2) + struct_name.replace("LDK", "") + "_" + fn_line.group(3) + " " + struct_name + "* this_arg" + fn_line.group(5) + "\n"
1276                 map_fn(dummy_line, re.compile("([A-Za-z_0-9]*) *([A-Za-z_0-9]*) *(.*)").match(dummy_line), None, "(this_arg_conv->" + fn_line.group(3) + ")(this_arg_conv->this_arg")
1277         for idx, var_line in enumerate(field_var_lines):
1278             if var_line.group(1) not in trait_structs:
1279                 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
1280                 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
1281                 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
1282                 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
1283                 write_c("}\n")
1284                 dummy_line = var_line.group(1) + " " + struct_name.replace("LDK", "") + "_get_" + var_line.group(2) + " " + struct_name + "* this_arg" + fn_line.group(5) + "\n"
1285                 map_fn(dummy_line, re.compile("([A-Za-z_0-9]*) *([A-Za-z_0-9]*) *(.*)").match(dummy_line), None, struct_name + "_set_get_" + var_line.group(2) + "(this_arg_conv")
1286
1287     def map_result(struct_name, res_ty, err_ty):
1288         result_types.add(struct_name)
1289         human_ty = struct_name.replace("LDKCResult", "Result")
1290         with open(f"{path_to_bindings_directory}/structs/{human_ty}.{consts.file_extension}", "w") as out_java_struct:
1291             out_java_struct.write(consts.hu_struct_file_prefix)
1292             out_java_struct.write("public class " + human_ty + " extends CommonBase {\n")
1293             out_java_struct.write("\tprivate " + human_ty + "(Object _dummy, long ptr) { super(ptr); }\n")
1294             out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
1295             out_java_struct.write("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); } super.finalize();\n")
1296             out_java_struct.write("\t}\n\n")
1297             out_java_struct.write("\tstatic " + human_ty + " constr_from_ptr(long ptr) {\n")
1298             out_java_struct.write("\t\tif (bindings." + struct_name + "_result_ok(ptr)) {\n")
1299             out_java_struct.write("\t\t\treturn new " + human_ty + "_OK(null, ptr);\n")
1300             out_java_struct.write("\t\t} else {\n")
1301             out_java_struct.write("\t\t\treturn new " + human_ty + "_Err(null, ptr);\n")
1302             out_java_struct.write("\t\t}\n")
1303             out_java_struct.write("\t}\n")
1304
1305             res_map = map_type(res_ty + " res", True, None, False, True)
1306             err_map = map_type(err_ty + " err", True, None, False, True)
1307             can_clone = True
1308             if not res_map.is_native_primitive and (res_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
1309                 can_clone = False
1310             if not err_map.is_native_primitive and (err_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
1311                 can_clone = False
1312
1313             out_java.write("\tpublic static native boolean " + struct_name + "_result_ok(long arg);\n")
1314             write_c(consts.c_fn_ty_pfx + "jboolean " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1result_1ok (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " arg) {\n")
1315             write_c("\treturn ((" + struct_name + "*)arg)->result_ok;\n")
1316             write_c("}\n")
1317
1318             out_java.write("\tpublic static native " + res_map.java_ty + " " + struct_name + "_get_ok(long arg);\n")
1319             write_c(consts.c_fn_ty_pfx + res_map.c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1ok (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " arg) {\n")
1320             write_c("\t" + struct_name + " *val = (" + struct_name + "*)arg;\n")
1321             write_c("\tCHECK(val->result_ok);\n\t")
1322             out_java_struct.write("\tpublic static final class " + human_ty + "_OK extends " + human_ty + " {\n")
1323             if res_map.ret_conv is not None:
1324                 write_c(res_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.result)")
1325                 write_c(res_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + res_map.ret_conv_name)
1326             else:
1327                 write_c("return *val->contents.result")
1328             write_c(";\n}\n")
1329
1330             if res_map.java_hu_ty != "void":
1331                 out_java_struct.write("\t\tpublic final " + res_map.java_hu_ty + " res;\n")
1332             out_java_struct.write("\t\tprivate " + human_ty + "_OK(Object _dummy, long ptr) {\n")
1333             out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
1334             if res_map.java_hu_ty == "void":
1335                 pass
1336             elif res_map.to_hu_conv is not None:
1337                 out_java_struct.write("\t\t\t" + res_map.java_ty + " res = bindings." + struct_name + "_get_ok(ptr);\n")
1338                 out_java_struct.write("\t\t\t" + res_map.to_hu_conv.replace("\n", "\n\t\t\t"))
1339                 out_java_struct.write("\n\t\t\tthis.res = " + res_map.to_hu_conv_name + ";\n")
1340             else:
1341                 out_java_struct.write("\t\t\tthis.res = bindings." + struct_name + "_get_ok(ptr);\n")
1342             out_java_struct.write("\t\t}\n")
1343             if struct_name.startswith("LDKCResult_None"):
1344                 out_java_struct.write("\t\tpublic " + human_ty + "_OK() {\n\t\t\tthis(null, bindings.C" + human_ty + "_ok());\n")
1345             else:
1346                 out_java_struct.write("\t\tpublic " + human_ty + "_OK(" + res_map.java_hu_ty + " res) {\n")
1347                 if res_map.from_hu_conv is not None:
1348                     out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_ok(" + res_map.from_hu_conv[0] + "));\n")
1349                     if res_map.from_hu_conv[1] != "":
1350                         out_java_struct.write("\t\t\t" + res_map.from_hu_conv[1] + ";\n")
1351                 else:
1352                     out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_ok(res));\n")
1353             out_java_struct.write("\t\t}\n\t}\n\n")
1354
1355             out_java.write("\tpublic static native " + err_map.java_ty + " " + struct_name + "_get_err(long arg);\n")
1356             write_c(consts.c_fn_ty_pfx + err_map.c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1err (" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " arg) {\n")
1357             write_c("\t" + struct_name + " *val = (" + struct_name + "*)arg;\n")
1358             write_c("\tCHECK(!val->result_ok);\n\t")
1359             out_java_struct.write("\tpublic static final class " + human_ty + "_Err extends " + human_ty + " {\n")
1360             if err_map.ret_conv is not None:
1361                 write_c(err_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.err)")
1362                 write_c(err_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + err_map.ret_conv_name)
1363             else:
1364                 write_c("return *val->contents.err")
1365             write_c(";\n}\n")
1366
1367             if err_map.java_hu_ty != "void":
1368                 out_java_struct.write("\t\tpublic final " + err_map.java_hu_ty + " err;\n")
1369             out_java_struct.write("\t\tprivate " + human_ty + "_Err(Object _dummy, long ptr) {\n")
1370             out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
1371             if err_map.java_hu_ty == "void":
1372                 pass
1373             elif err_map.to_hu_conv is not None:
1374                 out_java_struct.write("\t\t\t" + err_map.java_ty + " err = bindings." + struct_name + "_get_err(ptr);\n")
1375                 out_java_struct.write("\t\t\t" + err_map.to_hu_conv.replace("\n", "\n\t\t\t"))
1376                 out_java_struct.write("\n\t\t\tthis.err = " + err_map.to_hu_conv_name + ";\n")
1377             else:
1378                 out_java_struct.write("\t\t\tthis.err = bindings." + struct_name + "_get_err(ptr);\n")
1379             out_java_struct.write("\t\t}\n")
1380
1381             if struct_name.endswith("NoneZ"):
1382                 out_java_struct.write("\t\tpublic " + human_ty + "_Err() {\n\t\t\tthis(null, bindings.C" + human_ty + "_err());\n")
1383             else:
1384                 out_java_struct.write("\t\tpublic " + human_ty + "_Err(" + err_map.java_hu_ty + " err) {\n")
1385                 if err_map.from_hu_conv is not None:
1386                     out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_err(" + err_map.from_hu_conv[0] + "));\n")
1387                     if err_map.from_hu_conv[1] != "":
1388                         out_java_struct.write("\t\t\t" + err_map.from_hu_conv[1] + ";\n")
1389                 else:
1390                     out_java_struct.write("\t\t\tthis(null, bindings.C" + human_ty + "_err(err));\n")
1391             out_java_struct.write("\t\t}\n\t}\n}\n")
1392
1393             if can_clone:
1394                 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1395                 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1396                 write_c("\t" + struct_name + " res = { .result_ok = orig->result_ok };\n")
1397                 write_c("\tif (orig->result_ok) {\n")
1398                 if res_map.c_ty == "void":
1399                     write_c("\t\tres.contents.result = NULL;\n")
1400                 else:
1401                     if res_map.is_native_primitive:
1402                         write_c("\t\t" + res_map.c_ty + "* contents = MALLOC(sizeof(" + res_map.c_ty + "), \"" + res_map.c_ty + " result OK clone\");\n")
1403                         write_c("\t\t*contents = *orig->contents.result;\n")
1404                     else:
1405                         write_c("\t\t" + res_map.rust_obj + "* contents = MALLOC(sizeof(" + res_map.rust_obj + "), \"" + res_map.rust_obj + " result OK clone\");\n")
1406                         write_c("\t\t*contents = " + res_map.rust_obj.replace("LDK", "") + "_clone(orig->contents.result);\n")
1407                     write_c("\t\tres.contents.result = contents;\n")
1408                 write_c("\t} else {\n")
1409                 if err_map.c_ty == "void":
1410                     write_c("\t\tres.contents.err = NULL;\n")
1411                 else:
1412                     if err_map.is_native_primitive:
1413                         write_c("\t\t" + err_map.c_ty + "* contents = MALLOC(sizeof(" + err_map.c_ty + "), \"" + err_map.c_ty + " result Err clone\");\n")
1414                         write_c("\t\t*contents = *orig->contents.err;\n")
1415                     else:
1416                         write_c("\t\t" + err_map.rust_obj + "* contents = MALLOC(sizeof(" + err_map.rust_obj + "), \"" + err_map.rust_obj + " result Err clone\");\n")
1417                         write_c("\t\t*contents = " + err_map.rust_obj.replace("LDK", "") + "_clone(orig->contents.err);\n")
1418                     write_c("\t\tres.contents.err = contents;\n")
1419                 write_c("\t}\n\treturn res;\n}\n")
1420
1421     def map_tuple(struct_name, field_lines):
1422         out_java.write("\tpublic static native long " + struct_name + "_new(")
1423         write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1new(" + consts.c_fn_args_pfx)
1424         ty_list = []
1425         for idx, line in enumerate(field_lines):
1426             if idx != 0 and idx < len(field_lines) - 2:
1427                 ty_info = java_c_types(line.strip(';'), None)
1428                 if idx != 1:
1429                     out_java.write(", ")
1430                 e = chr(ord('a') + idx - 1)
1431                 out_java.write(ty_info.java_ty + " " + e)
1432                 write_c(", " + ty_info.c_ty + " " + e)
1433                 ty_list.append(ty_info)
1434         tuple_types[struct_name] = (ty_list, struct_name)
1435         out_java.write(");\n")
1436         write_c(") {\n")
1437         write_c("\t" + struct_name + "* ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n")
1438         can_clone = True
1439         clone_str = "static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n"
1440         clone_str = clone_str + "\t" + struct_name + " ret = {\n"
1441         for idx, line in enumerate(field_lines):
1442             if idx != 0 and idx < len(field_lines) - 2:
1443                 ty_info = map_type(line.strip(';'), False, None, False, False)
1444                 e = chr(ord('a') + idx - 1)
1445                 if ty_info.arg_conv is not None:
1446                     write_c("\t" + ty_info.arg_conv.replace("\n", "\n\t"))
1447                     write_c("\n\tret->" + e + " = " + ty_info.arg_conv_name + ";\n")
1448                 else:
1449                     write_c("\tret->" + e + " = " + e + ";\n")
1450                 if ty_info.arg_conv_cleanup is not None:
1451                     write_c("\t//TODO: Really need to call " + ty_info.arg_conv_cleanup + " here\n")
1452                 if not ty_info.is_native_primitive and (ty_info.rust_obj.replace("LDK", "") + "_clone") not in clone_fns:
1453                     can_clone = False
1454                 elif can_clone and ty_info.is_native_primitive:
1455                     clone_str = clone_str + "\t\t." + chr(ord('a') + idx - 1) + " = orig->" + chr(ord('a') + idx - 1) + ",\n"
1456                 elif can_clone:
1457                     clone_str = clone_str + "\t\t." + chr(ord('a') + idx - 1) + " = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->" + chr(ord('a') + idx - 1) + "),\n"
1458         write_c("\treturn (long)ret;\n")
1459         write_c("}\n")
1460
1461         if can_clone:
1462             clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1463             write_c(clone_str)
1464             write_c("\t};\n\treturn ret;\n}\n")
1465
1466         for idx, ty_info in enumerate(ty_list):
1467             e = chr(ord('a') + idx)
1468             out_java.write("\tpublic static native " + ty_info.java_ty + " " + struct_name + "_get_" + e + "(long ptr);\n")
1469             write_c(consts.c_fn_ty_pfx + ty_info.c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1get_1" + e + "(" + consts.c_fn_args_pfx + ", " + consts.ptr_c_ty + " ptr) {\n")
1470             write_c("\t" + struct_name + " *tuple = (" + struct_name + "*)ptr;\n")
1471             conv_info = map_type_with_info(ty_info, False, None, False, True)
1472             if conv_info.ret_conv is not None:
1473                 write_c("\t" + conv_info.ret_conv[0].replace("\n", "\n\t") + "tuple->" + e + conv_info.ret_conv[1].replace("\n", "\n\t") + "\n")
1474                 write_c("\treturn " + conv_info.ret_conv_name + ";\n")
1475             else:
1476                 write_c("\treturn tuple->" + e + ";\n")
1477             write_c("}\n")
1478
1479     out_java.write("""package org.ldk.impl;
1480 import org.ldk.enums.*;
1481
1482 public class bindings {
1483         public static class VecOrSliceDef {
1484                 public long dataptr;
1485                 public long datalen;
1486                 public long stride;
1487                 public VecOrSliceDef(long dataptr, long datalen, long stride) {
1488                         this.dataptr = dataptr; this.datalen = datalen; this.stride = stride;
1489                 }
1490         }
1491         static {
1492                 System.loadLibrary(\"lightningjni\");
1493                 init(java.lang.Enum.class, VecOrSliceDef.class);
1494                 init_class_cache();
1495         }
1496         static native void init(java.lang.Class c, java.lang.Class slicedef);
1497         static native void init_class_cache();
1498
1499         public static native boolean deref_bool(long ptr);
1500         public static native long deref_long(long ptr);
1501         public static native void free_heap_ptr(long ptr);
1502         public static native byte[] read_bytes(long ptr, long len);
1503         public static native byte[] get_u8_slice_bytes(long slice_ptr);
1504         public static native long bytes_to_u8_vec(byte[] bytes);
1505         public static native long new_txpointer_copy_data(byte[] txdata);
1506         public static native void txpointer_free(long ptr);
1507         public static native byte[] txpointer_get_buffer(long ptr);
1508         public static native long vec_slice_len(long vec);
1509         public static native long new_empty_slice_vec();
1510
1511 """)
1512
1513     with recursiveOpenFile(f"{path_to_bindings_directory}/structs/CommonBase.{consts.file_extension}", "w") as out_java_struct:
1514         out_java_struct.write(consts.common_base)
1515
1516     in_block_comment = False
1517     cur_block_obj = None
1518
1519     const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
1520
1521     line_indicates_result_regex = re.compile("^   union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
1522     line_indicates_vec_regex = re.compile("^   (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
1523     line_indicates_opaque_regex = re.compile("^   bool is_owned;$")
1524     line_indicates_trait_regex = re.compile("^   (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
1525     assert(line_indicates_trait_regex.match("   uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
1526     assert(line_indicates_trait_regex.match("   struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
1527     assert(line_indicates_trait_regex.match("   void *(*clone)(const void *this_arg);"))
1528     assert(line_indicates_trait_regex.match("   struct LDKCVec_u8Z (*write)(const void *this_arg);"))
1529     line_field_var_regex = re.compile("^   struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
1530     assert(line_field_var_regex.match("   struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
1531     assert(line_field_var_regex.match("   struct LDKChannelPublicKeys pubkeys;"))
1532     struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
1533     assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
1534     assert(struct_name_regex.match("typedef enum LDKNetwork {"))
1535
1536     union_enum_items = {}
1537     result_ptr_struct_items = {}
1538     for line in in_h:
1539         if in_block_comment:
1540             if line.endswith("*/\n"):
1541                 in_block_comment = False
1542         elif cur_block_obj is not None:
1543             cur_block_obj  = cur_block_obj + line
1544             if line.startswith("} "):
1545                 field_lines = []
1546                 struct_name = None
1547                 vec_ty = None
1548                 obj_lines = cur_block_obj.split("\n")
1549                 is_opaque = False
1550                 result_contents = None
1551                 is_unitary_enum = False
1552                 is_union_enum = False
1553                 is_union = False
1554                 is_tuple = False
1555                 trait_fn_lines = []
1556                 field_var_lines = []
1557
1558                 for idx, struct_line in enumerate(obj_lines):
1559                     if struct_line.strip().startswith("/*"):
1560                         in_block_comment = True
1561                     if in_block_comment:
1562                         if struct_line.endswith("*/"):
1563                             in_block_comment = False
1564                     else:
1565                         struct_name_match = struct_name_regex.match(struct_line)
1566                         if struct_name_match is not None:
1567                             struct_name = struct_name_match.group(3)
1568                             if struct_name_match.group(1) == "enum":
1569                                 if not struct_name.endswith("_Tag"):
1570                                     is_unitary_enum = True
1571                                 else:
1572                                     is_union_enum = True
1573                             elif struct_name_match.group(1) == "union":
1574                                 is_union = True
1575                         if line_indicates_opaque_regex.match(struct_line):
1576                             is_opaque = True
1577                         result_match = line_indicates_result_regex.match(struct_line)
1578                         if result_match is not None:
1579                             result_contents = result_match.group(1)
1580                         vec_ty_match = line_indicates_vec_regex.match(struct_line)
1581                         if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
1582                             vec_ty = vec_ty_match.group(2)
1583                         elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
1584                             is_tuple = True
1585                         trait_fn_match = line_indicates_trait_regex.match(struct_line)
1586                         if trait_fn_match is not None:
1587                             trait_fn_lines.append(trait_fn_match)
1588                         field_var_match = line_field_var_regex.match(struct_line)
1589                         if field_var_match is not None:
1590                             field_var_lines.append(field_var_match)
1591                         field_lines.append(struct_line)
1592
1593                 assert(struct_name is not None)
1594                 assert(len(trait_fn_lines) == 0 or not (is_opaque or is_unitary_enum or is_union_enum or is_union or result_contents is not None or vec_ty is not None))
1595                 assert(not is_opaque or not (len(trait_fn_lines) != 0 or is_unitary_enum or is_union_enum or is_union or result_contents is not None or vec_ty is not None))
1596                 assert(not is_unitary_enum or not (len(trait_fn_lines) != 0 or is_opaque or is_union_enum or is_union or result_contents is not None or vec_ty is not None))
1597                 assert(not is_union_enum or not (len(trait_fn_lines) != 0 or is_unitary_enum or is_opaque or is_union or result_contents is not None or vec_ty is not None))
1598                 assert(not is_union or not (len(trait_fn_lines) != 0 or is_unitary_enum or is_union_enum or is_opaque or result_contents is not None or vec_ty is not None))
1599                 assert(result_contents is None or not (len(trait_fn_lines) != 0 or is_unitary_enum or is_union_enum or is_opaque or is_union or vec_ty is not None))
1600                 assert(vec_ty is None or not (len(trait_fn_lines) != 0 or is_unitary_enum or is_union_enum or is_opaque or is_union or result_contents is not None))
1601
1602                 if is_opaque:
1603                     opaque_structs.add(struct_name)
1604                     with open(f"{path_to_bindings_directory}/structs/{struct_name.replace('LDK', '')}.{consts.file_extension}", "w") as out_java_struct:
1605                         out_java_struct.write(consts.hu_struct_file_prefix)
1606                         out_java_struct.write("public class " + struct_name.replace("LDK","") + " extends CommonBase")
1607                         if struct_name.startswith("LDKLocked"):
1608                             out_java_struct.write(" implements AutoCloseable")
1609                         out_java_struct.write(" {\n")
1610                         out_java_struct.write("\t" + struct_name.replace("LDK", "") + "(Object _dummy, long ptr) { super(ptr); }\n")
1611                         if struct_name.startswith("LDKLocked"):
1612                             out_java_struct.write("\t@Override public void close() {\n")
1613                         else:
1614                             out_java_struct.write("\t@Override @SuppressWarnings(\"deprecation\")\n")
1615                             out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
1616                             out_java_struct.write("\t\tsuper.finalize();\n")
1617                         out_java_struct.write("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); }\n")
1618                         out_java_struct.write("\t}\n\n")
1619                 elif result_contents is not None:
1620                     assert result_contents in result_ptr_struct_items
1621                     res_ty, err_ty = result_ptr_struct_items[result_contents]
1622                     map_result(struct_name, res_ty, err_ty)
1623                 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1624                     for line in field_lines:
1625                         if line.endswith("*result;"):
1626                             res_ty = line[:-8].strip()
1627                         elif line.endswith("*err;"):
1628                             err_ty = line[:-5].strip()
1629                     result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1630                     result_types.add(struct_name[:-3])
1631                 elif is_tuple:
1632                     map_tuple(struct_name, field_lines)
1633                 elif vec_ty is not None:
1634                     ty_info = map_type(vec_ty + " arr_elem", False, None, False, False)
1635                     if len(ty_info.java_fn_ty_arg) == 1: # ie we're a primitive of some form
1636                         out_java.write("\tpublic static native long " + struct_name + "_new(" + ty_info.java_ty + "[] elems);\n")
1637                         write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_pfx + struct_name.replace("_", "_1") + "_1new(" + consts.c_fn_args_pfx + ", " + ty_info.c_ty + "Array elems) {\n")
1638                         write_c("\t" + struct_name + " *ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n")
1639                         write_c("\tret->datalen = " + consts.get_native_arr_len_call[0] + "elems" + consts.get_native_arr_len_call[1] + ";\n")
1640                         write_c("\tif (ret->datalen == 0) {\n")
1641                         write_c("\t\tret->data = NULL;\n")
1642                         write_c("\t} else {\n")
1643                         write_c("\t\tret->data = MALLOC(sizeof(" + vec_ty + ") * ret->datalen, \"" + struct_name + " Data\");\n")
1644                         write_c("\t\t" + ty_info.c_ty + " *java_elems = " + consts.get_native_arr_ptr_call[0] + "elems" + consts.get_native_arr_ptr_call[1] + ";\n")
1645                         write_c("\t\tfor (size_t i = 0; i < ret->datalen; i++) {\n")
1646                         if ty_info.arg_conv is not None:
1647                             write_c("\t\t\t" + ty_info.c_ty + " arr_elem = java_elems[i];\n")
1648                             write_c("\t\t\t" + ty_info.arg_conv.replace("\n", "\n\t\t\t") + "\n")
1649                             write_c("\t\t\tret->data[i] = " + ty_info.arg_conv_name + ";\n")
1650                             assert ty_info.arg_conv_cleanup is None
1651                         else:
1652                             write_c("\t\t\tret->data[i] = java_elems[i];\n")
1653                         write_c("\t\t}\n")
1654                         cleanup = consts.release_native_arr_ptr_call("elems", "java_elems")
1655                         if cleanup is not None:
1656                             write_c("\t\t" + cleanup + ";\n")
1657                         write_c("\t}\n")
1658                         write_c("\treturn (long)ret;\n")
1659                         write_c("}\n")
1660
1661                     if ty_info.is_native_primitive:
1662                         clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1663                         write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1664                         write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1665                         write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1666                         write_c("\treturn ret;\n}\n")
1667                     elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1668                         ty_name = "CVec_" + ty_info.rust_obj.replace("LDK", "") + "Z";
1669                         clone_fns.add(ty_name + "_clone")
1670                         write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1671                         write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1672                         write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1673                         write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1674                         write_c("\t}\n\treturn ret;\n}\n")
1675                 elif is_union_enum:
1676                     assert(struct_name.endswith("_Tag"))
1677                     struct_name = struct_name[:-4]
1678                     union_enum_items[struct_name] = {"field_lines": field_lines}
1679                 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1680                     enum_var_name = struct_name.split("_")
1681                     union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1682                 elif struct_name in union_enum_items:
1683                     map_complex_enum(struct_name, union_enum_items[struct_name])
1684                 elif is_unitary_enum:
1685                     map_unitary_enum(struct_name, field_lines)
1686                 elif len(trait_fn_lines) > 0:
1687                     trait_structs.add(struct_name)
1688                     map_trait(struct_name, field_var_lines, trait_fn_lines)
1689                 elif struct_name == "LDKTxOut":
1690                     with open(f"{path_to_bindings_directory}/structs/TxOut.{consts.file_extension}", "w") as out_java_struct:
1691                         out_java_struct.write(consts.hu_struct_file_prefix)
1692                         out_java_struct.write("public class TxOut extends CommonBase{\n")
1693                         out_java_struct.write("\tTxOut(java.lang.Object _dummy, long ptr) { super(ptr); }\n")
1694                         out_java_struct.write("\tlong to_c_ptr() { return 0; }\n")
1695                         out_java_struct.write("\t@Override @SuppressWarnings(\"deprecation\")\n")
1696                         out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
1697                         out_java_struct.write("\t\tsuper.finalize();\n")
1698                         out_java_struct.write("\t\tif (ptr != 0) { bindings.TxOut_free(ptr); }\n")
1699                         out_java_struct.write("\t}\n")
1700                         # TODO: TxOut body
1701                         out_java_struct.write("}")
1702                 else:
1703                     pass # Everything remaining is a byte[] or some form
1704                 cur_block_obj = None
1705         else:
1706             fn_ptr = fn_ptr_regex.match(line)
1707             fn_ret_arr = fn_ret_arr_regex.match(line)
1708             reg_fn = reg_fn_regex.match(line)
1709             const_val = const_val_regex.match(line)
1710
1711             if line.startswith("#include <"):
1712                 pass
1713             elif line.startswith("/*"):
1714                 #out_java.write("\t" + line)
1715                 if not line.endswith("*/\n"):
1716                     in_block_comment = True
1717             elif line.startswith("typedef enum "):
1718                 cur_block_obj = line
1719             elif line.startswith("typedef struct "):
1720                 cur_block_obj = line
1721             elif line.startswith("typedef union "):
1722                 cur_block_obj = line
1723             elif fn_ptr is not None:
1724                 map_fn(line, fn_ptr, None, None)
1725             elif fn_ret_arr is not None:
1726                 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None)
1727             elif reg_fn is not None:
1728                 map_fn(line, reg_fn, None, None)
1729             elif const_val_regex is not None:
1730                 # TODO Map const variables
1731                 pass
1732             else:
1733                 assert(line == "\n")
1734
1735     out_java.write("}\n")
1736     for struct_name in opaque_structs:
1737         with open(f"{path_to_bindings_directory}/structs/{struct_name.replace('LDK', '')}.{consts.file_extension}", "a") as out_java_struct:
1738             out_java_struct.write("}\n")
1739     for struct_name in trait_structs:
1740         with open(f"{path_to_bindings_directory}/structs/{struct_name.replace('LDK', '')}.{consts.file_extension}", "a") as out_java_struct:
1741             out_java_struct.write("}\n")
1742 with open(path_to_c_file, "w") as out_c:
1743     out_c.write(consts.c_file_pfx)
1744     out_c.write(consts.init_str(c_array_class_caches))
1745     out_c.write(c_file)
1746