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()
307 elif ma.group(1).strip().startswith("LDKC2Tuple"):
308 c_ty = consts.ptr_c_ty
309 java_ty = consts.ptr_native_ty
310 java_hu_ty = "TwoTuple<"
311 if not ma.group(1).strip() in tuple_types:
312 assert java_c_types_none_allowed
314 for idx, ty_info in enumerate(tuple_types[ma.group(1).strip()][0]):
316 java_hu_ty = java_hu_ty + ", "
317 if ty_info.is_native_primitive:
318 if ty_info.java_hu_ty == "int":
319 java_hu_ty = java_hu_ty + "Integer" # Java concrete integer type is Integer, not Int
321 java_hu_ty = java_hu_ty + ty_info.java_hu_ty.title() # If we're a primitive, capitalize the first letter
323 java_hu_ty = java_hu_ty + ty_info.java_hu_ty
324 java_hu_ty = java_hu_ty + ">"
326 fn_arg = ma.group(2).strip()
327 rust_obj = ma.group(1).strip()
329 elif ma.group(1).strip().startswith("LDKC3Tuple"):
330 c_ty = consts.ptr_c_ty
331 java_ty = consts.ptr_native_ty
332 java_hu_ty = "ThreeTuple<"
333 if not ma.group(1).strip() in tuple_types:
334 assert java_c_types_none_allowed
336 for idx, ty_info in enumerate(tuple_types[ma.group(1).strip()][0]):
338 java_hu_ty = java_hu_ty + ", "
339 if ty_info.is_native_primitive:
340 if ty_info.java_hu_ty == "int":
341 java_hu_ty = java_hu_ty + "Integer" # Java concrete integer type is Integer, not Int
343 java_hu_ty = java_hu_ty + ty_info.java_hu_ty.title() # If we're a primitive, capitalize the first letter
345 java_hu_ty = java_hu_ty + ty_info.java_hu_ty
346 java_hu_ty = java_hu_ty + ">"
348 fn_arg = ma.group(2).strip()
349 rust_obj = ma.group(1).strip()
352 c_ty = consts.ptr_c_ty
353 java_ty = consts.ptr_native_ty
354 java_hu_ty = ma.group(1).strip().replace("LDKCOption", "Option").replace("LDKCResult", "Result").replace("LDK", "")
356 fn_arg = ma.group(2).strip()
357 rust_obj = ma.group(1).strip()
360 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
361 fn_arg = fn_arg.replace("*", "").strip()
363 c_ty = consts.ptr_c_ty
364 java_ty = consts.ptr_native_ty
367 var_is_arr = var_is_arr_regex.match(fn_arg)
368 if var_is_arr is not None or ret_arr_len is not None:
369 assert(not take_by_ptr)
371 # is there a special case for plurals?
372 if len(mapped_type) == 2:
373 java_ty = mapped_type[1]
375 java_ty = java_ty + "[]"
376 c_ty = c_ty + "Array"
377 if var_is_arr is not None:
378 if var_is_arr.group(1) == "":
379 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,
380 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg",
381 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False)
382 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,
383 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1),
384 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False)
386 if java_hu_ty is None:
388 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,
389 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)
391 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
392 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
393 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
397 from gen_type_mapping import TypeMappingGenerator
398 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
400 with open(sys.argv[1]) as in_h:
402 reg_fn = reg_fn_regex.match(line)
403 if reg_fn is not None:
404 if reg_fn.group(2).endswith("_clone"):
405 clone_fns.add(reg_fn.group(2))
407 rty = java_c_types(reg_fn.group(1), None)
408 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
409 constructor_fns[rty.rust_obj] = reg_fn.group(3)
411 arr_fn = fn_ret_arr_regex.match(line)
412 if arr_fn is not None:
413 if arr_fn.group(2).endswith("_clone"):
414 clone_fns.add(arr_fn.group(2))
415 # No object constructors return arrays, as then they wouldn't be an object constructor
418 # Define some manual clones...
419 clone_fns.add("ThirtyTwoBytes_clone")
420 write_c("static inline struct LDKThirtyTwoBytes ThirtyTwoBytes_clone(const struct LDKThirtyTwoBytes *orig) { struct LDKThirtyTwoBytes ret; memcpy(ret.data, orig->data, 32); return ret; }\n")
422 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
424 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
425 util.write(consts.util_fn_pfx)
427 with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
428 # Map a top-level function
429 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
430 method_return_type = re_match.group(1)
431 method_name = re_match.group(2)
432 orig_method_name = str(method_name)
433 method_comma_separated_arguments = re_match.group(3)
434 method_arguments = method_comma_separated_arguments.split(',')
436 is_free = method_name.endswith("_free")
437 if method_name.startswith("COption") or method_name.startswith("CResult"):
438 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
440 struct_meth = method_name.split("_")[0]
442 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, False)
444 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
446 return_type_info.nullable = True
449 default_constructor_args = {}
451 takes_self_ptr = False
454 for argument_index, argument in enumerate(method_arguments):
455 argument_conversion_info = type_mapping_generator.map_type(argument, False, None, is_free, True)
456 if argument_index == 0 and argument_conversion_info.java_hu_ty == struct_meth:
458 if argument_conversion_info.ty_info.is_ptr:
459 takes_self_ptr = True
460 elif argument_conversion_info.arg_name in params_nullable:
461 argument_conversion_info.nullable = True
462 if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
463 arg_ty_info = java_c_types(argument, None)
464 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
465 print(" The argument appears to require a move, or not clonable, and is nullable.")
466 print(" Normally for arguments that require a move and are not clonable, we split")
467 print(" the argument into the type's constructor's arguments and just use those to")
468 print(" construct a new object on the fly.")
469 print(" However, because the object is nullable, doing so would mean we can no")
470 print(" longer allow the user to pass null, as we now have an argument list instead.")
471 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
472 print(" It may or may not actually be a reference, but its the simplest mapping option")
473 print(" and also the only use of this code today.")
474 arg_ty_info.requires_clone = False
475 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True)
476 assert argument_conversion_info.arg_conv is not None and "Warning" not in argument_conversion_info.arg_conv
478 if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
479 if argument_conversion_info.rust_obj in constructor_fns:
481 for explode_arg in constructor_fns[argument_conversion_info.rust_obj].split(','):
482 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
483 if explode_arg_conv.c_ty == "void":
484 # We actually want to handle this case, but for now its only used in NetGraphMsgHandler::new()
485 # which ends up resulting in a redundant constructor - both without arguments for the NetworkGraph.
488 if not argument_conversion_info.arg_name in default_constructor_args:
489 default_constructor_args[argument_conversion_info.arg_name] = []
490 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
491 argument_types.append(argument_conversion_info)
492 if not takes_self and return_type_info.java_hu_ty != struct_meth:
493 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
494 method_name = orig_method_name
497 out_java.write("\t// " + line)
498 (out_java_delta, out_c_delta, out_java_struct_delta) = \
499 consts.map_function(argument_types, c_call_string, method_name, return_type_info, struct_meth, default_constructor_args, takes_self, takes_self_ptr, args_known, type_mapping_generator, doc_comment)
500 out_java.write(out_java_delta)
503 assert len(argument_types) == 1
504 assert return_type_info.c_ty == "void"
505 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")
506 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
507 write_c("\tif ((" + argument_types[0].ty_info.var_name + " & 1) != 0) return;\n")
509 for info in argument_types:
510 if info.arg_conv is not None:
511 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
512 assert c_call_string is None
513 write_c("\t" + method_name + "(")
514 if argument_types[0].arg_conv_name is not None:
515 write_c(argument_types[0].arg_conv_name)
517 for info in argument_types:
518 if info.arg_conv_cleanup is not None:
519 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
524 out_java_struct = None
525 expected_struct = "LDK" + struct_meth
526 expected_cstruct = "LDKC" + struct_meth
527 if (expected_struct in opaque_structs or expected_struct in trait_structs
528 or expected_struct in complex_enums or expected_cstruct in complex_enums
529 or expected_cstruct in result_types) and not is_free:
530 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
531 out_java_struct.write(out_java_struct_delta)
532 elif (not is_free and not method_name.endswith("_clone") and
533 not method_name.startswith("TxOut") and
534 not method_name.startswith("_") and
535 method_name != "check_platform" and method_name != "Result_read" and
536 not expected_struct in unitary_enums and
537 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
538 or method_name.endswith("_read"))):
539 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
540 for line in out_java_struct_delta.splitlines():
541 if not line.strip().startswith("this."):
542 out_java_struct.write(line + "\n")
544 out_java_struct.write("\t\t// " + line.strip() + "\n")
546 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
547 assert struct_name.startswith("LDK")
548 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
549 unitary_enums.add(struct_name)
550 for idx, (struct_line, _) in enumerate(field_lines):
552 assert(struct_line == "typedef enum %s {" % struct_name)
553 elif idx == len(field_lines) - 3:
554 assert(struct_line.endswith("_Sentinel,"))
555 elif idx == len(field_lines) - 2:
556 assert(struct_line == "} %s;" % struct_name)
557 elif idx == len(field_lines) - 1:
558 assert(struct_line == "")
559 assert struct_name.startswith("LDK")
560 (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)
562 out_java_enum.write(native_file_out)
563 out_java.write(native_out)
565 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
566 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
567 complex_enums.add(struct_name)
570 tag_field_lines = union_enum_items["field_lines"]
571 for idx, (struct_line, _) in enumerate(tag_field_lines):
573 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
574 elif idx == len(tag_field_lines) - 3:
575 assert(struct_line.endswith("_Sentinel,"))
576 elif idx == len(tag_field_lines) - 2:
577 assert(struct_line == "} %s_Tag;" % struct_name)
578 elif idx == len(tag_field_lines) - 1:
579 assert(struct_line == "")
581 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
583 if "LDK" + variant_name in union_enum_items:
584 enum_var_lines = union_enum_items["LDK" + variant_name]
585 for idx, (field, field_docs) in enumerate(enum_var_lines):
586 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
587 field_ty = type_mapping_generator.map_type(field.strip(' ;'), False, None, False, True)
588 if field_docs is not None and doc_to_field_nullable(field_docs):
589 field_ty.nullable = True
590 fields.append((field_ty, field_docs))
591 enum_variants.append(ComplexEnumVariantInfo(variant_name, fields, False))
592 elif camel_to_snake(variant_name) in inline_enum_variants:
593 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
594 # docs through to there, and then potentially mark the field nullable.
595 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))
596 enum_variants.append(ComplexEnumVariantInfo(variant_name, fields, True))
598 enum_variants.append(ComplexEnumVariantInfo(variant_name, fields, True))
600 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
601 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
603 out_java_enum.write(out_java_enum_addendum)
604 out_java.write(out_java_addendum)
605 write_c(out_c_addendum)
607 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
608 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
610 flattened_field_var_convs = []
611 for var_line in field_var_lines:
612 if var_line.group(1) in trait_structs:
613 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
614 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
615 flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
617 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
618 field_var_convs.append(mapped)
619 flattened_field_var_convs.append(mapped)
620 trait_structs[struct_name] = field_var_convs
623 for fn_docs, fn_line in trait_fn_lines:
624 if fn_line == "cloned":
625 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
626 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
628 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
629 is_const = fn_line.group(4) is not None
630 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
632 assert False # This isn't yet handled on the Java side
633 ret_ty_info.nullable = True
636 for idx, arg in enumerate(fn_line.group(5).split(',')):
639 arg_conv_info = type_mapping_generator.map_type(arg, True, None, False, False)
640 if arg_conv_info.arg_name in nullable_params:
641 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
642 assert arg_conv_info.rust_obj == "LDKPublicKey"
643 arg_conv_info.nullable = True
644 arg_tys.append(arg_conv_info)
645 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
647 (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)
648 write_c(out_c_addendum)
649 out_java_trait.write(out_java_trait_addendum)
650 out_java.write(out_java_addendum)
652 for fn_docs, fn_line in trait_fn_lines:
653 if fn_line == "cloned":
655 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
656 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
657 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
658 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"
659 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)
660 for idx, var_line in enumerate(field_var_lines):
661 if var_line.group(1) not in trait_structs:
662 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
663 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
664 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
665 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
667 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"
668 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)
670 def map_result(struct_name, res_ty, err_ty):
671 result_types.add(struct_name)
672 human_ty = struct_name.replace("LDKCResult", "Result")
673 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
674 out_java_struct.write(consts.hu_struct_file_prefix)
675 out_java_struct.write("public class " + human_ty + " extends CommonBase {\n")
676 out_java_struct.write("\tprivate " + human_ty + "(Object _dummy, long ptr) { super(ptr); }\n")
677 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
678 out_java_struct.write("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); } super.finalize();\n")
679 out_java_struct.write("\t}\n\n")
680 out_java_struct.write("\tstatic " + human_ty + " constr_from_ptr(long ptr) {\n")
681 out_java_struct.write("\t\tif (bindings." + struct_name + "_result_ok(ptr)) {\n")
682 out_java_struct.write("\t\t\treturn new " + human_ty + "_OK(null, ptr);\n")
683 out_java_struct.write("\t\t} else {\n")
684 out_java_struct.write("\t\t\treturn new " + human_ty + "_Err(null, ptr);\n")
685 out_java_struct.write("\t\t}\n")
686 out_java_struct.write("\t}\n")
688 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
689 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
691 if not res_map.is_native_primitive and (res_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
693 if not err_map.is_native_primitive and (err_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
696 out_java.write("\tpublic static native boolean " + struct_name + "_result_ok(long arg);\n")
697 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")
698 write_c("\treturn ((" + struct_name + "*)arg)->result_ok;\n")
701 out_java.write("\tpublic static native " + res_map.java_ty + " " + struct_name + "_get_ok(long arg);\n")
702 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")
703 write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
704 write_c("\tCHECK(val->result_ok);\n\t")
705 out_java_struct.write("\tpublic static final class " + human_ty + "_OK extends " + human_ty + " {\n")
706 if res_map.ret_conv is not None:
707 write_c(res_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.result)")
708 write_c(res_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + res_map.ret_conv_name)
710 write_c("return *val->contents.result")
713 if res_map.java_hu_ty != "void":
714 out_java_struct.write("\t\tpublic final " + res_map.java_hu_ty + " res;\n")
715 out_java_struct.write("\t\tprivate " + human_ty + "_OK(Object _dummy, long ptr) {\n")
716 out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
717 if res_map.java_hu_ty == "void":
719 elif res_map.to_hu_conv is not None:
720 out_java_struct.write("\t\t\t" + res_map.java_ty + " res = bindings." + struct_name + "_get_ok(ptr);\n")
721 out_java_struct.write("\t\t\t" + res_map.to_hu_conv.replace("\n", "\n\t\t\t"))
722 out_java_struct.write("\n\t\t\tthis.res = " + res_map.to_hu_conv_name + ";\n")
724 out_java_struct.write("\t\t\tthis.res = bindings." + struct_name + "_get_ok(ptr);\n")
725 out_java_struct.write("\t\t}\n")
726 out_java_struct.write("\t}\n\n")
728 out_java.write("\tpublic static native " + err_map.java_ty + " " + struct_name + "_get_err(long arg);\n")
729 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")
730 write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
731 write_c("\tCHECK(!val->result_ok);\n\t")
732 out_java_struct.write("\tpublic static final class " + human_ty + "_Err extends " + human_ty + " {\n")
733 if err_map.ret_conv is not None:
734 write_c(err_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.err)")
735 write_c(err_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + err_map.ret_conv_name)
737 write_c("return *val->contents.err")
740 if err_map.java_hu_ty != "void":
741 out_java_struct.write("\t\tpublic final " + err_map.java_hu_ty + " err;\n")
742 out_java_struct.write("\t\tprivate " + human_ty + "_Err(Object _dummy, long ptr) {\n")
743 out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
744 if err_map.java_hu_ty == "void":
746 elif err_map.to_hu_conv is not None:
747 out_java_struct.write("\t\t\t" + err_map.java_ty + " err = bindings." + struct_name + "_get_err(ptr);\n")
748 out_java_struct.write("\t\t\t" + err_map.to_hu_conv.replace("\n", "\n\t\t\t"))
749 out_java_struct.write("\n\t\t\tthis.err = " + err_map.to_hu_conv_name + ";\n")
751 out_java_struct.write("\t\t\tthis.err = bindings." + struct_name + "_get_err(ptr);\n")
752 out_java_struct.write("\t\t}\n")
754 out_java_struct.write("\t}\n\n")
756 def map_tuple(struct_name, field_lines):
757 out_java.write("\tpublic static native long " + struct_name + "_new(")
758 write_c(consts.c_fn_ty_pfx + consts.ptr_c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_new", len(field_lines) > 3))
760 for idx, (line, _) in enumerate(field_lines):
761 if idx != 0 and idx < len(field_lines) - 2:
762 ty_info = java_c_types(line.strip(';'), None)
766 e = chr(ord('a') + idx - 1)
767 out_java.write(ty_info.java_ty + " " + e)
768 write_c(ty_info.c_ty + " " + e)
769 ty_list.append(ty_info)
770 tuple_types[struct_name] = (ty_list, struct_name)
771 out_java.write(");\n")
773 write_c("\t" + struct_name + "* ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n")
774 for idx, (line, _) in enumerate(field_lines):
775 if idx != 0 and idx < len(field_lines) - 2:
776 ty_info = type_mapping_generator.map_type(line.strip(';'), False, None, False, False)
777 e = chr(ord('a') + idx - 1)
778 if ty_info.arg_conv is not None:
779 write_c("\t" + ty_info.arg_conv.replace("\n", "\n\t"))
780 write_c("\n\tret->" + e + " = " + ty_info.arg_conv_name + ";\n")
782 write_c("\tret->" + e + " = " + e + ";\n")
783 if ty_info.arg_conv_cleanup is not None:
784 write_c("\t//TODO: Really need to call " + ty_info.arg_conv_cleanup + " here\n")
785 write_c("\treturn (uint64_t)ret;\n")
788 for idx, ty_info in enumerate(ty_list):
789 e = chr(ord('a') + idx)
790 out_java.write("\tpublic static native " + ty_info.java_ty + " " + struct_name + "_get_" + e + "(long ptr);\n")
791 write_c(consts.c_fn_ty_pfx + ty_info.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_" + e, True) + consts.ptr_c_ty + " ptr) {\n")
792 write_c("\t" + struct_name + " *tuple = (" + struct_name + "*)(ptr & ~1);\n")
793 conv_info = type_mapping_generator.map_type_with_info(ty_info, False, None, False, True)
794 if conv_info.ret_conv is not None:
795 write_c("\t" + conv_info.ret_conv[0].replace("\n", "\n\t") + "tuple->" + e + conv_info.ret_conv[1].replace("\n", "\n\t") + "\n")
796 write_c("\treturn " + conv_info.ret_conv_name + ";\n")
798 write_c("\treturn tuple->" + e + ";\n")
801 out_java.write(consts.bindings_header.replace('<git_version_ldk_garbagecollected>', local_git_version))
803 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
804 out_java_struct.write(consts.common_base)
807 last_block_comment = None
810 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
812 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
813 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
814 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
815 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
816 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
817 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
818 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
819 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
820 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
821 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
822 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
823 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
824 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
825 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
826 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
828 union_enum_items = {}
829 result_ptr_struct_items = {}
831 if block_comment is not None:
832 if line.endswith("*/\n"):
833 last_block_comment = block_comment.strip("\n")
836 block_comment = block_comment + line.strip(" /*")
837 elif cur_block_obj is not None:
838 cur_block_obj = cur_block_obj + line
839 if line.startswith("} "):
843 obj_lines = cur_block_obj.split("\n")
845 result_contents = None
846 is_unitary_enum = False
847 is_union_enum = False
852 last_struct_block_comment = None
854 for idx, struct_line in enumerate(obj_lines):
855 if struct_line.strip().startswith("/*"):
856 block_comment = struct_line.strip(" /*")
857 if block_comment is not None:
858 if struct_line.endswith("*/"):
859 last_struct_block_comment = block_comment.strip("\n")
862 block_comment = block_comment + "\n" + struct_line.strip(" /*")
864 struct_name_match = struct_name_regex.match(struct_line)
865 if struct_name_match is not None:
866 struct_name = struct_name_match.group(3)
867 if struct_name_match.group(1) == "enum":
868 if not struct_name.endswith("_Tag"):
869 is_unitary_enum = True
872 elif struct_name_match.group(1) == "union":
874 if line_indicates_opaque_regex.match(struct_line):
876 result_match = line_indicates_result_regex.match(struct_line)
877 if result_match is not None:
878 result_contents = result_match.group(1)
879 vec_ty_match = line_indicates_vec_regex.match(struct_line)
880 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
881 vec_ty = vec_ty_match.group(2)
882 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
884 trait_fn_match = line_indicates_trait_regex.match(struct_line)
885 if trait_fn_match is not None:
886 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
887 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
888 if trait_clone_fn_match is not None:
889 trait_fn_lines.append((last_struct_block_comment, "cloned"))
890 field_var_match = line_field_var_regex.match(struct_line)
891 if field_var_match is not None:
892 field_var_lines.append(field_var_match)
893 field_lines.append((struct_line, last_struct_block_comment))
894 last_struct_block_comment = None
896 assert(struct_name is not None)
897 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))
898 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))
899 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))
900 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))
901 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))
902 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))
903 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))
906 opaque_structs.add(struct_name)
907 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
908 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
909 last_block_comment = None
910 out_java_struct.write(out_opaque_struct_human)
911 elif result_contents is not None:
912 assert result_contents in result_ptr_struct_items
913 res_ty, err_ty = result_ptr_struct_items[result_contents]
914 map_result(struct_name, res_ty, err_ty)
915 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
916 for line, _ in field_lines:
917 if line.endswith("*result;"):
918 res_ty = line[:-8].strip()
919 elif line.endswith("*err;"):
920 err_ty = line[:-5].strip()
921 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
922 result_types.add(struct_name[:-3])
924 map_tuple(struct_name, field_lines)
925 elif vec_ty is not None:
926 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
927 if len(ty_info.java_fn_ty_arg) == 1: # ie we're a primitive of some form
928 out_java.write("\tpublic static native long " + struct_name + "_new(" + ty_info.java_ty + "[] elems);\n")
929 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")
930 write_c("\t" + struct_name + " *ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n")
931 write_c("\tret->datalen = " + consts.get_native_arr_len_call[0] + "elems" + consts.get_native_arr_len_call[1] + ";\n")
932 write_c("\tif (ret->datalen == 0) {\n")
933 write_c("\t\tret->data = NULL;\n")
934 write_c("\t} else {\n")
935 write_c("\t\tret->data = MALLOC(sizeof(" + vec_ty + ") * ret->datalen, \"" + struct_name + " Data\");\n")
936 native_arr_ptr_call = consts.get_native_arr_ptr_call(ty_info.ty_info)
937 write_c("\t\t" + ty_info.c_ty + " *java_elems = " + native_arr_ptr_call[0] + "elems" + native_arr_ptr_call[1] + ";\n")
938 write_c("\t\tfor (size_t i = 0; i < ret->datalen; i++) {\n")
939 if ty_info.arg_conv is not None:
940 write_c("\t\t\t" + ty_info.c_ty + " arr_elem = java_elems[i];\n")
941 write_c("\t\t\t" + ty_info.arg_conv.replace("\n", "\n\t\t\t") + "\n")
942 write_c("\t\t\tret->data[i] = " + ty_info.arg_conv_name + ";\n")
943 assert ty_info.arg_conv_cleanup is None
945 write_c("\t\t\tret->data[i] = java_elems[i];\n")
947 cleanup = consts.release_native_arr_ptr_call(ty_info.ty_info, "elems", "java_elems")
948 if cleanup is not None:
949 write_c("\t\t" + cleanup + ";\n")
951 write_c("\treturn (uint64_t)ret;\n")
954 if ty_info.is_native_primitive:
955 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
956 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
957 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
958 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
959 write_c("\treturn ret;\n}\n")
960 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
961 ty_name = "CVec_" + ty_info.rust_obj.replace("LDK", "") + "Z";
962 clone_fns.add(ty_name + "_clone")
963 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
964 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
965 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
966 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
967 write_c("\t}\n\treturn ret;\n}\n")
969 assert(struct_name.endswith("_Tag"))
970 struct_name = struct_name[:-4]
971 union_enum_items[struct_name] = {"field_lines": field_lines}
972 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
973 enum_var_name = struct_name.split("_")
974 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
975 elif struct_name in union_enum_items:
978 for line, _ in field_lines:
979 if line == " struct {":
983 elif elem_items > -1:
985 if line.startswith("struct "):
987 elif line.startswith("enum "):
989 split = line.split(" ")
990 assert len(split) == 2
991 tuple_variants[split[1].strip(";")] = split[0]
994 # We don't currently support tuple variant with more than one element
996 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
997 last_block_comment = None
998 elif is_unitary_enum:
999 map_unitary_enum(struct_name, field_lines, last_block_comment)
1000 last_block_comment = None
1001 elif len(trait_fn_lines) > 0:
1002 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1003 elif struct_name == "LDKTxOut":
1004 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1005 out_java_struct.write(consts.hu_struct_file_prefix)
1006 out_java_struct.write("public class TxOut extends CommonBase{\n")
1007 out_java_struct.write("\t/** The script_pubkey in this output */\n")
1008 out_java_struct.write("\tpublic final byte[] script_pubkey;\n")
1009 out_java_struct.write("\t/** The value, in satoshis, of this output */\n")
1010 out_java_struct.write("\tpublic final long value;\n")
1011 out_java_struct.write("\n")
1012 out_java_struct.write("\tTxOut(java.lang.Object _dummy, long ptr) {\n")
1013 out_java_struct.write("\t\tsuper(ptr);\n")
1014 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
1015 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
1016 out_java_struct.write("\t}\n")
1017 out_java_struct.write("\tpublic TxOut(long value, byte[] script_pubkey) {\n")
1018 out_java_struct.write("\t\tsuper(bindings.TxOut_new(script_pubkey, value));\n")
1019 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
1020 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
1021 out_java_struct.write("\t}\n")
1022 out_java_struct.write("\n")
1023 out_java_struct.write("\t@Override @SuppressWarnings(\"deprecation\")\n")
1024 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
1025 out_java_struct.write("\t\tsuper.finalize();\n")
1026 out_java_struct.write("\t\tif (ptr != 0) { bindings.TxOut_free(ptr); }\n")
1027 out_java_struct.write("\t}\n")
1028 out_java_struct.write("\n")
1029 out_java_struct.write("}")
1030 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1031 write_c(fn_line + " {")
1032 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1034 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1035 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1036 write_c(fn_line + " {")
1037 write_c("\treturn thing->value;")
1039 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1041 pass # Everything remaining is a byte[] or some form
1042 cur_block_obj = None
1044 fn_ptr = fn_ptr_regex.match(line)
1045 fn_ret_arr = fn_ret_arr_regex.match(line)
1046 reg_fn = reg_fn_regex.match(line)
1047 const_val = const_val_regex.match(line)
1049 if line.startswith("#include <"):
1051 elif line.startswith("/*"):
1052 if not line.endswith("*/\n"):
1053 block_comment = line.strip(" /*")
1054 elif line.startswith("typedef enum "):
1055 cur_block_obj = line
1056 elif line.startswith("typedef struct "):
1057 cur_block_obj = line
1058 elif line.startswith("typedef union "):
1059 cur_block_obj = line
1060 elif fn_ptr is not None:
1061 map_fn(line, fn_ptr, None, None, last_block_comment)
1062 last_block_comment = None
1063 elif fn_ret_arr is not None:
1064 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1065 last_block_comment = None
1066 elif reg_fn is not None:
1067 map_fn(line, reg_fn, None, None, last_block_comment)
1068 last_block_comment = None
1069 elif const_val_regex is not None:
1070 # TODO Map const variables
1073 assert(line == "\n")
1075 out_java.write(consts.bindings_footer)
1076 for struct_name in opaque_structs:
1077 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1078 out_java_struct.write("}\n")
1079 for struct_name in trait_structs:
1080 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1081 out_java_struct.write("}\n")
1082 for struct_name in complex_enums:
1083 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1084 out_java_struct.write("}\n")
1085 for struct_name in result_types:
1086 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1087 out_java_struct.write("}\n")
1089 with open(sys.argv[4], "w") as out_c:
1090 out_c.write(consts.c_file_pfx.replace('<git_version_ldk_garbagecollected>', local_git_version))
1091 out_c.write(consts.init_str())
1093 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1094 util.write(consts.util_fn_sfx)