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