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"):
414 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
415 struct_meth = "Two" + tuple_name
416 expected_struct = "LDKC2" + tuple_name
417 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
419 struct_meth = method_name.split("_")[0]
420 expected_struct = "LDK" + struct_meth
421 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
423 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
425 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
427 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
430 default_constructor_args = {}
432 takes_self_ptr = False
435 for argument_index, argument in enumerate(method_arguments):
436 arg_ty = type_mapping_generator.java_c_types(argument, None)
437 argument_conversion_info = None
438 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
439 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
441 if argument_conversion_info.ty_info.is_ptr:
442 takes_self_ptr = True
443 elif arg_ty.var_name in params_nullable:
444 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
445 if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
446 arg_ty_info = java_c_types(argument, None)
447 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
448 print(" The argument appears to require a move, or not clonable, and is nullable.")
449 print(" Normally for arguments that require a move and are not clonable, we split")
450 print(" the argument into the type's constructor's arguments and just use those to")
451 print(" construct a new object on the fly.")
452 print(" However, because the object is nullable, doing so would mean we can no")
453 print(" longer allow the user to pass null, as we now have an argument list instead.")
454 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
455 print(" It may or may not actually be a reference, but its the simplest mapping option")
456 print(" and also the only use of this code today.")
457 arg_ty_info.requires_clone = False
458 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
459 assert argument_conversion_info.nullable
460 assert argument_conversion_info.arg_conv is not None and "Warning" not in argument_conversion_info.arg_conv
462 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
464 if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
465 if argument_conversion_info.rust_obj in constructor_fns:
467 for explode_arg in constructor_fns[argument_conversion_info.rust_obj].split(','):
468 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
469 if explode_arg_conv.c_ty == "void":
470 # We actually want to handle this case, but for now its only used in NetGraphMsgHandler::new()
471 # which ends up resulting in a redundant constructor - both without arguments for the NetworkGraph.
474 if not argument_conversion_info.arg_name in default_constructor_args:
475 default_constructor_args[argument_conversion_info.arg_name] = []
476 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
477 argument_types.append(argument_conversion_info)
478 if not takes_self and return_type_info.java_hu_ty != struct_meth:
479 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
480 struct_meth_name = method_name
484 out_java.write("\t// " + line)
485 (out_java_delta, out_c_delta, out_java_struct_delta) = \
486 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)
487 out_java.write(out_java_delta)
490 assert len(argument_types) == 1
491 assert return_type_info.c_ty == "void"
492 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")
493 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
494 write_c("\tif ((" + argument_types[0].ty_info.var_name + " & 1) != 0) return;\n")
496 for info in argument_types:
497 if info.arg_conv is not None:
498 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
499 assert c_call_string is None
500 write_c("\t" + method_name + "(")
501 if argument_types[0].arg_conv_name is not None:
502 write_c(argument_types[0].arg_conv_name)
504 for info in argument_types:
505 if info.arg_conv_cleanup is not None:
506 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
511 out_java_struct = None
512 if (expected_struct in opaque_structs or expected_struct in trait_structs
513 or expected_struct in complex_enums or expected_struct in complex_enums
514 or expected_struct in result_types or expected_struct in tuple_types) and not is_free:
515 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
516 out_java_struct.write(out_java_struct_delta)
517 elif (not is_free and not method_name.endswith("_clone") and
518 not method_name.startswith("TxOut") and
519 not method_name.startswith("_") and
520 method_name != "check_platform" and method_name != "Result_read" and
521 not expected_struct in unitary_enums and
522 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
523 or method_name.endswith("_read"))):
524 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
525 for line in out_java_struct_delta.splitlines():
526 if not line.strip().startswith("this."):
527 out_java_struct.write(line + "\n")
529 out_java_struct.write("\t\t// " + line.strip() + "\n")
531 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
532 assert struct_name.startswith("LDK")
533 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
534 unitary_enums.add(struct_name)
535 for idx, (struct_line, _) in enumerate(field_lines):
537 assert(struct_line == "typedef enum %s {" % struct_name)
538 elif idx == len(field_lines) - 3:
539 assert(struct_line.endswith("_Sentinel,"))
540 elif idx == len(field_lines) - 2:
541 assert(struct_line == "} %s;" % struct_name)
542 elif idx == len(field_lines) - 1:
543 assert(struct_line == "")
544 assert struct_name.startswith("LDK")
545 (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)
547 out_java_enum.write(native_file_out)
548 out_java.write(native_out)
550 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
551 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
554 tag_field_lines = union_enum_items["field_lines"]
555 contains_trait = False
556 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
558 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
559 elif idx == len(tag_field_lines) - 3:
560 assert(struct_line.endswith("_Sentinel,"))
561 elif idx == len(tag_field_lines) - 2:
562 assert(struct_line == "} %s_Tag;" % struct_name)
563 elif idx == len(tag_field_lines) - 1:
564 assert(struct_line == "")
566 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
568 if "LDK" + variant_name in union_enum_items:
569 enum_var_lines = union_enum_items["LDK" + variant_name]
570 for idx, (field, field_docs) in enumerate(enum_var_lines):
571 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
572 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
573 contains_trait |= field_ty.contains_trait
574 if field_docs is not None and doc_to_field_nullable(field_docs):
575 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
577 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
578 fields.append((field_conv, field_docs))
579 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
580 elif camel_to_snake(variant_name) in inline_enum_variants:
581 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
582 # docs through to there, and then potentially mark the field nullable.
583 mapped = type_mapping_generator.map_type(inline_enum_variants[camel_to_snake(variant_name)] + " " + camel_to_snake(variant_name), False, None, False, True)
584 contains_trait |= mapped.ty_info.contains_trait
585 fields.append((mapped, None))
586 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
588 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
589 complex_enums[struct_name] = contains_trait
591 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
592 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
594 out_java_enum.write(out_java_enum_addendum)
595 out_java.write(out_java_addendum)
596 write_c(out_c_addendum)
598 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
599 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
601 flattened_field_var_convs = []
602 for var_line in field_var_lines:
603 if var_line.group(1) in trait_structs:
604 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
605 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
606 flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
608 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
609 field_var_convs.append(mapped)
610 flattened_field_var_convs.append(mapped)
611 trait_structs[struct_name] = field_var_convs
614 for fn_docs, fn_line in trait_fn_lines:
615 if fn_line == "cloned":
616 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
617 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
619 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
621 assert False # This isn't yet handled on the Java side
622 ret_ty_info.nullable = True
623 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
625 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
626 is_const = fn_line.group(4) is not None
629 for idx, arg in enumerate(fn_line.group(5).split(',')):
632 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
633 if arg_ty_info.var_name in nullable_params:
634 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
635 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
637 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
638 arg_tys.append(arg_conv_info)
639 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
641 (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)
642 write_c(out_c_addendum)
643 out_java_trait.write(out_java_trait_addendum)
644 out_java.write(out_java_addendum)
646 for fn_docs, fn_line in trait_fn_lines:
647 if fn_line == "cloned":
649 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
650 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
651 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
652 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"
653 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)
654 for idx, var_line in enumerate(field_var_lines):
655 if var_line.group(1) not in trait_structs:
656 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
657 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
658 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
659 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
661 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"
662 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)
664 def map_result(struct_name, res_ty, err_ty):
665 result_types.add(struct_name)
666 human_ty = struct_name.replace("LDKCResult", "Result")
667 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
668 out_java_struct.write(consts.hu_struct_file_prefix)
669 out_java_struct.write("public class " + human_ty + " extends CommonBase {\n")
670 out_java_struct.write("\tprivate " + human_ty + "(Object _dummy, long ptr) { super(ptr); }\n")
671 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
672 out_java_struct.write("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); } super.finalize();\n")
673 out_java_struct.write("\t}\n\n")
674 out_java_struct.write("\tstatic " + human_ty + " constr_from_ptr(long ptr) {\n")
675 out_java_struct.write("\t\tif (bindings." + struct_name.replace("LDK", "") + "_is_ok(ptr)) {\n")
676 out_java_struct.write("\t\t\treturn new " + human_ty + "_OK(null, ptr);\n")
677 out_java_struct.write("\t\t} else {\n")
678 out_java_struct.write("\t\t\treturn new " + human_ty + "_Err(null, ptr);\n")
679 out_java_struct.write("\t\t}\n")
680 out_java_struct.write("\t}\n")
682 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
683 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
685 if not res_map.is_native_primitive and (res_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
687 if not err_map.is_native_primitive and (err_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
690 out_java.write("\tpublic static native " + res_map.java_ty + " " + struct_name + "_get_ok(long arg);\n")
691 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")
692 write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
693 write_c("\tCHECK(val->result_ok);\n\t")
694 out_java_struct.write("\tpublic static final class " + human_ty + "_OK extends " + human_ty + " {\n")
695 if res_map.ret_conv is not None:
696 write_c(res_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.result)")
697 write_c(res_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + res_map.ret_conv_name)
699 write_c("return *val->contents.result")
702 if res_map.java_hu_ty != "void":
703 out_java_struct.write("\t\tpublic final " + res_map.java_hu_ty + " res;\n")
704 out_java_struct.write("\t\tprivate " + human_ty + "_OK(Object _dummy, long ptr) {\n")
705 out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
706 if res_map.java_hu_ty == "void":
708 elif res_map.to_hu_conv is not None:
709 out_java_struct.write("\t\t\t" + res_map.java_ty + " res = bindings." + struct_name + "_get_ok(ptr);\n")
710 out_java_struct.write("\t\t\t" + res_map.to_hu_conv.replace("\n", "\n\t\t\t"))
711 out_java_struct.write("\n\t\t\tthis.res = " + res_map.to_hu_conv_name + ";\n")
713 out_java_struct.write("\t\t\tthis.res = bindings." + struct_name + "_get_ok(ptr);\n")
714 out_java_struct.write("\t\t}\n")
715 out_java_struct.write("\t}\n\n")
717 out_java.write("\tpublic static native " + err_map.java_ty + " " + struct_name + "_get_err(long arg);\n")
718 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")
719 write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
720 write_c("\tCHECK(!val->result_ok);\n\t")
721 out_java_struct.write("\tpublic static final class " + human_ty + "_Err extends " + human_ty + " {\n")
722 if err_map.ret_conv is not None:
723 write_c(err_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.err)")
724 write_c(err_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + err_map.ret_conv_name)
726 write_c("return *val->contents.err")
729 if err_map.java_hu_ty != "void":
730 out_java_struct.write("\t\tpublic final " + err_map.java_hu_ty + " err;\n")
731 out_java_struct.write("\t\tprivate " + human_ty + "_Err(Object _dummy, long ptr) {\n")
732 out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
733 if err_map.java_hu_ty == "void":
735 elif err_map.to_hu_conv is not None:
736 out_java_struct.write("\t\t\t" + err_map.java_ty + " err = bindings." + struct_name + "_get_err(ptr);\n")
737 out_java_struct.write("\t\t\t" + err_map.to_hu_conv.replace("\n", "\n\t\t\t"))
738 out_java_struct.write("\n\t\t\tthis.err = " + err_map.to_hu_conv_name + ";\n")
740 out_java_struct.write("\t\t\tthis.err = bindings." + struct_name + "_get_err(ptr);\n")
741 out_java_struct.write("\t\t}\n")
743 out_java_struct.write("\t}\n\n")
745 def map_tuple(struct_name, field_lines):
746 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
747 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
748 out_java_struct.write(consts.map_tuple(struct_name))
750 for idx, (line, _) in enumerate(field_lines):
751 if idx != 0 and idx < len(field_lines) - 2:
752 ty_list.append(java_c_types(line.strip(';'), None))
753 tuple_types[struct_name] = (ty_list, struct_name)
755 # Map virtual getter functions
756 for idx, (line, _) in enumerate(field_lines):
757 if idx != 0 and idx < len(field_lines) - 2:
758 field_name = chr(ord('a') + idx - 1)
759 assert line.endswith(" " + field_name + ";")
760 field_ty = java_c_types(line[:-1], None)
761 ptr_fn_defn = line[:-3].strip() + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR tuple)"
762 owned_fn_defn = line[:-3].strip() + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR tuple)"
765 if field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
766 fn_defn = owned_fn_defn
767 write_c("static inline " + fn_defn + "{\n")
768 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&tuple->" + field_name + ");\n")
769 elif field_ty.arr_len is not None or field_ty.is_native_primitive:
770 fn_defn = owned_fn_defn
771 write_c("static inline " + fn_defn + "{\n")
772 write_c("\treturn tuple->" + field_name + ";\n")
774 fn_defn = ptr_fn_defn
775 write_c("static inline " + fn_defn + "{\n")
776 write_c("\treturn &tuple->" + field_name + ";\n")
779 dummy_line = fn_defn + ";\n"
780 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
782 out_java.write(consts.bindings_header)
783 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
784 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
786 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
787 out_java_struct.write(consts.common_base)
790 last_block_comment = None
793 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
795 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
796 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
797 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
798 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
799 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
800 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
801 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
802 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
803 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
804 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
805 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
806 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
807 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
808 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
809 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
811 union_enum_items = {}
812 result_ptr_struct_items = {}
814 if block_comment is not None:
815 if line.endswith("*/\n"):
816 last_block_comment = block_comment.strip("\n")
819 block_comment = block_comment + line.strip(" /*")
820 elif cur_block_obj is not None:
821 cur_block_obj = cur_block_obj + line
822 if line.startswith("} "):
826 obj_lines = cur_block_obj.split("\n")
828 result_contents = None
829 is_unitary_enum = False
830 is_union_enum = False
835 last_struct_block_comment = None
837 for idx, struct_line in enumerate(obj_lines):
838 if struct_line.strip().startswith("/*"):
839 block_comment = struct_line.strip(" /*")
840 if block_comment is not None:
841 if struct_line.endswith("*/"):
842 last_struct_block_comment = block_comment.strip("\n")
845 block_comment = block_comment + "\n" + struct_line.strip(" /*")
847 struct_name_match = struct_name_regex.match(struct_line)
848 if struct_name_match is not None:
849 struct_name = struct_name_match.group(3)
850 if struct_name_match.group(1) == "enum":
851 if not struct_name.endswith("_Tag"):
852 is_unitary_enum = True
855 elif struct_name_match.group(1) == "union":
857 if line_indicates_opaque_regex.match(struct_line):
859 result_match = line_indicates_result_regex.match(struct_line)
860 if result_match is not None:
861 result_contents = result_match.group(1)
862 vec_ty_match = line_indicates_vec_regex.match(struct_line)
863 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
864 vec_ty = vec_ty_match.group(2)
865 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
867 trait_fn_match = line_indicates_trait_regex.match(struct_line)
868 if trait_fn_match is not None:
869 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
870 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
871 if trait_clone_fn_match is not None:
872 trait_fn_lines.append((last_struct_block_comment, "cloned"))
873 field_var_match = line_field_var_regex.match(struct_line)
874 if field_var_match is not None:
875 field_var_lines.append(field_var_match)
876 field_lines.append((struct_line, last_struct_block_comment))
877 last_struct_block_comment = None
879 assert(struct_name is not None)
880 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))
881 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))
882 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))
883 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))
884 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))
885 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))
886 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))
889 opaque_structs.add(struct_name)
890 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
891 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
892 last_block_comment = None
893 out_java_struct.write(out_opaque_struct_human)
894 elif result_contents is not None:
895 assert result_contents in result_ptr_struct_items
896 res_ty, err_ty = result_ptr_struct_items[result_contents]
897 map_result(struct_name, res_ty, err_ty)
898 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
899 for line, _ in field_lines:
900 if line.endswith("*result;"):
901 res_ty = line[:-8].strip()
902 elif line.endswith("*err;"):
903 err_ty = line[:-5].strip()
904 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
905 result_types.add(struct_name[:-3])
907 map_tuple(struct_name, field_lines)
908 elif vec_ty is not None:
909 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
910 if len(ty_info.java_fn_ty_arg) == 1: # ie we're a primitive of some form
911 out_java.write("\tpublic static native long " + struct_name + "_new(" + ty_info.java_ty + "[] elems);\n")
912 write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_new", True) + ty_info.c_ty + "Array elems) {\n")
913 write_c("\t" + struct_name + " *ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n")
914 write_c("\tret->datalen = " + consts.get_native_arr_len_call[0] + "elems" + consts.get_native_arr_len_call[1] + ";\n")
915 write_c("\tif (ret->datalen == 0) {\n")
916 write_c("\t\tret->data = NULL;\n")
917 write_c("\t} else {\n")
918 write_c("\t\tret->data = MALLOC(sizeof(" + vec_ty + ") * ret->datalen, \"" + struct_name + " Data\");\n")
919 native_arr_ptr_call = consts.get_native_arr_ptr_call(ty_info.ty_info)
920 write_c("\t\t" + ty_info.c_ty + " *java_elems = " + native_arr_ptr_call[0] + "elems" + native_arr_ptr_call[1] + ";\n")
921 write_c("\t\tfor (size_t i = 0; i < ret->datalen; i++) {\n")
922 if ty_info.arg_conv is not None:
923 write_c("\t\t\t" + ty_info.c_ty + " arr_elem = java_elems[i];\n")
924 write_c("\t\t\t" + ty_info.arg_conv.replace("\n", "\n\t\t\t") + "\n")
925 write_c("\t\t\tret->data[i] = " + ty_info.arg_conv_name + ";\n")
926 assert ty_info.arg_conv_cleanup is None
928 write_c("\t\t\tret->data[i] = java_elems[i];\n")
930 cleanup = consts.release_native_arr_ptr_call(ty_info.ty_info, "elems", "java_elems")
931 if cleanup is not None:
932 write_c("\t\t" + cleanup + ";\n")
934 write_c("\treturn (uint64_t)ret;\n")
937 if ty_info.is_native_primitive:
938 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
939 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
940 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
941 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
942 write_c("\treturn ret;\n}\n")
943 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
944 ty_name = "CVec_" + ty_info.rust_obj.replace("LDK", "") + "Z";
945 clone_fns.add(ty_name + "_clone")
946 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
947 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
948 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
949 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
950 write_c("\t}\n\treturn ret;\n}\n")
952 assert(struct_name.endswith("_Tag"))
953 struct_name = struct_name[:-4]
954 union_enum_items[struct_name] = {"field_lines": field_lines}
955 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
956 enum_var_name = struct_name.split("_")
957 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
958 elif struct_name in union_enum_items:
961 for line, _ in field_lines:
962 if line == " struct {":
966 elif elem_items > -1:
968 if line.startswith("struct "):
970 elif line.startswith("enum "):
972 split = line.split(" ")
973 assert len(split) == 2
974 tuple_variants[split[1].strip(";")] = split[0]
977 # We don't currently support tuple variant with more than one element
979 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
980 last_block_comment = None
981 elif is_unitary_enum:
982 map_unitary_enum(struct_name, field_lines, last_block_comment)
983 last_block_comment = None
984 elif len(trait_fn_lines) > 0:
985 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
986 elif struct_name == "LDKTxOut":
987 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
988 out_java_struct.write(consts.hu_struct_file_prefix)
989 out_java_struct.write("public class TxOut extends CommonBase{\n")
990 out_java_struct.write("\t/** The script_pubkey in this output */\n")
991 out_java_struct.write("\tpublic final byte[] script_pubkey;\n")
992 out_java_struct.write("\t/** The value, in satoshis, of this output */\n")
993 out_java_struct.write("\tpublic final long value;\n")
994 out_java_struct.write("\n")
995 out_java_struct.write("\tTxOut(java.lang.Object _dummy, long ptr) {\n")
996 out_java_struct.write("\t\tsuper(ptr);\n")
997 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
998 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
999 out_java_struct.write("\t}\n")
1000 out_java_struct.write("\tpublic TxOut(long value, byte[] script_pubkey) {\n")
1001 out_java_struct.write("\t\tsuper(bindings.TxOut_new(script_pubkey, value));\n")
1002 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
1003 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
1004 out_java_struct.write("\t}\n")
1005 out_java_struct.write("\n")
1006 out_java_struct.write("\t@Override @SuppressWarnings(\"deprecation\")\n")
1007 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
1008 out_java_struct.write("\t\tsuper.finalize();\n")
1009 out_java_struct.write("\t\tif (ptr != 0) { bindings.TxOut_free(ptr); }\n")
1010 out_java_struct.write("\t}\n")
1011 out_java_struct.write("\n")
1012 out_java_struct.write("}")
1013 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1014 write_c(fn_line + " {")
1015 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1017 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1018 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1019 write_c(fn_line + " {")
1020 write_c("\treturn thing->value;")
1022 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1024 pass # Everything remaining is a byte[] or some form
1025 cur_block_obj = None
1027 fn_ptr = fn_ptr_regex.match(line)
1028 fn_ret_arr = fn_ret_arr_regex.match(line)
1029 reg_fn = reg_fn_regex.match(line)
1030 const_val = const_val_regex.match(line)
1032 if line.startswith("#include <"):
1034 elif line.startswith("/*"):
1035 if not line.endswith("*/\n"):
1036 block_comment = line.strip(" /*")
1037 elif line.startswith("typedef enum "):
1038 cur_block_obj = line
1039 elif line.startswith("typedef struct "):
1040 cur_block_obj = line
1041 elif line.startswith("typedef union "):
1042 cur_block_obj = line
1043 elif fn_ptr is not None:
1044 map_fn(line, fn_ptr, None, None, last_block_comment)
1045 last_block_comment = None
1046 elif fn_ret_arr is not None:
1047 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1048 last_block_comment = None
1049 elif reg_fn is not None:
1050 map_fn(line, reg_fn, None, None, last_block_comment)
1051 last_block_comment = None
1052 elif const_val_regex is not None:
1053 # TODO Map const variables
1056 assert(line == "\n")
1058 out_java.write(consts.bindings_footer)
1059 for struct_name in opaque_structs:
1060 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1061 out_java_struct.write("}\n")
1062 for struct_name in trait_structs:
1063 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1064 out_java_struct.write("}\n")
1065 for struct_name in complex_enums:
1066 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1067 out_java_struct.write("}\n")
1068 for struct_name in result_types:
1069 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1070 out_java_struct.write("}\n")
1071 for struct_name in tuple_types:
1072 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1073 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1074 out_java_struct.write("}\n")
1076 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1077 out_c.write(consts.c_file_pfx)
1078 out_c.write(consts.init_str())
1080 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1081 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1082 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1083 util.write(consts.util_fn_sfx)