2 import os, sys, re, subprocess
5 print("USAGE: /path/to/lightning.h /path/to/bindings/output /path/to/bindings/ /path/to/bindings/output.c debug lang")
8 if sys.argv[5] == "false":
10 elif sys.argv[5] == "true":
13 print("debug should be true or false and indicates whether to track allocations and ensure we don't leak")
17 if sys.argv[6] == "java" or sys.argv[6] == "android":
19 from java_strings import Consts
20 target = java_strings.Target.JAVA
21 if sys.argv[6] == "android":
22 target = java_strings.Target.ANDROID
23 elif sys.argv[6] == "typescript":
24 import typescript_strings
25 from typescript_strings import Consts
26 target = typescript_strings.Target.NODEJS
27 if len(sys.argv) == 8 and sys.argv[7] == 'browser':
28 target = typescript_strings.Target.BROWSER
30 print("Only java or typescript can be set for lang")
34 consts = Consts(DEBUG, target=target)
36 local_git_version = os.getenv("LDK_GARBAGECOLLECTED_GIT_OVERRIDE")
37 if local_git_version is None:
38 local_git_version = subprocess.check_output(["git", "describe", '--tag', '--dirty']).decode("utf-8").strip()
40 from bindingstypes import *
47 def camel_to_snake(s):
48 # Convert camel case to snake case, in a way that appears to match cbindgen
54 if lastchar.isupper():
55 if not char.isupper() and not lastund:
60 ret = ret + lastchar.lower()
63 if char.isupper() and not lastund:
71 return (ret + lastchar.lower()).strip("_")
73 def doc_to_field_nullable(doc):
76 for line in doc.splitlines():
77 if "Note that this (or a relevant inner pointer) may be NULL or all-0s to represent None" in line:
81 def doc_to_params_ret_nullable(doc):
86 for line in doc.splitlines():
87 if "may be NULL or all-0s to represent None" not in line:
89 if "Note that the return value" in line:
91 elif "Note that " in line:
92 param = line.split("Note that ")[1].split(" ")[0]
94 return (params, ret_null)
98 opaque_structs = set()
103 var_is_arr_regex = re.compile("\(\* ?([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
104 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
105 java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
106 def java_c_types(fn_arg, ret_arr_len):
107 fn_arg = fn_arg.strip()
108 if fn_arg.startswith("MUST_USE_RES "):
111 if fn_arg.startswith("const "):
114 if fn_arg.startswith("struct "):
116 if fn_arg.startswith("enum "):
118 nonnull_ptr = "NONNULL_PTR" in fn_arg
119 fn_arg = fn_arg.replace("NONNULL_PTR", "")
126 if fn_arg.startswith("LDKThirtyTwoBytes"):
127 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
128 assert var_is_arr_regex.match(fn_arg[8:])
129 rust_obj = "LDKThirtyTwoBytes"
131 elif fn_arg.startswith("LDKTxid"):
132 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
133 assert var_is_arr_regex.match(fn_arg[8:])
134 rust_obj = "LDKThirtyTwoBytes"
136 elif fn_arg.startswith("LDKPublicKey"):
137 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
138 assert var_is_arr_regex.match(fn_arg[8:])
139 rust_obj = "LDKPublicKey"
140 arr_access = "compressed_form"
141 elif fn_arg.startswith("LDKSecretKey"):
142 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
143 assert var_is_arr_regex.match(fn_arg[8:])
144 rust_obj = "LDKSecretKey"
146 elif fn_arg.startswith("LDKSignature"):
147 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
148 assert var_is_arr_regex.match(fn_arg[8:])
149 rust_obj = "LDKSignature"
150 arr_access = "compact_form"
151 elif fn_arg.startswith("LDKRecoverableSignature"):
152 fn_arg = "uint8_t (*" + fn_arg[25:] + ")[68]"
153 assert var_is_arr_regex.match(fn_arg[8:])
154 rust_obj = "LDKRecoverableSignature"
155 arr_access = "serialized_form"
156 elif fn_arg.startswith("LDKThreeBytes"):
157 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
158 assert var_is_arr_regex.match(fn_arg[8:])
159 rust_obj = "LDKThreeBytes"
161 elif fn_arg.startswith("LDKFourBytes"):
162 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
163 assert var_is_arr_regex.match(fn_arg[8:])
164 rust_obj = "LDKFourBytes"
166 elif fn_arg.startswith("LDKSixteenBytes"):
167 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
168 assert var_is_arr_regex.match(fn_arg[8:])
169 rust_obj = "LDKSixteenBytes"
171 elif fn_arg.startswith("LDKTwentyBytes"):
172 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
173 assert var_is_arr_regex.match(fn_arg[8:])
174 rust_obj = "LDKTwentyBytes"
176 elif fn_arg.startswith("LDKTenBytes"):
177 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[10]"
178 assert var_is_arr_regex.match(fn_arg[8:])
179 rust_obj = "LDKTenBytes"
181 elif fn_arg.startswith("LDKu8slice"):
182 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
183 assert var_is_arr_regex.match(fn_arg[8:])
184 rust_obj = "LDKu8slice"
186 elif fn_arg.startswith("LDKCVec_u8Z"):
187 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
188 rust_obj = "LDKCVec_u8Z"
189 assert var_is_arr_regex.match(fn_arg[8:])
191 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
192 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
193 rust_obj = "LDKTransaction"
194 assert var_is_arr_regex.match(fn_arg[8:])
196 elif fn_arg.startswith("LDKCVec_"):
199 fn_arg = fn_arg.replace("*", "")
202 tyn = fn_arg[8:].split(" ")
203 assert tyn[0].endswith("Z")
207 new_arg = "LDK" + tyn[0][:-1]
209 new_arg = new_arg + " " + a
210 res = java_c_types(new_arg, ret_arr_len)
212 assert java_c_types_none_allowed
215 res.pass_by_ref = True
216 if res.is_native_primitive or res.passed_as_ptr:
217 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=res.java_ty + "[]", java_hu_ty=res.java_hu_ty + "[]",
218 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
219 nonnull_ptr=nonnull_ptr, is_const=is_const,
220 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
222 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=res.java_ty + "[]", java_hu_ty=res.java_hu_ty + "[]",
223 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
224 nonnull_ptr=nonnull_ptr, is_const=is_const,
225 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
230 java_type_plural = None
231 if fn_arg.startswith("void"):
235 fn_arg = fn_arg[4:].strip()
237 elif fn_arg.startswith("bool"):
241 fn_arg = fn_arg[4:].strip()
243 elif fn_arg.startswith("uint8_t"):
244 mapped_type = consts.c_type_map['uint8_t']
245 java_ty = mapped_type[0]
248 fn_arg = fn_arg[7:].strip()
250 elif fn_arg.startswith("LDKu5"):
251 java_ty = consts.c_type_map['uint8_t'][0]
256 fn_arg = fn_arg[6:].strip()
257 elif fn_arg.startswith("uint16_t"):
258 mapped_type = consts.c_type_map['uint16_t']
259 java_ty = mapped_type[0]
262 fn_arg = fn_arg[8:].strip()
264 elif fn_arg.startswith("uint32_t"):
265 mapped_type = consts.c_type_map['uint32_t']
266 java_ty = mapped_type[0]
269 fn_arg = fn_arg[8:].strip()
271 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
272 # TODO: uintptr_t is arch-dependent :(
273 mapped_type = consts.c_type_map['uint64_t']
274 java_ty = mapped_type[0]
276 if fn_arg.startswith("uint64_t"):
278 fn_arg = fn_arg[8:].strip()
281 rust_obj = "uintptr_t"
282 fn_arg = fn_arg[9:].strip()
284 elif is_const and fn_arg.startswith("char *"):
287 fn_ty_arg = "Ljava/lang/String;"
288 fn_arg = fn_arg[6:].strip()
289 elif fn_arg.startswith("LDKStr"):
293 fn_ty_arg = "Ljava/lang/String;"
294 fn_arg = fn_arg[6:].strip()
298 ma = var_ty_regex.match(fn_arg)
299 if ma.group(1).strip() in unitary_enums:
300 assert ma.group(1).strip().startswith("LDK")
301 java_ty = ma.group(1).strip()[3:]
303 c_ty = consts.result_c_ty
304 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
305 fn_arg = ma.group(2).strip()
306 rust_obj = ma.group(1).strip()
308 c_ty = consts.ptr_c_ty
309 java_ty = consts.ptr_native_ty
310 java_hu_ty = ma.group(1).strip()
311 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
312 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
313 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
314 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
315 java_hu_ty = java_hu_ty.replace("LDK", "")
317 fn_arg = ma.group(2).strip()
318 rust_obj = ma.group(1).strip()
321 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
322 fn_arg = fn_arg.replace("*", "").strip()
324 c_ty = consts.ptr_c_ty
325 java_ty = consts.ptr_native_ty
328 var_is_arr = var_is_arr_regex.match(fn_arg)
329 if var_is_arr is not None or ret_arr_len is not None:
330 assert(not take_by_ptr)
332 # is there a special case for plurals?
333 if len(mapped_type) == 2:
334 java_ty = mapped_type[1]
336 java_ty = java_ty + "[]"
337 c_ty = c_ty + "Array"
338 if var_is_arr is not None:
339 if var_is_arr.group(1) == "":
340 return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
341 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg",
342 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False)
343 return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
344 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1),
345 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False)
347 if java_hu_ty is None:
349 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,
350 is_const=is_const, is_ptr=is_ptr, nonnull_ptr=nonnull_ptr, var_name=fn_arg, arr_len=arr_len, arr_access=arr_access, is_native_primitive=is_primitive)
352 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
353 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
354 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
358 from gen_type_mapping import TypeMappingGenerator
359 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
361 with open(sys.argv[1]) as in_h:
363 reg_fn = reg_fn_regex.match(line)
364 if reg_fn is not None:
365 if reg_fn.group(2).endswith("_clone"):
366 clone_fns.add(reg_fn.group(2))
368 rty = java_c_types(reg_fn.group(1), None)
369 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
370 constructor_fns[rty.rust_obj] = reg_fn.group(3)
372 arr_fn = fn_ret_arr_regex.match(line)
373 if arr_fn is not None:
374 if arr_fn.group(2).endswith("_clone"):
375 clone_fns.add(arr_fn.group(2))
376 # No object constructors return arrays, as then they wouldn't be an object constructor
379 # Define some manual clones...
380 clone_fns.add("ThirtyTwoBytes_clone")
381 write_c("static inline struct LDKThirtyTwoBytes ThirtyTwoBytes_clone(const struct LDKThirtyTwoBytes *orig) { struct LDKThirtyTwoBytes ret; memcpy(ret.data, orig->data, 32); return ret; }\n")
383 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
385 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
386 util.write(consts.util_fn_pfx)
388 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
389 # Map a top-level function
390 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
391 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
392 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
393 method_return_type = re_match.group(1)
394 method_name = re_match.group(2)
395 method_comma_separated_arguments = re_match.group(3)
396 method_arguments = method_comma_separated_arguments.split(',')
398 is_free = method_name.endswith("_free")
399 if method_name.startswith("COption") or method_name.startswith("CResult"):
400 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
401 expected_struct = "LDKC" + struct_meth
402 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
403 elif method_name.startswith("C2Tuple"):
404 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
405 struct_meth = "Two" + tuple_name
406 expected_struct = "LDKC2" + tuple_name
407 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
409 struct_meth = method_name.split("_")[0]
410 expected_struct = "LDK" + struct_meth
411 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
413 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
415 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
417 return_type_info.nullable = True
420 default_constructor_args = {}
422 takes_self_ptr = False
425 for argument_index, argument in enumerate(method_arguments):
426 argument_conversion_info = type_mapping_generator.map_type(argument, False, None, is_free, True)
427 if argument_index == 0 and argument_conversion_info.java_hu_ty == struct_meth:
429 if argument_conversion_info.ty_info.is_ptr:
430 takes_self_ptr = True
431 elif argument_conversion_info.arg_name in params_nullable:
432 argument_conversion_info.nullable = True
433 if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
434 arg_ty_info = java_c_types(argument, None)
435 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
436 print(" The argument appears to require a move, or not clonable, and is nullable.")
437 print(" Normally for arguments that require a move and are not clonable, we split")
438 print(" the argument into the type's constructor's arguments and just use those to")
439 print(" construct a new object on the fly.")
440 print(" However, because the object is nullable, doing so would mean we can no")
441 print(" longer allow the user to pass null, as we now have an argument list instead.")
442 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
443 print(" It may or may not actually be a reference, but its the simplest mapping option")
444 print(" and also the only use of this code today.")
445 arg_ty_info.requires_clone = False
446 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True)
447 assert argument_conversion_info.arg_conv is not None and "Warning" not in argument_conversion_info.arg_conv
449 if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
450 if argument_conversion_info.rust_obj in constructor_fns:
452 for explode_arg in constructor_fns[argument_conversion_info.rust_obj].split(','):
453 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
454 if explode_arg_conv.c_ty == "void":
455 # We actually want to handle this case, but for now its only used in NetGraphMsgHandler::new()
456 # which ends up resulting in a redundant constructor - both without arguments for the NetworkGraph.
459 if not argument_conversion_info.arg_name in default_constructor_args:
460 default_constructor_args[argument_conversion_info.arg_name] = []
461 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
462 argument_types.append(argument_conversion_info)
463 if not takes_self and return_type_info.java_hu_ty != struct_meth:
464 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
465 struct_meth_name = method_name
469 out_java.write("\t// " + line)
470 (out_java_delta, out_c_delta, out_java_struct_delta) = \
471 consts.map_function(argument_types, c_call_string, method_name, struct_meth_name, return_type_info, struct_meth, default_constructor_args, takes_self, takes_self_ptr, args_known, type_mapping_generator, doc_comment)
472 out_java.write(out_java_delta)
475 assert len(argument_types) == 1
476 assert return_type_info.c_ty == "void"
477 write_c(consts.c_fn_ty_pfx + "void " + consts.c_fn_name_define_pfx(method_name, True) + argument_types[0].c_ty + " " + argument_types[0].ty_info.var_name + ") {\n")
478 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
479 write_c("\tif ((" + argument_types[0].ty_info.var_name + " & 1) != 0) return;\n")
481 for info in argument_types:
482 if info.arg_conv is not None:
483 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
484 assert c_call_string is None
485 write_c("\t" + method_name + "(")
486 if argument_types[0].arg_conv_name is not None:
487 write_c(argument_types[0].arg_conv_name)
489 for info in argument_types:
490 if info.arg_conv_cleanup is not None:
491 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
496 out_java_struct = None
497 if (expected_struct in opaque_structs or expected_struct in trait_structs
498 or expected_struct in complex_enums or expected_struct in complex_enums
499 or expected_struct in result_types or expected_struct in tuple_types) and not is_free:
500 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
501 out_java_struct.write(out_java_struct_delta)
502 elif (not is_free and not method_name.endswith("_clone") and
503 not method_name.startswith("TxOut") and
504 not method_name.startswith("_") and
505 method_name != "check_platform" and method_name != "Result_read" and
506 not expected_struct in unitary_enums and
507 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
508 or method_name.endswith("_read"))):
509 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
510 for line in out_java_struct_delta.splitlines():
511 if not line.strip().startswith("this."):
512 out_java_struct.write(line + "\n")
514 out_java_struct.write("\t\t// " + line.strip() + "\n")
516 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
517 assert struct_name.startswith("LDK")
518 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
519 unitary_enums.add(struct_name)
520 for idx, (struct_line, _) in enumerate(field_lines):
522 assert(struct_line == "typedef enum %s {" % struct_name)
523 elif idx == len(field_lines) - 3:
524 assert(struct_line.endswith("_Sentinel,"))
525 elif idx == len(field_lines) - 2:
526 assert(struct_line == "} %s;" % struct_name)
527 elif idx == len(field_lines) - 1:
528 assert(struct_line == "")
529 assert struct_name.startswith("LDK")
530 (c_out, native_file_out, native_out) = consts.native_c_unitary_enum_map(struct_name[3:], [x.strip().strip(",") for x, _ in field_lines[1:-3]], enum_doc_comment)
532 out_java_enum.write(native_file_out)
533 out_java.write(native_out)
535 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
536 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
537 complex_enums.add(struct_name)
540 tag_field_lines = union_enum_items["field_lines"]
541 for idx, (struct_line, _) in enumerate(tag_field_lines):
543 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
544 elif idx == len(tag_field_lines) - 3:
545 assert(struct_line.endswith("_Sentinel,"))
546 elif idx == len(tag_field_lines) - 2:
547 assert(struct_line == "} %s_Tag;" % struct_name)
548 elif idx == len(tag_field_lines) - 1:
549 assert(struct_line == "")
551 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
553 if "LDK" + variant_name in union_enum_items:
554 enum_var_lines = union_enum_items["LDK" + variant_name]
555 for idx, (field, field_docs) in enumerate(enum_var_lines):
556 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
557 field_ty = type_mapping_generator.map_type(field.strip(' ;'), False, None, False, True)
558 if field_docs is not None and doc_to_field_nullable(field_docs):
559 field_ty.nullable = True
560 fields.append((field_ty, field_docs))
561 enum_variants.append(ComplexEnumVariantInfo(variant_name, fields, False))
562 elif camel_to_snake(variant_name) in inline_enum_variants:
563 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
564 # docs through to there, and then potentially mark the field nullable.
565 fields.append((type_mapping_generator.map_type(inline_enum_variants[camel_to_snake(variant_name)] + " " + camel_to_snake(variant_name), False, None, False, True), None))
566 enum_variants.append(ComplexEnumVariantInfo(variant_name, fields, True))
568 enum_variants.append(ComplexEnumVariantInfo(variant_name, fields, True))
570 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
571 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
573 out_java_enum.write(out_java_enum_addendum)
574 out_java.write(out_java_addendum)
575 write_c(out_c_addendum)
577 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
578 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
580 flattened_field_var_convs = []
581 for var_line in field_var_lines:
582 if var_line.group(1) in trait_structs:
583 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
584 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
585 flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
587 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
588 field_var_convs.append(mapped)
589 flattened_field_var_convs.append(mapped)
590 trait_structs[struct_name] = field_var_convs
593 for fn_docs, fn_line in trait_fn_lines:
594 if fn_line == "cloned":
595 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
596 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
598 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
599 is_const = fn_line.group(4) is not None
600 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
602 assert False # This isn't yet handled on the Java side
603 ret_ty_info.nullable = True
606 for idx, arg in enumerate(fn_line.group(5).split(',')):
609 arg_conv_info = type_mapping_generator.map_type(arg, True, None, False, False)
610 if arg_conv_info.arg_name in nullable_params:
611 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
612 assert arg_conv_info.rust_obj == "LDKPublicKey"
613 arg_conv_info.nullable = True
614 arg_tys.append(arg_conv_info)
615 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
617 (out_java_addendum, out_java_trait_addendum, out_c_addendum) = consts.native_c_map_trait(struct_name, field_var_convs, flattened_field_var_convs, field_fns, trait_doc_comment)
618 write_c(out_c_addendum)
619 out_java_trait.write(out_java_trait_addendum)
620 out_java.write(out_java_addendum)
622 for fn_docs, fn_line in trait_fn_lines:
623 if fn_line == "cloned":
625 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
626 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
627 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
628 dummy_line = fn_line.group(2) + struct_name.replace("LDK", "") + "_" + fn_line.group(3) + " " + struct_name + " *NONNULL_PTR this_arg" + fn_line.group(5) + "\n"
629 map_fn(dummy_line, re.compile("([A-Za-z_0-9]*) *([A-Za-z_0-9]*) *(.*)").match(dummy_line), None, "(this_arg_conv->" + fn_line.group(3) + ")(this_arg_conv->this_arg", fn_docs)
630 for idx, var_line in enumerate(field_var_lines):
631 if var_line.group(1) not in trait_structs:
632 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
633 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
634 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
635 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
637 dummy_line = var_line.group(1) + " " + struct_name.replace("LDK", "") + "_get_" + var_line.group(2) + " " + struct_name + " *NONNULL_PTR this_arg" + fn_line.group(5) + "\n"
638 map_fn(dummy_line, re.compile("([A-Za-z_0-9]*) *([A-Za-z_0-9]*) *(.*)").match(dummy_line), None, struct_name + "_set_get_" + var_line.group(2) + "(this_arg_conv", fn_docs)
640 def map_result(struct_name, res_ty, err_ty):
641 result_types.add(struct_name)
642 human_ty = struct_name.replace("LDKCResult", "Result")
643 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
644 out_java_struct.write(consts.hu_struct_file_prefix)
645 out_java_struct.write("public class " + human_ty + " extends CommonBase {\n")
646 out_java_struct.write("\tprivate " + human_ty + "(Object _dummy, long ptr) { super(ptr); }\n")
647 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
648 out_java_struct.write("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); } super.finalize();\n")
649 out_java_struct.write("\t}\n\n")
650 out_java_struct.write("\tstatic " + human_ty + " constr_from_ptr(long ptr) {\n")
651 out_java_struct.write("\t\tif (bindings." + struct_name + "_result_ok(ptr)) {\n")
652 out_java_struct.write("\t\t\treturn new " + human_ty + "_OK(null, ptr);\n")
653 out_java_struct.write("\t\t} else {\n")
654 out_java_struct.write("\t\t\treturn new " + human_ty + "_Err(null, ptr);\n")
655 out_java_struct.write("\t\t}\n")
656 out_java_struct.write("\t}\n")
658 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
659 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
661 if not res_map.is_native_primitive and (res_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
663 if not err_map.is_native_primitive and (err_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
666 out_java.write("\tpublic static native boolean " + struct_name + "_result_ok(long arg);\n")
667 write_c(consts.c_fn_ty_pfx + "jboolean " + consts.c_fn_name_define_pfx(struct_name + "_result_ok", True) + consts.ptr_c_ty + " arg) {\n")
668 write_c("\treturn ((" + struct_name + "*)arg)->result_ok;\n")
671 out_java.write("\tpublic static native " + res_map.java_ty + " " + struct_name + "_get_ok(long arg);\n")
672 write_c(consts.c_fn_ty_pfx + res_map.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_ok", True) + consts.ptr_c_ty + " arg) {\n")
673 write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
674 write_c("\tCHECK(val->result_ok);\n\t")
675 out_java_struct.write("\tpublic static final class " + human_ty + "_OK extends " + human_ty + " {\n")
676 if res_map.ret_conv is not None:
677 write_c(res_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.result)")
678 write_c(res_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + res_map.ret_conv_name)
680 write_c("return *val->contents.result")
683 if res_map.java_hu_ty != "void":
684 out_java_struct.write("\t\tpublic final " + res_map.java_hu_ty + " res;\n")
685 out_java_struct.write("\t\tprivate " + human_ty + "_OK(Object _dummy, long ptr) {\n")
686 out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
687 if res_map.java_hu_ty == "void":
689 elif res_map.to_hu_conv is not None:
690 out_java_struct.write("\t\t\t" + res_map.java_ty + " res = bindings." + struct_name + "_get_ok(ptr);\n")
691 out_java_struct.write("\t\t\t" + res_map.to_hu_conv.replace("\n", "\n\t\t\t"))
692 out_java_struct.write("\n\t\t\tthis.res = " + res_map.to_hu_conv_name + ";\n")
694 out_java_struct.write("\t\t\tthis.res = bindings." + struct_name + "_get_ok(ptr);\n")
695 out_java_struct.write("\t\t}\n")
696 out_java_struct.write("\t}\n\n")
698 out_java.write("\tpublic static native " + err_map.java_ty + " " + struct_name + "_get_err(long arg);\n")
699 write_c(consts.c_fn_ty_pfx + err_map.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_err", True) + consts.ptr_c_ty + " arg) {\n")
700 write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
701 write_c("\tCHECK(!val->result_ok);\n\t")
702 out_java_struct.write("\tpublic static final class " + human_ty + "_Err extends " + human_ty + " {\n")
703 if err_map.ret_conv is not None:
704 write_c(err_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.err)")
705 write_c(err_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + err_map.ret_conv_name)
707 write_c("return *val->contents.err")
710 if err_map.java_hu_ty != "void":
711 out_java_struct.write("\t\tpublic final " + err_map.java_hu_ty + " err;\n")
712 out_java_struct.write("\t\tprivate " + human_ty + "_Err(Object _dummy, long ptr) {\n")
713 out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
714 if err_map.java_hu_ty == "void":
716 elif err_map.to_hu_conv is not None:
717 out_java_struct.write("\t\t\t" + err_map.java_ty + " err = bindings." + struct_name + "_get_err(ptr);\n")
718 out_java_struct.write("\t\t\t" + err_map.to_hu_conv.replace("\n", "\n\t\t\t"))
719 out_java_struct.write("\n\t\t\tthis.err = " + err_map.to_hu_conv_name + ";\n")
721 out_java_struct.write("\t\t\tthis.err = bindings." + struct_name + "_get_err(ptr);\n")
722 out_java_struct.write("\t\t}\n")
724 out_java_struct.write("\t}\n\n")
726 def map_tuple(struct_name, field_lines):
727 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
728 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
729 out_java_struct.write(consts.map_tuple(struct_name))
731 for idx, (line, _) in enumerate(field_lines):
732 if idx != 0 and idx < len(field_lines) - 2:
733 ty_list.append(java_c_types(line.strip(';'), None))
734 tuple_types[struct_name] = (ty_list, struct_name)
736 # Map virtual getter functions
737 for idx, (line, _) in enumerate(field_lines):
738 if idx != 0 and idx < len(field_lines) - 2:
739 field_name = chr(ord('a') + idx - 1)
740 assert line.endswith(" " + field_name + ";")
741 field_ty = java_c_types(line[:-1], None)
742 ptr_fn_defn = line[:-3].strip() + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR tuple)"
743 owned_fn_defn = line[:-3].strip() + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR tuple)"
746 if field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
747 fn_defn = owned_fn_defn
748 write_c("static inline " + fn_defn + "{\n")
749 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&tuple->" + field_name + ");\n")
750 elif field_ty.arr_len is not None or field_ty.is_native_primitive:
751 fn_defn = owned_fn_defn
752 write_c("static inline " + fn_defn + "{\n")
753 write_c("\treturn tuple->" + field_name + ";\n")
755 fn_defn = ptr_fn_defn
756 write_c("static inline " + fn_defn + "{\n")
757 write_c("\treturn &tuple->" + field_name + ";\n")
760 dummy_line = fn_defn + ";\n"
761 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
763 out_java.write(consts.bindings_header)
764 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
765 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
767 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
768 out_java_struct.write(consts.common_base)
771 last_block_comment = None
774 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
776 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
777 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
778 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
779 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
780 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
781 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
782 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
783 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
784 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
785 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
786 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
787 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
788 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
789 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
790 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
792 union_enum_items = {}
793 result_ptr_struct_items = {}
795 if block_comment is not None:
796 if line.endswith("*/\n"):
797 last_block_comment = block_comment.strip("\n")
800 block_comment = block_comment + line.strip(" /*")
801 elif cur_block_obj is not None:
802 cur_block_obj = cur_block_obj + line
803 if line.startswith("} "):
807 obj_lines = cur_block_obj.split("\n")
809 result_contents = None
810 is_unitary_enum = False
811 is_union_enum = False
816 last_struct_block_comment = None
818 for idx, struct_line in enumerate(obj_lines):
819 if struct_line.strip().startswith("/*"):
820 block_comment = struct_line.strip(" /*")
821 if block_comment is not None:
822 if struct_line.endswith("*/"):
823 last_struct_block_comment = block_comment.strip("\n")
826 block_comment = block_comment + "\n" + struct_line.strip(" /*")
828 struct_name_match = struct_name_regex.match(struct_line)
829 if struct_name_match is not None:
830 struct_name = struct_name_match.group(3)
831 if struct_name_match.group(1) == "enum":
832 if not struct_name.endswith("_Tag"):
833 is_unitary_enum = True
836 elif struct_name_match.group(1) == "union":
838 if line_indicates_opaque_regex.match(struct_line):
840 result_match = line_indicates_result_regex.match(struct_line)
841 if result_match is not None:
842 result_contents = result_match.group(1)
843 vec_ty_match = line_indicates_vec_regex.match(struct_line)
844 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
845 vec_ty = vec_ty_match.group(2)
846 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
848 trait_fn_match = line_indicates_trait_regex.match(struct_line)
849 if trait_fn_match is not None:
850 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
851 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
852 if trait_clone_fn_match is not None:
853 trait_fn_lines.append((last_struct_block_comment, "cloned"))
854 field_var_match = line_field_var_regex.match(struct_line)
855 if field_var_match is not None:
856 field_var_lines.append(field_var_match)
857 field_lines.append((struct_line, last_struct_block_comment))
858 last_struct_block_comment = None
860 assert(struct_name is not None)
861 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))
862 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))
863 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))
864 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))
865 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))
866 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))
867 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))
870 opaque_structs.add(struct_name)
871 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
872 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
873 last_block_comment = None
874 out_java_struct.write(out_opaque_struct_human)
875 elif result_contents is not None:
876 assert result_contents in result_ptr_struct_items
877 res_ty, err_ty = result_ptr_struct_items[result_contents]
878 map_result(struct_name, res_ty, err_ty)
879 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
880 for line, _ in field_lines:
881 if line.endswith("*result;"):
882 res_ty = line[:-8].strip()
883 elif line.endswith("*err;"):
884 err_ty = line[:-5].strip()
885 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
886 result_types.add(struct_name[:-3])
888 map_tuple(struct_name, field_lines)
889 elif vec_ty is not None:
890 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
891 if len(ty_info.java_fn_ty_arg) == 1: # ie we're a primitive of some form
892 out_java.write("\tpublic static native long " + struct_name + "_new(" + ty_info.java_ty + "[] elems);\n")
893 write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_new", True) + ty_info.c_ty + "Array elems) {\n")
894 write_c("\t" + struct_name + " *ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n")
895 write_c("\tret->datalen = " + consts.get_native_arr_len_call[0] + "elems" + consts.get_native_arr_len_call[1] + ";\n")
896 write_c("\tif (ret->datalen == 0) {\n")
897 write_c("\t\tret->data = NULL;\n")
898 write_c("\t} else {\n")
899 write_c("\t\tret->data = MALLOC(sizeof(" + vec_ty + ") * ret->datalen, \"" + struct_name + " Data\");\n")
900 native_arr_ptr_call = consts.get_native_arr_ptr_call(ty_info.ty_info)
901 write_c("\t\t" + ty_info.c_ty + " *java_elems = " + native_arr_ptr_call[0] + "elems" + native_arr_ptr_call[1] + ";\n")
902 write_c("\t\tfor (size_t i = 0; i < ret->datalen; i++) {\n")
903 if ty_info.arg_conv is not None:
904 write_c("\t\t\t" + ty_info.c_ty + " arr_elem = java_elems[i];\n")
905 write_c("\t\t\t" + ty_info.arg_conv.replace("\n", "\n\t\t\t") + "\n")
906 write_c("\t\t\tret->data[i] = " + ty_info.arg_conv_name + ";\n")
907 assert ty_info.arg_conv_cleanup is None
909 write_c("\t\t\tret->data[i] = java_elems[i];\n")
911 cleanup = consts.release_native_arr_ptr_call(ty_info.ty_info, "elems", "java_elems")
912 if cleanup is not None:
913 write_c("\t\t" + cleanup + ";\n")
915 write_c("\treturn (uint64_t)ret;\n")
918 if ty_info.is_native_primitive:
919 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
920 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
921 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
922 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
923 write_c("\treturn ret;\n}\n")
924 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
925 ty_name = "CVec_" + ty_info.rust_obj.replace("LDK", "") + "Z";
926 clone_fns.add(ty_name + "_clone")
927 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
928 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
929 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
930 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
931 write_c("\t}\n\treturn ret;\n}\n")
933 assert(struct_name.endswith("_Tag"))
934 struct_name = struct_name[:-4]
935 union_enum_items[struct_name] = {"field_lines": field_lines}
936 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
937 enum_var_name = struct_name.split("_")
938 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
939 elif struct_name in union_enum_items:
942 for line, _ in field_lines:
943 if line == " struct {":
947 elif elem_items > -1:
949 if line.startswith("struct "):
951 elif line.startswith("enum "):
953 split = line.split(" ")
954 assert len(split) == 2
955 tuple_variants[split[1].strip(";")] = split[0]
958 # We don't currently support tuple variant with more than one element
960 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
961 last_block_comment = None
962 elif is_unitary_enum:
963 map_unitary_enum(struct_name, field_lines, last_block_comment)
964 last_block_comment = None
965 elif len(trait_fn_lines) > 0:
966 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
967 elif struct_name == "LDKTxOut":
968 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
969 out_java_struct.write(consts.hu_struct_file_prefix)
970 out_java_struct.write("public class TxOut extends CommonBase{\n")
971 out_java_struct.write("\t/** The script_pubkey in this output */\n")
972 out_java_struct.write("\tpublic final byte[] script_pubkey;\n")
973 out_java_struct.write("\t/** The value, in satoshis, of this output */\n")
974 out_java_struct.write("\tpublic final long value;\n")
975 out_java_struct.write("\n")
976 out_java_struct.write("\tTxOut(java.lang.Object _dummy, long ptr) {\n")
977 out_java_struct.write("\t\tsuper(ptr);\n")
978 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
979 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
980 out_java_struct.write("\t}\n")
981 out_java_struct.write("\tpublic TxOut(long value, byte[] script_pubkey) {\n")
982 out_java_struct.write("\t\tsuper(bindings.TxOut_new(script_pubkey, value));\n")
983 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
984 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
985 out_java_struct.write("\t}\n")
986 out_java_struct.write("\n")
987 out_java_struct.write("\t@Override @SuppressWarnings(\"deprecation\")\n")
988 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
989 out_java_struct.write("\t\tsuper.finalize();\n")
990 out_java_struct.write("\t\tif (ptr != 0) { bindings.TxOut_free(ptr); }\n")
991 out_java_struct.write("\t}\n")
992 out_java_struct.write("\n")
993 out_java_struct.write("}")
994 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
995 write_c(fn_line + " {")
996 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
998 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
999 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1000 write_c(fn_line + " {")
1001 write_c("\treturn thing->value;")
1003 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1005 pass # Everything remaining is a byte[] or some form
1006 cur_block_obj = None
1008 fn_ptr = fn_ptr_regex.match(line)
1009 fn_ret_arr = fn_ret_arr_regex.match(line)
1010 reg_fn = reg_fn_regex.match(line)
1011 const_val = const_val_regex.match(line)
1013 if line.startswith("#include <"):
1015 elif line.startswith("/*"):
1016 if not line.endswith("*/\n"):
1017 block_comment = line.strip(" /*")
1018 elif line.startswith("typedef enum "):
1019 cur_block_obj = line
1020 elif line.startswith("typedef struct "):
1021 cur_block_obj = line
1022 elif line.startswith("typedef union "):
1023 cur_block_obj = line
1024 elif fn_ptr is not None:
1025 map_fn(line, fn_ptr, None, None, last_block_comment)
1026 last_block_comment = None
1027 elif fn_ret_arr is not None:
1028 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1029 last_block_comment = None
1030 elif reg_fn is not None:
1031 map_fn(line, reg_fn, None, None, last_block_comment)
1032 last_block_comment = None
1033 elif const_val_regex is not None:
1034 # TODO Map const variables
1037 assert(line == "\n")
1039 out_java.write(consts.bindings_footer)
1040 for struct_name in opaque_structs:
1041 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1042 out_java_struct.write("}\n")
1043 for struct_name in trait_structs:
1044 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1045 out_java_struct.write("}\n")
1046 for struct_name in complex_enums:
1047 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1048 out_java_struct.write("}\n")
1049 for struct_name in result_types:
1050 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1051 out_java_struct.write("}\n")
1052 for struct_name in tuple_types:
1053 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1054 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1055 out_java_struct.write("}\n")
1057 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1058 out_c.write(consts.c_file_pfx)
1059 out_c.write(consts.init_str())
1061 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1062 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1063 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1064 util.write(consts.util_fn_sfx)