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, outdir=sys.argv[4])
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("LDKPaymentPreimage") or fn_arg.startswith("LDKPaymentSecret") or fn_arg.startswith("LDKPaymentHash"):
128 if fn_arg.startswith("LDKPaymentPreimage"):
129 fn_arg = "uint8_t (*" + fn_arg[19:] + ")[32]"
130 elif fn_arg.startswith("LDKPaymentSecret"):
131 fn_arg = "uint8_t (*" + fn_arg[17:] + ")[32]"
132 elif fn_arg.startswith("LDKPaymentHash"):
133 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[32]"
134 assert var_is_arr_regex.match(fn_arg[8:])
135 rust_obj = "LDKThirtyTwoBytes"
137 elif fn_arg.startswith("LDKThirtyTwoBytes"):
138 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
139 assert var_is_arr_regex.match(fn_arg[8:])
140 rust_obj = "LDKThirtyTwoBytes"
142 elif fn_arg.startswith("LDKTxid"):
143 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
144 assert var_is_arr_regex.match(fn_arg[8:])
145 rust_obj = "LDKThirtyTwoBytes"
147 elif fn_arg.startswith("LDKPublicKey"):
148 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
149 assert var_is_arr_regex.match(fn_arg[8:])
150 rust_obj = "LDKPublicKey"
151 arr_access = "compressed_form"
152 elif fn_arg.startswith("LDKSecretKey"):
153 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
154 assert var_is_arr_regex.match(fn_arg[8:])
155 rust_obj = "LDKSecretKey"
157 elif fn_arg.startswith("LDKSignature"):
158 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
159 assert var_is_arr_regex.match(fn_arg[8:])
160 rust_obj = "LDKSignature"
161 arr_access = "compact_form"
162 elif fn_arg.startswith("LDKRecoverableSignature"):
163 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
164 assert var_is_arr_regex.match(fn_arg[8:])
165 rust_obj = "LDKRecoverableSignature"
166 arr_access = "serialized_form"
167 elif fn_arg.startswith("LDKThreeBytes"):
168 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
169 assert var_is_arr_regex.match(fn_arg[8:])
170 rust_obj = "LDKThreeBytes"
172 elif fn_arg.startswith("LDKFourBytes"):
173 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
174 assert var_is_arr_regex.match(fn_arg[8:])
175 rust_obj = "LDKFourBytes"
177 elif fn_arg.startswith("LDKSixteenBytes"):
178 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
179 assert var_is_arr_regex.match(fn_arg[8:])
180 rust_obj = "LDKSixteenBytes"
182 elif fn_arg.startswith("LDKTwentyBytes"):
183 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
184 assert var_is_arr_regex.match(fn_arg[8:])
185 rust_obj = "LDKTwentyBytes"
187 elif fn_arg.startswith("LDKTwelveBytes"):
188 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
189 assert var_is_arr_regex.match(fn_arg[8:])
190 rust_obj = "LDKTwelveBytes"
192 elif fn_arg.startswith("LDKu8slice"):
193 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
194 assert var_is_arr_regex.match(fn_arg[8:])
195 rust_obj = "LDKu8slice"
197 elif fn_arg.startswith("LDKCVec_u8Z"):
198 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
199 rust_obj = "LDKCVec_u8Z"
200 assert var_is_arr_regex.match(fn_arg[8:])
202 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
203 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
204 rust_obj = "LDKTransaction"
205 assert var_is_arr_regex.match(fn_arg[8:])
207 elif fn_arg.startswith("LDKCVec_"):
210 fn_arg = fn_arg.replace("*", "")
213 tyn = fn_arg[8:].split(" ")
214 assert tyn[0].endswith("Z")
218 new_arg = "LDK" + tyn[0][:-1]
220 new_arg = new_arg + " " + a
221 res = java_c_types(new_arg, ret_arr_len)
223 assert java_c_types_none_allowed
226 res.pass_by_ref = True
227 java_ty = consts.java_arr_ty_str(res.java_ty)
228 if res.is_native_primitive or res.passed_as_ptr:
229 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
230 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
231 nonnull_ptr=nonnull_ptr, is_const=is_const,
232 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
234 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
235 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
236 nonnull_ptr=nonnull_ptr, is_const=is_const,
237 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
240 contains_trait = False
243 java_type_plural = None
245 if fn_arg.startswith("void"):
249 fn_arg = fn_arg[4:].strip()
251 elif fn_arg.startswith("bool"):
256 fn_arg = fn_arg[4:].strip()
258 elif fn_arg.startswith("uint8_t"):
259 mapped_type = consts.c_type_map['uint8_t']
260 java_ty = mapped_type[0]
264 fn_arg = fn_arg[7:].strip()
266 elif fn_arg.startswith("LDKu5") or fn_arg.startswith("LDKWitnessVersion"):
267 java_ty = consts.c_type_map['uint8_t'][0]
268 if fn_arg.startswith("LDKu5"):
271 fn_arg = fn_arg[6:].strip()
273 java_hu_ty = "WitnessVersion"
274 rust_obj = "LDKWitnessVersion"
275 fn_arg = fn_arg[18:].strip()
279 elif fn_arg.startswith("uint16_t"):
280 mapped_type = consts.c_type_map['uint16_t']
281 java_ty = mapped_type[0]
285 fn_arg = fn_arg[8:].strip()
287 elif fn_arg.startswith("uint32_t"):
288 mapped_type = consts.c_type_map['uint32_t']
289 java_ty = mapped_type[0]
293 fn_arg = fn_arg[8:].strip()
295 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
296 # TODO: uintptr_t is arch-dependent :(
297 mapped_type = consts.c_type_map['uint64_t']
298 java_ty = mapped_type[0]
300 if fn_arg.startswith("uint64_t"):
303 fn_arg = fn_arg[8:].strip()
305 java_ty = consts.ptr_native_ty
306 c_ty = consts.ptr_c_ty
308 rust_obj = "uintptr_t"
309 fn_arg = fn_arg[9:].strip()
311 elif is_const and fn_arg.startswith("char *"):
312 java_ty = consts.java_type_map["String"]
313 java_hu_ty = consts.java_hu_type_map["String"]
316 fn_ty_arg = "Ljava/lang/String;"
317 fn_arg = fn_arg[6:].strip()
318 elif fn_arg.startswith("LDKStr"):
321 java_ty = consts.java_type_map["String"]
322 java_hu_ty = consts.java_hu_type_map["String"]
324 fn_ty_arg = "Ljava/lang/String;"
325 fn_arg = fn_arg[6:].strip()
328 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
329 java_ty = consts.c_type_map['uint32_t'][0]
330 java_hu_ty = "UnqualifiedError"
331 rust_obj = "LDKError"
335 fn_arg = fn_arg[8:].strip()
337 ma = var_ty_regex.match(fn_arg)
338 arr_ty = ma.group(1).strip()
339 if ma.group(1).strip() in unitary_enums:
340 assert ma.group(1).strip().startswith("LDK")
341 java_ty = ma.group(1).strip()[3:]
343 c_ty = consts.result_c_ty
344 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
345 fn_arg = ma.group(2).strip()
346 rust_obj = ma.group(1).strip()
348 c_ty = consts.ptr_c_ty
349 java_ty = consts.ptr_native_ty
350 java_hu_ty = ma.group(1).strip()
351 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
352 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
353 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
354 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
355 java_hu_ty = java_hu_ty.replace("LDK", "")
357 fn_arg = ma.group(2).strip()
358 rust_obj = ma.group(1).strip()
359 if rust_obj in trait_structs:
360 contains_trait = True
361 elif rust_obj in complex_enums:
362 contains_trait = complex_enums[rust_obj]
365 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
366 fn_arg = fn_arg.replace("*", "").strip()
368 c_ty = consts.ptr_c_ty
369 java_ty = consts.ptr_native_ty
372 var_is_arr = var_is_arr_regex.match(fn_arg)
374 if var_is_arr is not None or ret_arr_len is not None:
375 assert(not take_by_ptr)
377 # is there a special case for plurals?
378 if len(mapped_type) == 3:
379 java_ty = mapped_type[1]
380 java_hu_ty = mapped_type[2]
382 java_ty = java_ty + "[]"
384 c_ty = c_ty + "Array"
386 subty = java_c_types(arr_ty, None)
388 assert java_c_types_none_allowed
391 subty.pass_by_ref = True
393 if var_is_arr is not None:
394 if var_is_arr.group(1) == "":
395 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, is_const=is_const,
396 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
397 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
398 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, is_const=is_const,
399 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
400 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
402 if java_hu_ty is None:
404 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,
405 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,
406 contains_trait=contains_trait, subty=subty)
408 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
409 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
410 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
414 from gen_type_mapping import TypeMappingGenerator
415 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
417 with open(sys.argv[1]) as in_h:
419 reg_fn = reg_fn_regex.match(line)
420 if reg_fn is not None:
421 if reg_fn.group(2).endswith("_clone"):
422 clone_fns.add(reg_fn.group(2))
424 rty = java_c_types(reg_fn.group(1), None)
425 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
426 constructor_fns[rty.rust_obj] = reg_fn.group(3)
428 arr_fn = fn_ret_arr_regex.match(line)
429 if arr_fn is not None:
430 if arr_fn.group(2).endswith("_clone"):
431 clone_fns.add(arr_fn.group(2))
432 # No object constructors return arrays, as then they wouldn't be an object constructor
435 # Define some manual clones...
436 clone_fns.add("ThirtyTwoBytes_clone")
437 write_c("static inline struct LDKThirtyTwoBytes ThirtyTwoBytes_clone(const struct LDKThirtyTwoBytes *orig) { struct LDKThirtyTwoBytes ret; memcpy(ret.data, orig->data, 32); return ret; }\n")
439 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
441 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
442 util.write(consts.util_fn_pfx)
444 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
445 # Map a top-level function
446 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
447 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
448 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
449 method_return_type = re_match.group(1)
450 method_name = re_match.group(2)
451 method_comma_separated_arguments = re_match.group(3)
452 method_arguments = method_comma_separated_arguments.split(',')
454 if method_name.startswith("__"):
457 is_free = method_name.endswith("_free")
458 if method_name.startswith("COption") or method_name.startswith("CResult"):
459 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
460 expected_struct = "LDKC" + struct_meth
461 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
462 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
463 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
464 if method_name.startswith("C2Tuple"):
465 struct_meth = "Two" + tuple_name
466 expected_struct = "LDKC2" + tuple_name
468 struct_meth = "Three" + tuple_name
469 expected_struct = "LDKC3" + tuple_name
470 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
472 struct_meth = method_name.split("_")[0]
473 expected_struct = "LDK" + struct_meth
474 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
476 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
478 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
480 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
482 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
483 meth_line = "uintptr_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
484 write_c("static inline " + meth_line + " {\n")
485 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
486 write_c(method_name + "(arg)")
487 write_c(return_type_info.ret_conv[1])
488 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
489 map_fn(meth_line + ";\n", re.compile("(uintptr_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
492 default_constructor_args = {}
494 takes_self_ptr = False
497 for argument_index, argument in enumerate(method_arguments):
498 arg_ty = type_mapping_generator.java_c_types(argument, None)
499 argument_conversion_info = None
500 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
501 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
503 if argument_conversion_info.ty_info.is_ptr:
504 takes_self_ptr = True
505 elif arg_ty.var_name in params_nullable:
506 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
507 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
508 arg_ty_info = java_c_types(argument, None)
509 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
510 print(" The argument appears to require a move, or not clonable, and is nullable.")
511 print(" Normally for arguments that require a move and are not clonable, we split")
512 print(" the argument into the type's constructor's arguments and just use those to")
513 print(" construct a new object on the fly.")
514 print(" However, because the object is nullable, doing so would mean we can no")
515 print(" longer allow the user to pass null, as we now have an argument list instead.")
516 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
517 print(" It may or may not actually be a reference, but its the simplest mapping option")
518 print(" and also the only use of this code today.")
519 arg_ty_info.requires_clone = False
520 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
521 assert argument_conversion_info.nullable
522 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
524 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
526 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
527 if argument_conversion_info.rust_obj in constructor_fns:
529 for explode_arg in constructor_fns[argument_conversion_info.rust_obj].split(','):
530 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
531 if explode_arg_conv.c_ty == "void":
532 # We actually want to handle this case, but for now its only used in NetGraphMsgHandler::new()
533 # which ends up resulting in a redundant constructor - both without arguments for the NetworkGraph.
536 if not argument_conversion_info.arg_name in default_constructor_args:
537 default_constructor_args[argument_conversion_info.arg_name] = []
538 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
539 argument_types.append(argument_conversion_info)
541 if not takes_self and return_type_info.java_hu_ty != struct_meth:
542 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
543 struct_meth_name = method_name
547 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
548 expected_struct in complex_enums or expected_struct in complex_enums or
549 expected_struct in result_types or expected_struct in tuple_types) and not is_free
550 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
551 not method_name.startswith("TxOut") and
552 not method_name.startswith("_") and
553 method_name != "check_platform" and method_name != "Result_read" and
554 not expected_struct in unitary_enums and
555 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
556 or method_name.endswith("_read")))
558 # If we're adding a static method, and it returns a primitive or an array of primitives,
559 # and a variable conversion adds a reference on the return type (via `this`), skip the
560 # variable's conversion reference-add (as we obviously cannot need a reference).
561 if impl_on_utils and (return_type_info.is_native_primitive or
562 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
563 for arg in argument_types:
564 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
565 if "this" in arg.from_hu_conv[1]:
566 arg.from_hu_conv = (arg.from_hu_conv[0], "")
568 out_java.write("\t// " + line)
569 (out_java_delta, out_c_delta, out_java_struct_delta) = \
570 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)
571 out_java.write(out_java_delta)
574 assert len(argument_types) == 1
575 assert return_type_info.c_ty == "void"
576 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")
577 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
578 write_c("\tif ((" + argument_types[0].ty_info.var_name + " & 1) != 0) return;\n")
580 for info in argument_types:
581 if info.arg_conv is not None:
582 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
583 assert c_call_string is None
584 write_c("\t" + method_name + "(")
585 if argument_types[0].arg_conv_name is not None:
586 write_c(argument_types[0].arg_conv_name)
588 for info in argument_types:
589 if info.arg_conv_cleanup is not None:
590 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
595 out_java_struct = None
597 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
598 out_java_struct.write(out_java_struct_delta)
600 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
601 for line in out_java_struct_delta.splitlines():
602 out_java_struct.write(line + "\n")
604 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
605 assert struct_name.startswith("LDK")
606 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
607 unitary_enums.add(struct_name)
608 for idx, (struct_line, _) in enumerate(field_lines):
610 assert(struct_line == "typedef enum %s {" % struct_name)
611 elif idx == len(field_lines) - 3:
612 assert(struct_line.endswith("_Sentinel,"))
613 elif idx == len(field_lines) - 2:
614 assert(struct_line == "} %s;" % struct_name)
615 elif idx == len(field_lines) - 1:
616 assert(struct_line == "")
617 assert struct_name.startswith("LDK")
618 (c_out, native_file_out, native_out) = consts.native_c_unitary_enum_map(struct_name[3:], [(x.strip().strip(","), y) for x, y in field_lines[1:-3]], enum_doc_comment)
620 out_java_enum.write(native_file_out)
621 out_java.write(native_out)
623 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
624 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
627 tag_field_lines = union_enum_items["field_lines"]
628 contains_trait = False
629 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
631 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
632 elif idx == len(tag_field_lines) - 3:
633 assert(struct_line.endswith("_Sentinel,"))
634 elif idx == len(tag_field_lines) - 2:
635 assert(struct_line == "} %s_Tag;" % struct_name)
636 elif idx == len(tag_field_lines) - 1:
637 assert(struct_line == "")
639 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
641 if "LDK" + variant_name in union_enum_items:
642 enum_var_lines = union_enum_items["LDK" + variant_name]
643 for idx, (field, field_docs) in enumerate(enum_var_lines):
644 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
645 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
646 contains_trait |= field_ty.contains_trait
647 if field_docs is not None and doc_to_field_nullable(field_docs):
648 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
650 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
651 fields.append((field_conv, field_docs))
652 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
653 elif camel_to_snake(variant_name) in inline_enum_variants:
654 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
655 # docs through to there, and then potentially mark the field nullable.
656 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
657 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
658 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
659 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
660 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
662 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
663 contains_trait |= mapped.ty_info.contains_trait
664 fields.append((mapped, None))
665 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
667 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
668 complex_enums[struct_name] = contains_trait
670 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
671 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
673 out_java_enum.write(out_java_enum_addendum)
674 out_java.write(out_java_addendum)
675 write_c(out_c_addendum)
677 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
678 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
680 flattened_field_var_convs = []
681 for var_line in field_var_lines:
682 if var_line.group(1) in trait_structs:
683 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
684 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
685 flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
687 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
688 field_var_convs.append(mapped)
689 flattened_field_var_convs.append(mapped)
690 trait_structs[struct_name] = field_var_convs
693 for fn_docs, fn_line in trait_fn_lines:
694 if fn_line == "cloned":
695 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
696 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
698 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
700 assert False # This isn't yet handled on the Java side
701 ret_ty_info.nullable = True
702 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
704 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
705 is_const = fn_line.group(4) is not None
708 for idx, arg in enumerate(fn_line.group(5).split(',')):
711 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
712 if arg_ty_info.var_name in nullable_params:
713 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
714 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
716 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
717 arg_tys.append(arg_conv_info)
718 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
720 (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)
721 write_c(out_c_addendum)
722 out_java_trait.write(out_java_trait_addendum)
723 out_java.write(out_java_addendum)
725 for fn_docs, fn_line in trait_fn_lines:
726 if fn_line == "cloned":
728 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
729 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
730 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
731 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"
732 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)
733 for idx, var_line in enumerate(field_var_lines):
734 if var_line.group(1) not in trait_structs:
735 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
736 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
737 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
738 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
740 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"
741 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)
743 def map_result(struct_name, res_ty, err_ty):
744 result_types.add(struct_name)
745 human_ty = struct_name.replace("LDKCResult", "Result")
746 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
747 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
748 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
749 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
750 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
751 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
752 out_java_struct.write(java_hu_struct)
754 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
755 field_ty = java_c_types(field_decl + " " + field_name, None)
756 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
757 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
760 if field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
761 fn_defn = owned_fn_defn
762 write_c("static inline " + fn_defn + "{\n")
763 if check_sfx is not None:
764 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
765 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
766 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
767 fn_defn = owned_fn_defn
768 write_c("static inline " + fn_defn + "{\n")
769 if check_sfx is not None:
770 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
771 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
774 fn_defn = ptr_fn_defn
775 write_c("static inline " + fn_defn + "{\n")
776 if check_sfx is not None:
777 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
778 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\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 def map_tuple(struct_name, field_lines):
785 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
786 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
787 out_java_struct.write(consts.map_tuple(struct_name))
789 for idx, (line, _) in enumerate(field_lines):
790 if idx != 0 and idx < len(field_lines) - 2:
791 ty_list.append(java_c_types(line.strip(';'), None))
792 tuple_types[struct_name] = (ty_list, struct_name)
794 # Map virtual getter functions
795 for idx, (line, _) in enumerate(field_lines):
796 if idx != 0 and idx < len(field_lines) - 2:
797 field_name = chr(ord('a') + idx - 1)
798 assert line.endswith(" " + field_name + ";")
799 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
801 out_java.write(consts.bindings_header)
802 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
803 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
805 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
806 out_java_struct.write(consts.common_base)
809 last_block_comment = None
812 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
814 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
815 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
816 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
817 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
818 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
819 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
820 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
821 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
822 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
823 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
824 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
825 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
826 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
827 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
828 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
830 union_enum_items = {}
831 result_ptr_struct_items = {}
833 if block_comment is not None:
834 if line.endswith("*/\n"):
835 last_block_comment = block_comment.strip("\n")
838 block_comment = block_comment + line.strip(" /*")
839 elif cur_block_obj is not None:
840 cur_block_obj = cur_block_obj + line
841 if line.startswith("} "):
845 obj_lines = cur_block_obj.split("\n")
847 result_contents = None
848 is_unitary_enum = False
849 is_union_enum = False
854 last_struct_block_comment = None
856 for idx, struct_line in enumerate(obj_lines):
857 if struct_line.strip().startswith("/*"):
858 block_comment = struct_line.strip(" /*")
859 if block_comment is not None:
860 if struct_line.endswith("*/"):
861 last_struct_block_comment = block_comment.strip("\n")
864 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
866 struct_name_match = struct_name_regex.match(struct_line)
867 if struct_name_match is not None:
868 struct_name = struct_name_match.group(3)
869 if struct_name_match.group(1) == "enum":
870 if not struct_name.endswith("_Tag"):
871 is_unitary_enum = True
874 elif struct_name_match.group(1) == "union":
876 if line_indicates_opaque_regex.match(struct_line):
878 result_match = line_indicates_result_regex.match(struct_line)
879 if result_match is not None:
880 result_contents = result_match.group(1)
881 vec_ty_match = line_indicates_vec_regex.match(struct_line)
882 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
883 vec_ty = vec_ty_match.group(2)
884 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
886 trait_fn_match = line_indicates_trait_regex.match(struct_line)
887 if trait_fn_match is not None:
888 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
889 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
890 if trait_clone_fn_match is not None:
891 trait_fn_lines.append((last_struct_block_comment, "cloned"))
892 field_var_match = line_field_var_regex.match(struct_line)
893 if field_var_match is not None:
894 field_var_lines.append(field_var_match)
895 field_lines.append((struct_line, last_struct_block_comment))
896 last_struct_block_comment = None
898 assert(struct_name is not None)
899 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))
900 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))
901 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))
902 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))
903 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))
904 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))
905 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))
908 opaque_structs.add(struct_name)
909 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
910 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
911 last_block_comment = None
912 out_java_struct.write(out_opaque_struct_human)
913 elif result_contents is not None:
914 assert result_contents in result_ptr_struct_items
915 res_ty, err_ty = result_ptr_struct_items[result_contents]
916 map_result(struct_name, res_ty, err_ty)
917 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
918 for line, _ in field_lines:
919 if line.endswith("*result;"):
920 res_ty = line[:-8].strip()
921 elif line.endswith("*err;"):
922 err_ty = line[:-5].strip()
923 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
924 result_types.add(struct_name[:-3])
926 map_tuple(struct_name, field_lines)
927 elif vec_ty is not None:
928 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
929 if ty_info.is_native_primitive:
930 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
931 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
932 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
933 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
934 write_c("\treturn ret;\n}\n")
935 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
936 ty_name = struct_name.replace("LDK", "")
937 clone_fns.add(ty_name + "_clone")
938 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
939 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
940 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
941 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
942 write_c("\t}\n\treturn ret;\n}\n")
944 assert(struct_name.endswith("_Tag"))
945 struct_name = struct_name[:-4]
946 union_enum_items[struct_name] = {"field_lines": field_lines}
947 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
948 enum_var_name = struct_name.split("_")
949 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
950 elif struct_name in union_enum_items:
953 for line, field_block_comment in field_lines:
954 if line == " struct {":
958 elif elem_items > -1:
960 if line.startswith("struct "):
962 elif line.startswith("enum "):
964 split = line.split(" ")
965 assert len(split) == 2
966 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
969 # We don't currently support tuple variant with more than one element
971 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
972 last_block_comment = None
973 elif is_unitary_enum:
974 map_unitary_enum(struct_name, field_lines, last_block_comment)
975 last_block_comment = None
976 elif len(trait_fn_lines) > 0:
977 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
978 elif struct_name == "LDKTxOut":
979 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
980 out_java_struct.write(consts.hu_struct_file_prefix)
981 out_java_struct.write(consts.txout_defn)
982 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
983 write_c(fn_line + " {")
984 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
986 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
987 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
988 write_c(fn_line + " {")
989 write_c("\treturn thing->value;")
991 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
993 pass # Everything remaining is a byte[] or some form
996 fn_ptr = fn_ptr_regex.match(line)
997 fn_ret_arr = fn_ret_arr_regex.match(line)
998 reg_fn = reg_fn_regex.match(line)
999 const_val = const_val_regex.match(line)
1001 if line.startswith("#include <"):
1003 elif line.startswith("/*"):
1004 if not line.endswith("*/\n"):
1005 block_comment = line.strip(" /*")
1006 elif line.startswith("typedef enum "):
1007 cur_block_obj = line
1008 elif line.startswith("typedef struct "):
1009 cur_block_obj = line
1010 elif line.startswith("typedef union "):
1011 cur_block_obj = line
1012 elif fn_ptr is not None:
1013 map_fn(line, fn_ptr, None, None, last_block_comment)
1014 last_block_comment = None
1015 elif fn_ret_arr is not None:
1016 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1017 last_block_comment = None
1018 elif reg_fn is not None:
1019 map_fn(line, reg_fn, None, None, last_block_comment)
1020 last_block_comment = None
1021 elif const_val_regex is not None:
1022 # TODO Map const variables
1025 assert(line == "\n")
1027 out_java.write(consts.bindings_footer)
1028 for struct_name in opaque_structs:
1029 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1030 out_java_struct.write("}\n")
1031 for struct_name in trait_structs:
1032 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1033 out_java_struct.write("}\n")
1034 for struct_name in complex_enums:
1035 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1036 out_java_struct.write("}\n")
1037 for struct_name in result_types:
1038 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1039 out_java_struct.write("}\n")
1040 for struct_name in tuple_types:
1041 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1042 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1043 out_java_struct.write("}\n")
1045 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1046 out_c.write(consts.c_file_pfx)
1047 out_c.write(consts.init_str())
1049 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1050 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1051 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1052 util.write(consts.util_fn_sfx)