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