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("LDKTenBytes"):
178 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[10]"
179 assert var_is_arr_regex.match(fn_arg[8:])
180 rust_obj = "LDKTenBytes"
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)
434 default_constructor_args = {}
436 takes_self_ptr = False
439 for argument_index, argument in enumerate(method_arguments):
440 arg_ty = type_mapping_generator.java_c_types(argument, None)
441 argument_conversion_info = None
442 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
443 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
445 if argument_conversion_info.ty_info.is_ptr:
446 takes_self_ptr = True
447 elif arg_ty.var_name in params_nullable:
448 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
449 if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
450 arg_ty_info = java_c_types(argument, None)
451 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
452 print(" The argument appears to require a move, or not clonable, and is nullable.")
453 print(" Normally for arguments that require a move and are not clonable, we split")
454 print(" the argument into the type's constructor's arguments and just use those to")
455 print(" construct a new object on the fly.")
456 print(" However, because the object is nullable, doing so would mean we can no")
457 print(" longer allow the user to pass null, as we now have an argument list instead.")
458 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
459 print(" It may or may not actually be a reference, but its the simplest mapping option")
460 print(" and also the only use of this code today.")
461 arg_ty_info.requires_clone = False
462 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
463 assert argument_conversion_info.nullable
464 assert argument_conversion_info.arg_conv is not None and "Warning" not in argument_conversion_info.arg_conv
466 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
468 if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
469 if argument_conversion_info.rust_obj in constructor_fns:
471 for explode_arg in constructor_fns[argument_conversion_info.rust_obj].split(','):
472 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
473 if explode_arg_conv.c_ty == "void":
474 # We actually want to handle this case, but for now its only used in NetGraphMsgHandler::new()
475 # which ends up resulting in a redundant constructor - both without arguments for the NetworkGraph.
478 if not argument_conversion_info.arg_name in default_constructor_args:
479 default_constructor_args[argument_conversion_info.arg_name] = []
480 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
481 argument_types.append(argument_conversion_info)
482 if not takes_self and return_type_info.java_hu_ty != struct_meth:
483 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
484 struct_meth_name = method_name
488 out_java.write("\t// " + line)
489 (out_java_delta, out_c_delta, out_java_struct_delta) = \
490 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)
491 out_java.write(out_java_delta)
494 assert len(argument_types) == 1
495 assert return_type_info.c_ty == "void"
496 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")
497 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
498 write_c("\tif ((" + argument_types[0].ty_info.var_name + " & 1) != 0) return;\n")
500 for info in argument_types:
501 if info.arg_conv is not None:
502 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
503 assert c_call_string is None
504 write_c("\t" + method_name + "(")
505 if argument_types[0].arg_conv_name is not None:
506 write_c(argument_types[0].arg_conv_name)
508 for info in argument_types:
509 if info.arg_conv_cleanup is not None:
510 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
515 out_java_struct = None
516 if (expected_struct in opaque_structs or expected_struct in trait_structs
517 or expected_struct in complex_enums or expected_struct in complex_enums
518 or expected_struct in result_types or expected_struct in tuple_types) and not is_free:
519 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
520 out_java_struct.write(out_java_struct_delta)
521 elif (not is_free and not method_name.endswith("_clone") and
522 not method_name.startswith("TxOut") and
523 not method_name.startswith("_") and
524 method_name != "check_platform" and method_name != "Result_read" and
525 not expected_struct in unitary_enums and
526 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
527 or method_name.endswith("_read"))):
528 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
529 for line in out_java_struct_delta.splitlines():
530 if not line.strip().startswith("this."):
531 out_java_struct.write(line + "\n")
533 out_java_struct.write("\t\t// " + line.strip() + "\n")
535 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
536 assert struct_name.startswith("LDK")
537 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
538 unitary_enums.add(struct_name)
539 for idx, (struct_line, _) in enumerate(field_lines):
541 assert(struct_line == "typedef enum %s {" % struct_name)
542 elif idx == len(field_lines) - 3:
543 assert(struct_line.endswith("_Sentinel,"))
544 elif idx == len(field_lines) - 2:
545 assert(struct_line == "} %s;" % struct_name)
546 elif idx == len(field_lines) - 1:
547 assert(struct_line == "")
548 assert struct_name.startswith("LDK")
549 (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)
551 out_java_enum.write(native_file_out)
552 out_java.write(native_out)
554 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
555 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
558 tag_field_lines = union_enum_items["field_lines"]
559 contains_trait = False
560 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
562 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
563 elif idx == len(tag_field_lines) - 3:
564 assert(struct_line.endswith("_Sentinel,"))
565 elif idx == len(tag_field_lines) - 2:
566 assert(struct_line == "} %s_Tag;" % struct_name)
567 elif idx == len(tag_field_lines) - 1:
568 assert(struct_line == "")
570 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
572 if "LDK" + variant_name in union_enum_items:
573 enum_var_lines = union_enum_items["LDK" + variant_name]
574 for idx, (field, field_docs) in enumerate(enum_var_lines):
575 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
576 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
577 contains_trait |= field_ty.contains_trait
578 if field_docs is not None and doc_to_field_nullable(field_docs):
579 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
581 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
582 fields.append((field_conv, field_docs))
583 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
584 elif camel_to_snake(variant_name) in inline_enum_variants:
585 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
586 # docs through to there, and then potentially mark the field nullable.
587 mapped = type_mapping_generator.map_type(inline_enum_variants[camel_to_snake(variant_name)] + " " + camel_to_snake(variant_name), False, None, False, True)
588 contains_trait |= mapped.ty_info.contains_trait
589 fields.append((mapped, None))
590 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
592 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
593 complex_enums[struct_name] = contains_trait
595 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
596 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
598 out_java_enum.write(out_java_enum_addendum)
599 out_java.write(out_java_addendum)
600 write_c(out_c_addendum)
602 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
603 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
605 flattened_field_var_convs = []
606 for var_line in field_var_lines:
607 if var_line.group(1) in trait_structs:
608 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
609 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
610 flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
612 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
613 field_var_convs.append(mapped)
614 flattened_field_var_convs.append(mapped)
615 trait_structs[struct_name] = field_var_convs
618 for fn_docs, fn_line in trait_fn_lines:
619 if fn_line == "cloned":
620 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
621 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
623 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
625 assert False # This isn't yet handled on the Java side
626 ret_ty_info.nullable = True
627 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
629 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
630 is_const = fn_line.group(4) is not None
633 for idx, arg in enumerate(fn_line.group(5).split(',')):
636 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
637 if arg_ty_info.var_name in nullable_params:
638 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
639 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
641 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
642 arg_tys.append(arg_conv_info)
643 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
645 (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)
646 write_c(out_c_addendum)
647 out_java_trait.write(out_java_trait_addendum)
648 out_java.write(out_java_addendum)
650 for fn_docs, fn_line in trait_fn_lines:
651 if fn_line == "cloned":
653 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
654 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
655 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
656 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"
657 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)
658 for idx, var_line in enumerate(field_var_lines):
659 if var_line.group(1) not in trait_structs:
660 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
661 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
662 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
663 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
665 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"
666 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)
668 def map_result(struct_name, res_ty, err_ty):
669 result_types.add(struct_name)
670 human_ty = struct_name.replace("LDKCResult", "Result")
671 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
672 out_java_struct.write(consts.hu_struct_file_prefix)
673 out_java_struct.write("public class " + human_ty + " extends CommonBase {\n")
674 out_java_struct.write("\tprivate " + human_ty + "(Object _dummy, long ptr) { super(ptr); }\n")
675 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
676 out_java_struct.write("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); } super.finalize();\n")
677 out_java_struct.write("\t}\n\n")
678 out_java_struct.write("\tstatic " + human_ty + " constr_from_ptr(long ptr) {\n")
679 out_java_struct.write("\t\tif (bindings." + struct_name.replace("LDK", "") + "_is_ok(ptr)) {\n")
680 out_java_struct.write("\t\t\treturn new " + human_ty + "_OK(null, ptr);\n")
681 out_java_struct.write("\t\t} else {\n")
682 out_java_struct.write("\t\t\treturn new " + human_ty + "_Err(null, ptr);\n")
683 out_java_struct.write("\t\t}\n")
684 out_java_struct.write("\t}\n")
686 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
687 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
689 if not res_map.is_native_primitive and (res_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
691 if not err_map.is_native_primitive and (err_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
694 out_java.write("\tpublic static native " + res_map.java_ty + " " + struct_name + "_get_ok(long arg);\n")
695 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")
696 write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
697 write_c("\tCHECK(val->result_ok);\n\t")
698 out_java_struct.write("\tpublic static final class " + human_ty + "_OK extends " + human_ty + " {\n")
699 if res_map.ret_conv is not None:
700 write_c(res_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.result)")
701 write_c(res_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + res_map.ret_conv_name)
703 write_c("return *val->contents.result")
706 if res_map.java_hu_ty != "void":
707 out_java_struct.write("\t\tpublic final " + res_map.java_hu_ty + " res;\n")
708 out_java_struct.write("\t\tprivate " + human_ty + "_OK(Object _dummy, long ptr) {\n")
709 out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
710 if res_map.java_hu_ty == "void":
712 elif res_map.to_hu_conv is not None:
713 out_java_struct.write("\t\t\t" + res_map.java_ty + " res = bindings." + struct_name + "_get_ok(ptr);\n")
714 out_java_struct.write("\t\t\t" + res_map.to_hu_conv.replace("\n", "\n\t\t\t"))
715 out_java_struct.write("\n\t\t\tthis.res = " + res_map.to_hu_conv_name + ";\n")
717 out_java_struct.write("\t\t\tthis.res = bindings." + struct_name + "_get_ok(ptr);\n")
718 out_java_struct.write("\t\t}\n")
719 out_java_struct.write("\t}\n\n")
721 out_java.write("\tpublic static native " + err_map.java_ty + " " + struct_name + "_get_err(long arg);\n")
722 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")
723 write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
724 write_c("\tCHECK(!val->result_ok);\n\t")
725 out_java_struct.write("\tpublic static final class " + human_ty + "_Err extends " + human_ty + " {\n")
726 if err_map.ret_conv is not None:
727 write_c(err_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.err)")
728 write_c(err_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + err_map.ret_conv_name)
730 write_c("return *val->contents.err")
733 if err_map.java_hu_ty != "void":
734 out_java_struct.write("\t\tpublic final " + err_map.java_hu_ty + " err;\n")
735 out_java_struct.write("\t\tprivate " + human_ty + "_Err(Object _dummy, long ptr) {\n")
736 out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
737 if err_map.java_hu_ty == "void":
739 elif err_map.to_hu_conv is not None:
740 out_java_struct.write("\t\t\t" + err_map.java_ty + " err = bindings." + struct_name + "_get_err(ptr);\n")
741 out_java_struct.write("\t\t\t" + err_map.to_hu_conv.replace("\n", "\n\t\t\t"))
742 out_java_struct.write("\n\t\t\tthis.err = " + err_map.to_hu_conv_name + ";\n")
744 out_java_struct.write("\t\t\tthis.err = bindings." + struct_name + "_get_err(ptr);\n")
745 out_java_struct.write("\t\t}\n")
747 out_java_struct.write("\t}\n\n")
749 def map_tuple(struct_name, field_lines):
750 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
751 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
752 out_java_struct.write(consts.map_tuple(struct_name))
754 for idx, (line, _) in enumerate(field_lines):
755 if idx != 0 and idx < len(field_lines) - 2:
756 ty_list.append(java_c_types(line.strip(';'), None))
757 tuple_types[struct_name] = (ty_list, struct_name)
759 # Map virtual getter functions
760 for idx, (line, _) in enumerate(field_lines):
761 if idx != 0 and idx < len(field_lines) - 2:
762 field_name = chr(ord('a') + idx - 1)
763 assert line.endswith(" " + field_name + ";")
764 field_ty = java_c_types(line[:-1], None)
765 ptr_fn_defn = line[:-3].strip() + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR tuple)"
766 owned_fn_defn = line[:-3].strip() + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR tuple)"
769 if field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
770 fn_defn = owned_fn_defn
771 write_c("static inline " + fn_defn + "{\n")
772 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&tuple->" + field_name + ");\n")
773 elif field_ty.arr_len is not None or field_ty.is_native_primitive:
774 fn_defn = owned_fn_defn
775 write_c("static inline " + fn_defn + "{\n")
776 write_c("\treturn tuple->" + field_name + ";\n")
778 fn_defn = ptr_fn_defn
779 write_c("static inline " + fn_defn + "{\n")
780 write_c("\treturn &tuple->" + field_name + ";\n")
783 dummy_line = fn_defn + ";\n"
784 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
786 out_java.write(consts.bindings_header)
787 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
788 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
790 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
791 out_java_struct.write(consts.common_base)
794 last_block_comment = None
797 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
799 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
800 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
801 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
802 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
803 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
804 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
805 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
806 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
807 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
808 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
809 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
810 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
811 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
812 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
813 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
815 union_enum_items = {}
816 result_ptr_struct_items = {}
818 if block_comment is not None:
819 if line.endswith("*/\n"):
820 last_block_comment = block_comment.strip("\n")
823 block_comment = block_comment + line.strip(" /*")
824 elif cur_block_obj is not None:
825 cur_block_obj = cur_block_obj + line
826 if line.startswith("} "):
830 obj_lines = cur_block_obj.split("\n")
832 result_contents = None
833 is_unitary_enum = False
834 is_union_enum = False
839 last_struct_block_comment = None
841 for idx, struct_line in enumerate(obj_lines):
842 if struct_line.strip().startswith("/*"):
843 block_comment = struct_line.strip(" /*")
844 if block_comment is not None:
845 if struct_line.endswith("*/"):
846 last_struct_block_comment = block_comment.strip("\n")
849 block_comment = block_comment + "\n" + struct_line.strip(" /*")
851 struct_name_match = struct_name_regex.match(struct_line)
852 if struct_name_match is not None:
853 struct_name = struct_name_match.group(3)
854 if struct_name_match.group(1) == "enum":
855 if not struct_name.endswith("_Tag"):
856 is_unitary_enum = True
859 elif struct_name_match.group(1) == "union":
861 if line_indicates_opaque_regex.match(struct_line):
863 result_match = line_indicates_result_regex.match(struct_line)
864 if result_match is not None:
865 result_contents = result_match.group(1)
866 vec_ty_match = line_indicates_vec_regex.match(struct_line)
867 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
868 vec_ty = vec_ty_match.group(2)
869 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
871 trait_fn_match = line_indicates_trait_regex.match(struct_line)
872 if trait_fn_match is not None:
873 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
874 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
875 if trait_clone_fn_match is not None:
876 trait_fn_lines.append((last_struct_block_comment, "cloned"))
877 field_var_match = line_field_var_regex.match(struct_line)
878 if field_var_match is not None:
879 field_var_lines.append(field_var_match)
880 field_lines.append((struct_line, last_struct_block_comment))
881 last_struct_block_comment = None
883 assert(struct_name is not None)
884 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))
885 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))
886 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))
887 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))
888 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))
889 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))
890 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))
893 opaque_structs.add(struct_name)
894 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
895 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
896 last_block_comment = None
897 out_java_struct.write(out_opaque_struct_human)
898 elif result_contents is not None:
899 assert result_contents in result_ptr_struct_items
900 res_ty, err_ty = result_ptr_struct_items[result_contents]
901 map_result(struct_name, res_ty, err_ty)
902 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
903 for line, _ in field_lines:
904 if line.endswith("*result;"):
905 res_ty = line[:-8].strip()
906 elif line.endswith("*err;"):
907 err_ty = line[:-5].strip()
908 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
909 result_types.add(struct_name[:-3])
911 map_tuple(struct_name, field_lines)
912 elif vec_ty is not None:
913 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
914 if ty_info.is_native_primitive:
915 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
916 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
917 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
918 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
919 write_c("\treturn ret;\n}\n")
920 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
921 ty_name = "CVec_" + ty_info.rust_obj.replace("LDK", "") + "Z";
922 clone_fns.add(ty_name + "_clone")
923 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
924 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
925 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
926 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
927 write_c("\t}\n\treturn ret;\n}\n")
929 assert(struct_name.endswith("_Tag"))
930 struct_name = struct_name[:-4]
931 union_enum_items[struct_name] = {"field_lines": field_lines}
932 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
933 enum_var_name = struct_name.split("_")
934 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
935 elif struct_name in union_enum_items:
938 for line, _ in field_lines:
939 if line == " struct {":
943 elif elem_items > -1:
945 if line.startswith("struct "):
947 elif line.startswith("enum "):
949 split = line.split(" ")
950 assert len(split) == 2
951 tuple_variants[split[1].strip(";")] = split[0]
954 # We don't currently support tuple variant with more than one element
956 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
957 last_block_comment = None
958 elif is_unitary_enum:
959 map_unitary_enum(struct_name, field_lines, last_block_comment)
960 last_block_comment = None
961 elif len(trait_fn_lines) > 0:
962 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
963 elif struct_name == "LDKTxOut":
964 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
965 out_java_struct.write(consts.hu_struct_file_prefix)
966 out_java_struct.write("public class TxOut extends CommonBase{\n")
967 out_java_struct.write("\t/** The script_pubkey in this output */\n")
968 out_java_struct.write("\tpublic final byte[] script_pubkey;\n")
969 out_java_struct.write("\t/** The value, in satoshis, of this output */\n")
970 out_java_struct.write("\tpublic final long value;\n")
971 out_java_struct.write("\n")
972 out_java_struct.write("\tTxOut(java.lang.Object _dummy, long ptr) {\n")
973 out_java_struct.write("\t\tsuper(ptr);\n")
974 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
975 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
976 out_java_struct.write("\t}\n")
977 out_java_struct.write("\tpublic TxOut(long value, byte[] script_pubkey) {\n")
978 out_java_struct.write("\t\tsuper(bindings.TxOut_new(script_pubkey, value));\n")
979 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
980 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
981 out_java_struct.write("\t}\n")
982 out_java_struct.write("\n")
983 out_java_struct.write("\t@Override @SuppressWarnings(\"deprecation\")\n")
984 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
985 out_java_struct.write("\t\tsuper.finalize();\n")
986 out_java_struct.write("\t\tif (ptr != 0) { bindings.TxOut_free(ptr); }\n")
987 out_java_struct.write("\t}\n")
988 out_java_struct.write("\n")
989 out_java_struct.write("}")
990 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
991 write_c(fn_line + " {")
992 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
994 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
995 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
996 write_c(fn_line + " {")
997 write_c("\treturn thing->value;")
999 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1001 pass # Everything remaining is a byte[] or some form
1002 cur_block_obj = None
1004 fn_ptr = fn_ptr_regex.match(line)
1005 fn_ret_arr = fn_ret_arr_regex.match(line)
1006 reg_fn = reg_fn_regex.match(line)
1007 const_val = const_val_regex.match(line)
1009 if line.startswith("#include <"):
1011 elif line.startswith("/*"):
1012 if not line.endswith("*/\n"):
1013 block_comment = line.strip(" /*")
1014 elif line.startswith("typedef enum "):
1015 cur_block_obj = line
1016 elif line.startswith("typedef struct "):
1017 cur_block_obj = line
1018 elif line.startswith("typedef union "):
1019 cur_block_obj = line
1020 elif fn_ptr is not None:
1021 map_fn(line, fn_ptr, None, None, last_block_comment)
1022 last_block_comment = None
1023 elif fn_ret_arr is not None:
1024 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1025 last_block_comment = None
1026 elif reg_fn is not None:
1027 map_fn(line, reg_fn, None, None, last_block_comment)
1028 last_block_comment = None
1029 elif const_val_regex is not None:
1030 # TODO Map const variables
1033 assert(line == "\n")
1035 out_java.write(consts.bindings_footer)
1036 for struct_name in opaque_structs:
1037 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1038 out_java_struct.write("}\n")
1039 for struct_name in trait_structs:
1040 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1041 out_java_struct.write("}\n")
1042 for struct_name in complex_enums:
1043 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1044 out_java_struct.write("}\n")
1045 for struct_name in result_types:
1046 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1047 out_java_struct.write("}\n")
1048 for struct_name in tuple_types:
1049 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1050 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1051 out_java_struct.write("}\n")
1053 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1054 out_c.write(consts.c_file_pfx)
1055 out_c.write(consts.init_str())
1057 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1058 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1059 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1060 util.write(consts.util_fn_sfx)