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