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