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(f"{sys.argv[2]}/bindings{consts.file_ext}", "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)
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(" /*")
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 len(ty_info.java_fn_ty_arg) == 1: # ie we're a primitive of some form
930 out_java.write("\tpublic static native long " + struct_name + "_new(" + ty_info.java_ty + "[] elems);\n")
931 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")
932 write_c("\t" + struct_name + " *ret = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n")
933 write_c("\tret->datalen = " + consts.get_native_arr_len_call[0] + "elems" + consts.get_native_arr_len_call[1] + ";\n")
934 write_c("\tif (ret->datalen == 0) {\n")
935 write_c("\t\tret->data = NULL;\n")
936 write_c("\t} else {\n")
937 write_c("\t\tret->data = MALLOC(sizeof(" + vec_ty + ") * ret->datalen, \"" + struct_name + " Data\");\n")
938 native_arr_ptr_call = consts.get_native_arr_ptr_call(ty_info.ty_info)
939 write_c("\t\t" + ty_info.c_ty + " *java_elems = " + native_arr_ptr_call[0] + "elems" + native_arr_ptr_call[1] + ";\n")
940 write_c("\t\tfor (size_t i = 0; i < ret->datalen; i++) {\n")
941 if ty_info.arg_conv is not None:
942 write_c("\t\t\t" + ty_info.c_ty + " arr_elem = java_elems[i];\n")
943 write_c("\t\t\t" + ty_info.arg_conv.replace("\n", "\n\t\t\t") + "\n")
944 write_c("\t\t\tret->data[i] = " + ty_info.arg_conv_name + ";\n")
945 assert ty_info.arg_conv_cleanup is None
947 write_c("\t\t\tret->data[i] = java_elems[i];\n")
949 cleanup = consts.release_native_arr_ptr_call(ty_info.ty_info, "elems", "java_elems")
950 if cleanup is not None:
951 write_c("\t\t" + cleanup + ";\n")
953 write_c("\treturn (uint64_t)ret;\n")
956 if ty_info.is_native_primitive:
957 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
958 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
959 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
960 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
961 write_c("\treturn ret;\n}\n")
962 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
963 ty_name = "CVec_" + ty_info.rust_obj.replace("LDK", "") + "Z";
964 clone_fns.add(ty_name + "_clone")
965 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
966 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
967 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
968 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
969 write_c("\t}\n\treturn ret;\n}\n")
971 assert(struct_name.endswith("_Tag"))
972 struct_name = struct_name[:-4]
973 union_enum_items[struct_name] = {"field_lines": field_lines}
974 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
975 enum_var_name = struct_name.split("_")
976 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
977 elif struct_name in union_enum_items:
980 for line, _ in field_lines:
981 if line == " struct {":
985 elif elem_items > -1:
987 if line.startswith("struct "):
989 elif line.startswith("enum "):
991 split = line.split(" ")
992 assert len(split) == 2
993 tuple_variants[split[1].strip(";")] = split[0]
996 # We don't currently support tuple variant with more than one element
998 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
999 last_block_comment = None
1000 elif is_unitary_enum:
1001 map_unitary_enum(struct_name, field_lines, last_block_comment)
1002 last_block_comment = None
1003 elif len(trait_fn_lines) > 0:
1004 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1005 elif struct_name == "LDKTxOut":
1006 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1007 out_java_struct.write(consts.hu_struct_file_prefix)
1008 out_java_struct.write("public class TxOut extends CommonBase{\n")
1009 out_java_struct.write("\t/** The script_pubkey in this output */\n")
1010 out_java_struct.write("\tpublic final byte[] script_pubkey;\n")
1011 out_java_struct.write("\t/** The value, in satoshis, of this output */\n")
1012 out_java_struct.write("\tpublic final long value;\n")
1013 out_java_struct.write("\n")
1014 out_java_struct.write("\tTxOut(java.lang.Object _dummy, long ptr) {\n")
1015 out_java_struct.write("\t\tsuper(ptr);\n")
1016 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
1017 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
1018 out_java_struct.write("\t}\n")
1019 out_java_struct.write("\tpublic TxOut(long value, byte[] script_pubkey) {\n")
1020 out_java_struct.write("\t\tsuper(bindings.TxOut_new(script_pubkey, value));\n")
1021 out_java_struct.write("\t\tthis.script_pubkey = bindings.TxOut_get_script_pubkey(ptr);\n")
1022 out_java_struct.write("\t\tthis.value = bindings.TxOut_get_value(ptr);\n")
1023 out_java_struct.write("\t}\n")
1024 out_java_struct.write("\n")
1025 out_java_struct.write("\t@Override @SuppressWarnings(\"deprecation\")\n")
1026 out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
1027 out_java_struct.write("\t\tsuper.finalize();\n")
1028 out_java_struct.write("\t\tif (ptr != 0) { bindings.TxOut_free(ptr); }\n")
1029 out_java_struct.write("\t}\n")
1030 out_java_struct.write("\n")
1031 out_java_struct.write("}")
1032 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1033 write_c(fn_line + " {")
1034 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1036 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1037 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1038 write_c(fn_line + " {")
1039 write_c("\treturn thing->value;")
1041 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1043 pass # Everything remaining is a byte[] or some form
1044 cur_block_obj = None
1046 fn_ptr = fn_ptr_regex.match(line)
1047 fn_ret_arr = fn_ret_arr_regex.match(line)
1048 reg_fn = reg_fn_regex.match(line)
1049 const_val = const_val_regex.match(line)
1051 if line.startswith("#include <"):
1053 elif line.startswith("/*"):
1054 if not line.endswith("*/\n"):
1055 block_comment = line.strip(" /*")
1056 elif line.startswith("typedef enum "):
1057 cur_block_obj = line
1058 elif line.startswith("typedef struct "):
1059 cur_block_obj = line
1060 elif line.startswith("typedef union "):
1061 cur_block_obj = line
1062 elif fn_ptr is not None:
1063 map_fn(line, fn_ptr, None, None, last_block_comment)
1064 last_block_comment = None
1065 elif fn_ret_arr is not None:
1066 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1067 last_block_comment = None
1068 elif reg_fn is not None:
1069 map_fn(line, reg_fn, None, None, last_block_comment)
1070 last_block_comment = None
1071 elif const_val_regex is not None:
1072 # TODO Map const variables
1075 assert(line == "\n")
1077 out_java.write(consts.bindings_footer)
1078 for struct_name in opaque_structs:
1079 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1080 out_java_struct.write("}\n")
1081 for struct_name in trait_structs:
1082 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1083 out_java_struct.write("}\n")
1084 for struct_name in complex_enums:
1085 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1086 out_java_struct.write("}\n")
1087 for struct_name in result_types:
1088 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1089 out_java_struct.write("}\n")
1091 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1092 out_c.write(consts.c_file_pfx)
1093 out_c.write(consts.init_str())
1095 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1096 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1097 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1098 util.write(consts.util_fn_sfx)