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