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)
97 # Map from enum name to "contains trait object"
99 opaque_structs = set()
104 var_is_arr_regex = re.compile("\(\* ?([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
105 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
106 java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
107 def java_c_types(fn_arg, ret_arr_len):
108 fn_arg = fn_arg.strip()
109 if fn_arg.startswith("MUST_USE_RES "):
112 if fn_arg.startswith("const "):
115 if fn_arg.startswith("struct "):
117 if fn_arg.startswith("enum "):
119 nonnull_ptr = "NONNULL_PTR" in fn_arg
120 fn_arg = fn_arg.replace("NONNULL_PTR", "")
127 if fn_arg.startswith("LDKThirtyTwoBytes"):
128 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
129 assert var_is_arr_regex.match(fn_arg[8:])
130 rust_obj = "LDKThirtyTwoBytes"
132 elif fn_arg.startswith("LDKTxid"):
133 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
134 assert var_is_arr_regex.match(fn_arg[8:])
135 rust_obj = "LDKThirtyTwoBytes"
137 elif fn_arg.startswith("LDKPublicKey"):
138 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
139 assert var_is_arr_regex.match(fn_arg[8:])
140 rust_obj = "LDKPublicKey"
141 arr_access = "compressed_form"
142 elif fn_arg.startswith("LDKSecretKey"):
143 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
144 assert var_is_arr_regex.match(fn_arg[8:])
145 rust_obj = "LDKSecretKey"
147 elif fn_arg.startswith("LDKSignature"):
148 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
149 assert var_is_arr_regex.match(fn_arg[8:])
150 rust_obj = "LDKSignature"
151 arr_access = "compact_form"
152 elif fn_arg.startswith("LDKRecoverableSignature"):
153 fn_arg = "uint8_t (*" + fn_arg[25:] + ")[68]"
154 assert var_is_arr_regex.match(fn_arg[8:])
155 rust_obj = "LDKRecoverableSignature"
156 arr_access = "serialized_form"
157 elif fn_arg.startswith("LDKThreeBytes"):
158 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
159 assert var_is_arr_regex.match(fn_arg[8:])
160 rust_obj = "LDKThreeBytes"
162 elif fn_arg.startswith("LDKFourBytes"):
163 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
164 assert var_is_arr_regex.match(fn_arg[8:])
165 rust_obj = "LDKFourBytes"
167 elif fn_arg.startswith("LDKSixteenBytes"):
168 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
169 assert var_is_arr_regex.match(fn_arg[8:])
170 rust_obj = "LDKSixteenBytes"
172 elif fn_arg.startswith("LDKTwentyBytes"):
173 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
174 assert var_is_arr_regex.match(fn_arg[8:])
175 rust_obj = "LDKTwentyBytes"
177 elif fn_arg.startswith("LDKTwelveBytes"):
178 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
179 assert var_is_arr_regex.match(fn_arg[8:])
180 rust_obj = "LDKTwelveBytes"
182 elif fn_arg.startswith("LDKu8slice"):
183 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
184 assert var_is_arr_regex.match(fn_arg[8:])
185 rust_obj = "LDKu8slice"
187 elif fn_arg.startswith("LDKCVec_u8Z"):
188 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
189 rust_obj = "LDKCVec_u8Z"
190 assert var_is_arr_regex.match(fn_arg[8:])
192 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
193 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
194 rust_obj = "LDKTransaction"
195 assert var_is_arr_regex.match(fn_arg[8:])
197 elif fn_arg.startswith("LDKCVec_"):
200 fn_arg = fn_arg.replace("*", "")
203 tyn = fn_arg[8:].split(" ")
204 assert tyn[0].endswith("Z")
208 new_arg = "LDK" + tyn[0][:-1]
210 new_arg = new_arg + " " + a
211 res = java_c_types(new_arg, ret_arr_len)
213 assert java_c_types_none_allowed
216 res.pass_by_ref = True
217 if res.is_native_primitive or res.passed_as_ptr:
218 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=res.java_ty + "[]", java_hu_ty=res.java_hu_ty + "[]",
219 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
220 nonnull_ptr=nonnull_ptr, is_const=is_const,
221 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
223 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=res.java_ty + "[]", java_hu_ty=res.java_hu_ty + "[]",
224 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
225 nonnull_ptr=nonnull_ptr, is_const=is_const,
226 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
229 contains_trait = False
232 java_type_plural = None
233 if fn_arg.startswith("void"):
237 fn_arg = fn_arg[4:].strip()
239 elif fn_arg.startswith("bool"):
243 fn_arg = fn_arg[4:].strip()
245 elif fn_arg.startswith("uint8_t"):
246 mapped_type = consts.c_type_map['uint8_t']
247 java_ty = mapped_type[0]
250 fn_arg = fn_arg[7:].strip()
252 elif fn_arg.startswith("LDKu5"):
253 java_ty = consts.c_type_map['uint8_t'][0]
258 fn_arg = fn_arg[6:].strip()
259 elif fn_arg.startswith("uint16_t"):
260 mapped_type = consts.c_type_map['uint16_t']
261 java_ty = mapped_type[0]
264 fn_arg = fn_arg[8:].strip()
266 elif fn_arg.startswith("uint32_t"):
267 mapped_type = consts.c_type_map['uint32_t']
268 java_ty = mapped_type[0]
271 fn_arg = fn_arg[8:].strip()
273 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
274 # TODO: uintptr_t is arch-dependent :(
275 mapped_type = consts.c_type_map['uint64_t']
276 java_ty = mapped_type[0]
278 if fn_arg.startswith("uint64_t"):
280 fn_arg = fn_arg[8:].strip()
283 rust_obj = "uintptr_t"
284 fn_arg = fn_arg[9:].strip()
286 elif is_const and fn_arg.startswith("char *"):
289 fn_ty_arg = "Ljava/lang/String;"
290 fn_arg = fn_arg[6:].strip()
291 elif fn_arg.startswith("LDKStr"):
295 fn_ty_arg = "Ljava/lang/String;"
296 fn_arg = fn_arg[6:].strip()
300 ma = var_ty_regex.match(fn_arg)
301 if ma.group(1).strip() in unitary_enums:
302 assert ma.group(1).strip().startswith("LDK")
303 java_ty = ma.group(1).strip()[3:]
305 c_ty = consts.result_c_ty
306 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
307 fn_arg = ma.group(2).strip()
308 rust_obj = ma.group(1).strip()
310 c_ty = consts.ptr_c_ty
311 java_ty = consts.ptr_native_ty
312 java_hu_ty = ma.group(1).strip()
313 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
314 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
315 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
316 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
317 java_hu_ty = java_hu_ty.replace("LDK", "")
319 fn_arg = ma.group(2).strip()
320 rust_obj = ma.group(1).strip()
321 if rust_obj in trait_structs:
322 contains_trait = True
323 elif rust_obj in complex_enums:
324 contains_trait = complex_enums[rust_obj]
327 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
328 fn_arg = fn_arg.replace("*", "").strip()
330 c_ty = consts.ptr_c_ty
331 java_ty = consts.ptr_native_ty
334 var_is_arr = var_is_arr_regex.match(fn_arg)
335 if var_is_arr is not None or ret_arr_len is not None:
336 assert(not take_by_ptr)
338 # is there a special case for plurals?
339 if len(mapped_type) == 2:
340 java_ty = mapped_type[1]
342 java_ty = java_ty + "[]"
343 c_ty = c_ty + "Array"
344 if var_is_arr is not None:
345 if var_is_arr.group(1) == "":
346 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,
347 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg",
348 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
349 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,
350 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1),
351 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
353 if java_hu_ty is None:
355 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,
356 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,
357 contains_trait=contains_trait)
359 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
360 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
361 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
365 from gen_type_mapping import TypeMappingGenerator
366 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
368 with open(sys.argv[1]) as in_h:
370 reg_fn = reg_fn_regex.match(line)
371 if reg_fn is not None:
372 if reg_fn.group(2).endswith("_clone"):
373 clone_fns.add(reg_fn.group(2))
375 rty = java_c_types(reg_fn.group(1), None)
376 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
377 constructor_fns[rty.rust_obj] = reg_fn.group(3)
379 arr_fn = fn_ret_arr_regex.match(line)
380 if arr_fn is not None:
381 if arr_fn.group(2).endswith("_clone"):
382 clone_fns.add(arr_fn.group(2))
383 # No object constructors return arrays, as then they wouldn't be an object constructor
386 # Define some manual clones...
387 clone_fns.add("ThirtyTwoBytes_clone")
388 write_c("static inline struct LDKThirtyTwoBytes ThirtyTwoBytes_clone(const struct LDKThirtyTwoBytes *orig) { struct LDKThirtyTwoBytes ret; memcpy(ret.data, orig->data, 32); return ret; }\n")
390 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
392 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
393 util.write(consts.util_fn_pfx)
395 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
396 # Map a top-level function
397 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
398 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
399 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
400 method_return_type = re_match.group(1)
401 method_name = re_match.group(2)
402 method_comma_separated_arguments = re_match.group(3)
403 method_arguments = method_comma_separated_arguments.split(',')
405 if method_name.startswith("__"):
408 is_free = method_name.endswith("_free")
409 if method_name.startswith("COption") or method_name.startswith("CResult"):
410 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
411 expected_struct = "LDKC" + struct_meth
412 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
413 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
414 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
415 if method_name.startswith("C2Tuple"):
416 struct_meth = "Two" + tuple_name
417 expected_struct = "LDKC2" + tuple_name
419 struct_meth = "Three" + tuple_name
420 expected_struct = "LDKC3" + tuple_name
421 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
423 struct_meth = method_name.split("_")[0]
424 expected_struct = "LDK" + struct_meth
425 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
427 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
429 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
431 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
433 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
434 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
435 write_c("static inline " + meth_line + " {\n")
436 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
437 write_c(method_name + "(arg)")
438 write_c(return_type_info.ret_conv[1])
439 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
440 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
443 default_constructor_args = {}
445 takes_self_ptr = False
448 for argument_index, argument in enumerate(method_arguments):
449 arg_ty = type_mapping_generator.java_c_types(argument, None)
450 argument_conversion_info = None
451 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
452 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
454 if argument_conversion_info.ty_info.is_ptr:
455 takes_self_ptr = True
456 elif arg_ty.var_name in params_nullable:
457 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
458 if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
459 arg_ty_info = java_c_types(argument, None)
460 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
461 print(" The argument appears to require a move, or not clonable, and is nullable.")
462 print(" Normally for arguments that require a move and are not clonable, we split")
463 print(" the argument into the type's constructor's arguments and just use those to")
464 print(" construct a new object on the fly.")
465 print(" However, because the object is nullable, doing so would mean we can no")
466 print(" longer allow the user to pass null, as we now have an argument list instead.")
467 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
468 print(" It may or may not actually be a reference, but its the simplest mapping option")
469 print(" and also the only use of this code today.")
470 arg_ty_info.requires_clone = False
471 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
472 assert argument_conversion_info.nullable
473 assert argument_conversion_info.arg_conv is not None and "Warning" not in argument_conversion_info.arg_conv
475 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
477 if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
478 if argument_conversion_info.rust_obj in constructor_fns:
480 for explode_arg in constructor_fns[argument_conversion_info.rust_obj].split(','):
481 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
482 if explode_arg_conv.c_ty == "void":
483 # We actually want to handle this case, but for now its only used in NetGraphMsgHandler::new()
484 # which ends up resulting in a redundant constructor - both without arguments for the NetworkGraph.
487 if not argument_conversion_info.arg_name in default_constructor_args:
488 default_constructor_args[argument_conversion_info.arg_name] = []
489 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
490 argument_types.append(argument_conversion_info)
491 if not takes_self and return_type_info.java_hu_ty != struct_meth:
492 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
493 struct_meth_name = method_name
497 out_java.write("\t// " + line)
498 (out_java_delta, out_c_delta, out_java_struct_delta) = \
499 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)
500 out_java.write(out_java_delta)
503 assert len(argument_types) == 1
504 assert return_type_info.c_ty == "void"
505 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")
506 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
507 write_c("\tif ((" + argument_types[0].ty_info.var_name + " & 1) != 0) return;\n")
509 for info in argument_types:
510 if info.arg_conv is not None:
511 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
512 assert c_call_string is None
513 write_c("\t" + method_name + "(")
514 if argument_types[0].arg_conv_name is not None:
515 write_c(argument_types[0].arg_conv_name)
517 for info in argument_types:
518 if info.arg_conv_cleanup is not None:
519 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
524 out_java_struct = None
525 if (expected_struct in opaque_structs or expected_struct in trait_structs
526 or expected_struct in complex_enums or expected_struct in complex_enums
527 or expected_struct in result_types or expected_struct in tuple_types) and not is_free:
528 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
529 out_java_struct.write(out_java_struct_delta)
530 elif (not is_free and not method_name.endswith("_clone") and
531 not method_name.startswith("TxOut") and
532 not method_name.startswith("_") and
533 method_name != "check_platform" and method_name != "Result_read" and
534 not expected_struct in unitary_enums and
535 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
536 or method_name.endswith("_read"))):
537 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
538 for line in out_java_struct_delta.splitlines():
539 if not line.strip().startswith("this."):
540 out_java_struct.write(line + "\n")
542 out_java_struct.write("\t\t// " + line.strip() + "\n")
544 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
545 assert struct_name.startswith("LDK")
546 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
547 unitary_enums.add(struct_name)
548 for idx, (struct_line, _) in enumerate(field_lines):
550 assert(struct_line == "typedef enum %s {" % struct_name)
551 elif idx == len(field_lines) - 3:
552 assert(struct_line.endswith("_Sentinel,"))
553 elif idx == len(field_lines) - 2:
554 assert(struct_line == "} %s;" % struct_name)
555 elif idx == len(field_lines) - 1:
556 assert(struct_line == "")
557 assert struct_name.startswith("LDK")
558 (c_out, native_file_out, native_out) = consts.native_c_unitary_enum_map(struct_name[3:], [(x.strip().strip(","), y) for x, y in field_lines[1:-3]], enum_doc_comment)
560 out_java_enum.write(native_file_out)
561 out_java.write(native_out)
563 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
564 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
567 tag_field_lines = union_enum_items["field_lines"]
568 contains_trait = False
569 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
571 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
572 elif idx == len(tag_field_lines) - 3:
573 assert(struct_line.endswith("_Sentinel,"))
574 elif idx == len(tag_field_lines) - 2:
575 assert(struct_line == "} %s_Tag;" % struct_name)
576 elif idx == len(tag_field_lines) - 1:
577 assert(struct_line == "")
579 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
581 if "LDK" + variant_name in union_enum_items:
582 enum_var_lines = union_enum_items["LDK" + variant_name]
583 for idx, (field, field_docs) in enumerate(enum_var_lines):
584 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
585 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
586 contains_trait |= field_ty.contains_trait
587 if field_docs is not None and doc_to_field_nullable(field_docs):
588 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
590 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
591 fields.append((field_conv, field_docs))
592 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
593 elif camel_to_snake(variant_name) in inline_enum_variants:
594 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
595 # docs through to there, and then potentially mark the field nullable.
596 mapped = type_mapping_generator.map_type(inline_enum_variants[camel_to_snake(variant_name)] + " " + camel_to_snake(variant_name), False, None, False, True)
597 contains_trait |= mapped.ty_info.contains_trait
598 fields.append((mapped, None))
599 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
601 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
602 complex_enums[struct_name] = contains_trait
604 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
605 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
607 out_java_enum.write(out_java_enum_addendum)
608 out_java.write(out_java_addendum)
609 write_c(out_c_addendum)
611 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
612 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
614 flattened_field_var_convs = []
615 for var_line in field_var_lines:
616 if var_line.group(1) in trait_structs:
617 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
618 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
619 flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
621 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
622 field_var_convs.append(mapped)
623 flattened_field_var_convs.append(mapped)
624 trait_structs[struct_name] = field_var_convs
627 for fn_docs, fn_line in trait_fn_lines:
628 if fn_line == "cloned":
629 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
630 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
632 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
634 assert False # This isn't yet handled on the Java side
635 ret_ty_info.nullable = True
636 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
638 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
639 is_const = fn_line.group(4) is not None
642 for idx, arg in enumerate(fn_line.group(5).split(',')):
645 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
646 if arg_ty_info.var_name in nullable_params:
647 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
648 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
650 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
651 arg_tys.append(arg_conv_info)
652 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
654 (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)
655 write_c(out_c_addendum)
656 out_java_trait.write(out_java_trait_addendum)
657 out_java.write(out_java_addendum)
659 for fn_docs, fn_line in trait_fn_lines:
660 if fn_line == "cloned":
662 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
663 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
664 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
665 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"
666 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)
667 for idx, var_line in enumerate(field_var_lines):
668 if var_line.group(1) not in trait_structs:
669 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
670 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
671 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
672 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
674 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"
675 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)
677 def map_result(struct_name, res_ty, err_ty):
678 result_types.add(struct_name)
679 human_ty = struct_name.replace("LDKCResult", "Result")
680 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
681 out_java_struct.write(consts.hu_struct_file_prefix)
682 out_java_struct.write("public class " + human_ty + " extends CommonBase {\n")
683 out_java_struct.write("\tprivate " + human_ty + "(Object _dummy, long ptr) { super(ptr); }\n")
684 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
685 out_java_struct.write("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); } super.finalize();\n")
686 out_java_struct.write("\t}\n\n")
687 out_java_struct.write("\tstatic " + human_ty + " constr_from_ptr(long ptr) {\n")
688 out_java_struct.write("\t\tif (bindings." + struct_name.replace("LDK", "") + "_is_ok(ptr)) {\n")
689 out_java_struct.write("\t\t\treturn new " + human_ty + "_OK(null, ptr);\n")
690 out_java_struct.write("\t\t} else {\n")
691 out_java_struct.write("\t\t\treturn new " + human_ty + "_Err(null, ptr);\n")
692 out_java_struct.write("\t\t}\n")
693 out_java_struct.write("\t}\n")
695 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
696 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
698 if not res_map.is_native_primitive and (res_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
700 if not err_map.is_native_primitive and (err_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
703 out_java.write("\tpublic static native " + res_map.java_ty + " " + struct_name + "_get_ok(long arg);\n")
704 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")
705 write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
706 write_c("\tCHECK(val->result_ok);\n\t")
707 out_java_struct.write("\tpublic static final class " + human_ty + "_OK extends " + human_ty + " {\n")
708 if res_map.ret_conv is not None:
709 write_c(res_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.result)")
710 write_c(res_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + res_map.ret_conv_name)
712 write_c("return *val->contents.result")
715 if res_map.java_hu_ty != "void":
716 out_java_struct.write("\t\tpublic final " + res_map.java_hu_ty + " res;\n")
717 out_java_struct.write("\t\tprivate " + human_ty + "_OK(Object _dummy, long ptr) {\n")
718 out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
719 if res_map.java_hu_ty == "void":
721 elif res_map.to_hu_conv is not None:
722 out_java_struct.write("\t\t\t" + res_map.java_ty + " res = bindings." + struct_name + "_get_ok(ptr);\n")
723 out_java_struct.write("\t\t\t" + res_map.to_hu_conv.replace("\n", "\n\t\t\t"))
724 out_java_struct.write("\n\t\t\tthis.res = " + res_map.to_hu_conv_name + ";\n")
726 out_java_struct.write("\t\t\tthis.res = bindings." + struct_name + "_get_ok(ptr);\n")
727 out_java_struct.write("\t\t}\n")
728 out_java_struct.write("\t}\n\n")
730 out_java.write("\tpublic static native " + err_map.java_ty + " " + struct_name + "_get_err(long arg);\n")
731 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")
732 write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
733 write_c("\tCHECK(!val->result_ok);\n\t")
734 out_java_struct.write("\tpublic static final class " + human_ty + "_Err extends " + human_ty + " {\n")
735 if err_map.ret_conv is not None:
736 write_c(err_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.err)")
737 write_c(err_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + err_map.ret_conv_name)
739 write_c("return *val->contents.err")
742 if err_map.java_hu_ty != "void":
743 out_java_struct.write("\t\tpublic final " + err_map.java_hu_ty + " err;\n")
744 out_java_struct.write("\t\tprivate " + human_ty + "_Err(Object _dummy, long ptr) {\n")
745 out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
746 if err_map.java_hu_ty == "void":
748 elif err_map.to_hu_conv is not None:
749 out_java_struct.write("\t\t\t" + err_map.java_ty + " err = bindings." + struct_name + "_get_err(ptr);\n")
750 out_java_struct.write("\t\t\t" + err_map.to_hu_conv.replace("\n", "\n\t\t\t"))
751 out_java_struct.write("\n\t\t\tthis.err = " + err_map.to_hu_conv_name + ";\n")
753 out_java_struct.write("\t\t\tthis.err = bindings." + struct_name + "_get_err(ptr);\n")
754 out_java_struct.write("\t\t}\n")
756 out_java_struct.write("\t}\n\n")
758 def map_tuple(struct_name, field_lines):
759 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
760 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
761 out_java_struct.write(consts.map_tuple(struct_name))
763 for idx, (line, _) in enumerate(field_lines):
764 if idx != 0 and idx < len(field_lines) - 2:
765 ty_list.append(java_c_types(line.strip(';'), None))
766 tuple_types[struct_name] = (ty_list, struct_name)
768 # Map virtual getter functions
769 for idx, (line, _) in enumerate(field_lines):
770 if idx != 0 and idx < len(field_lines) - 2:
771 field_name = chr(ord('a') + idx - 1)
772 assert line.endswith(" " + field_name + ";")
773 field_ty = java_c_types(line[:-1], None)
774 ptr_fn_defn = line[:-3].strip() + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR tuple)"
775 owned_fn_defn = line[:-3].strip() + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR tuple)"
778 if field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
779 fn_defn = owned_fn_defn
780 write_c("static inline " + fn_defn + "{\n")
781 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&tuple->" + field_name + ");\n")
782 elif field_ty.arr_len is not None or field_ty.is_native_primitive:
783 fn_defn = owned_fn_defn
784 write_c("static inline " + fn_defn + "{\n")
785 write_c("\treturn tuple->" + field_name + ";\n")
787 fn_defn = ptr_fn_defn
788 write_c("static inline " + fn_defn + "{\n")
789 write_c("\treturn &tuple->" + field_name + ";\n")
792 dummy_line = fn_defn + ";\n"
793 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
795 out_java.write(consts.bindings_header)
796 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
797 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
799 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
800 out_java_struct.write(consts.common_base)
803 last_block_comment = None
806 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
808 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
809 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
810 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
811 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
812 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
813 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
814 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
815 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
816 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
817 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
818 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
819 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
820 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
821 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
822 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
824 union_enum_items = {}
825 result_ptr_struct_items = {}
827 if block_comment is not None:
828 if line.endswith("*/\n"):
829 last_block_comment = block_comment.strip("\n")
832 block_comment = block_comment + line.strip(" /*")
833 elif cur_block_obj is not None:
834 cur_block_obj = cur_block_obj + line
835 if line.startswith("} "):
839 obj_lines = cur_block_obj.split("\n")
841 result_contents = None
842 is_unitary_enum = False
843 is_union_enum = False
848 last_struct_block_comment = None
850 for idx, struct_line in enumerate(obj_lines):
851 if struct_line.strip().startswith("/*"):
852 block_comment = struct_line.strip(" /*")
853 if block_comment is not None:
854 if struct_line.endswith("*/"):
855 last_struct_block_comment = block_comment.strip("\n")
858 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
860 struct_name_match = struct_name_regex.match(struct_line)
861 if struct_name_match is not None:
862 struct_name = struct_name_match.group(3)
863 if struct_name_match.group(1) == "enum":
864 if not struct_name.endswith("_Tag"):
865 is_unitary_enum = True
868 elif struct_name_match.group(1) == "union":
870 if line_indicates_opaque_regex.match(struct_line):
872 result_match = line_indicates_result_regex.match(struct_line)
873 if result_match is not None:
874 result_contents = result_match.group(1)
875 vec_ty_match = line_indicates_vec_regex.match(struct_line)
876 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
877 vec_ty = vec_ty_match.group(2)
878 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
880 trait_fn_match = line_indicates_trait_regex.match(struct_line)
881 if trait_fn_match is not None:
882 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
883 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
884 if trait_clone_fn_match is not None:
885 trait_fn_lines.append((last_struct_block_comment, "cloned"))
886 field_var_match = line_field_var_regex.match(struct_line)
887 if field_var_match is not None:
888 field_var_lines.append(field_var_match)
889 field_lines.append((struct_line, last_struct_block_comment))
890 last_struct_block_comment = None
892 assert(struct_name is not None)
893 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))
894 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))
895 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))
896 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))
897 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))
898 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))
899 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))
902 opaque_structs.add(struct_name)
903 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
904 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
905 last_block_comment = None
906 out_java_struct.write(out_opaque_struct_human)
907 elif result_contents is not None:
908 assert result_contents in result_ptr_struct_items
909 res_ty, err_ty = result_ptr_struct_items[result_contents]
910 map_result(struct_name, res_ty, err_ty)
911 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
912 for line, _ in field_lines:
913 if line.endswith("*result;"):
914 res_ty = line[:-8].strip()
915 elif line.endswith("*err;"):
916 err_ty = line[:-5].strip()
917 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
918 result_types.add(struct_name[:-3])
920 map_tuple(struct_name, field_lines)
921 elif vec_ty is not None:
922 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
923 if ty_info.is_native_primitive:
924 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
925 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
926 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
927 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
928 write_c("\treturn ret;\n}\n")
929 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
930 ty_name = "CVec_" + ty_info.rust_obj.replace("LDK", "") + "Z";
931 clone_fns.add(ty_name + "_clone")
932 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
933 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
934 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
935 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
936 write_c("\t}\n\treturn ret;\n}\n")
938 assert(struct_name.endswith("_Tag"))
939 struct_name = struct_name[:-4]
940 union_enum_items[struct_name] = {"field_lines": field_lines}
941 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
942 enum_var_name = struct_name.split("_")
943 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
944 elif struct_name in union_enum_items:
947 for line, _ in field_lines:
948 if line == " struct {":
952 elif elem_items > -1:
954 if line.startswith("struct "):
956 elif line.startswith("enum "):
958 split = line.split(" ")
959 assert len(split) == 2
960 tuple_variants[split[1].strip(";")] = split[0]
963 # We don't currently support tuple variant with more than one element
965 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
966 last_block_comment = None
967 elif is_unitary_enum:
968 map_unitary_enum(struct_name, field_lines, last_block_comment)
969 last_block_comment = None
970 elif len(trait_fn_lines) > 0:
971 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
972 elif struct_name == "LDKTxOut":
973 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
974 out_java_struct.write(consts.hu_struct_file_prefix)
975 out_java_struct.write("public class TxOut extends CommonBase{\n")
976 out_java_struct.write("\t/** The script_pubkey in this output */\n")
977 out_java_struct.write("\tpublic final byte[] script_pubkey;\n")
978 out_java_struct.write("\t/** The value, in satoshis, of this output */\n")
979 out_java_struct.write("\tpublic final long value;\n")
980 out_java_struct.write("\n")
981 out_java_struct.write("\tTxOut(java.lang.Object _dummy, long ptr) {\n")
982 out_java_struct.write("\t\tsuper(ptr);\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("\tpublic TxOut(long value, byte[] script_pubkey) {\n")
987 out_java_struct.write("\t\tsuper(bindings.TxOut_new(script_pubkey, value));\n")
988 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
989 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
990 out_java_struct.write("\t}\n")
991 out_java_struct.write("\n")
992 out_java_struct.write("\t@Override @SuppressWarnings(\"deprecation\")\n")
993 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
994 out_java_struct.write("\t\tsuper.finalize();\n")
995 out_java_struct.write("\t\tif (ptr != 0) { bindings.TxOut_free(ptr); }\n")
996 out_java_struct.write("\t}\n")
997 out_java_struct.write("\n")
998 out_java_struct.write("}")
999 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1000 write_c(fn_line + " {")
1001 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1003 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1004 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1005 write_c(fn_line + " {")
1006 write_c("\treturn thing->value;")
1008 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1010 pass # Everything remaining is a byte[] or some form
1011 cur_block_obj = None
1013 fn_ptr = fn_ptr_regex.match(line)
1014 fn_ret_arr = fn_ret_arr_regex.match(line)
1015 reg_fn = reg_fn_regex.match(line)
1016 const_val = const_val_regex.match(line)
1018 if line.startswith("#include <"):
1020 elif line.startswith("/*"):
1021 if not line.endswith("*/\n"):
1022 block_comment = line.strip(" /*")
1023 elif line.startswith("typedef enum "):
1024 cur_block_obj = line
1025 elif line.startswith("typedef struct "):
1026 cur_block_obj = line
1027 elif line.startswith("typedef union "):
1028 cur_block_obj = line
1029 elif fn_ptr is not None:
1030 map_fn(line, fn_ptr, None, None, last_block_comment)
1031 last_block_comment = None
1032 elif fn_ret_arr is not None:
1033 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1034 last_block_comment = None
1035 elif reg_fn is not None:
1036 map_fn(line, reg_fn, None, None, last_block_comment)
1037 last_block_comment = None
1038 elif const_val_regex is not None:
1039 # TODO Map const variables
1042 assert(line == "\n")
1044 out_java.write(consts.bindings_footer)
1045 for struct_name in opaque_structs:
1046 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1047 out_java_struct.write("}\n")
1048 for struct_name in trait_structs:
1049 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1050 out_java_struct.write("}\n")
1051 for struct_name in complex_enums:
1052 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1053 out_java_struct.write("}\n")
1054 for struct_name in result_types:
1055 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1056 out_java_struct.write("}\n")
1057 for struct_name in tuple_types:
1058 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1059 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1060 out_java_struct.write("}\n")
1062 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1063 out_c.write(consts.c_file_pfx)
1064 out_c.write(consts.init_str())
1066 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1067 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1068 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1069 util.write(consts.util_fn_sfx)