2 import os, sys, re, subprocess
5 print("USAGE: /path/to/lightning.h /path/to/bindings/output /path/to/bindings/ /path/to/bindings/output.c debug lang")
8 if sys.argv[5] == "false":
10 elif sys.argv[5] == "true":
13 print("debug should be true or false and indicates whether to track allocations and ensure we don't leak")
17 if sys.argv[6] == "java" or sys.argv[6] == "android":
19 from java_strings import Consts
20 target = java_strings.Target.JAVA
21 if sys.argv[6] == "android":
22 target = java_strings.Target.ANDROID
23 elif sys.argv[6] == "typescript":
24 import typescript_strings
25 from typescript_strings import Consts
26 target = typescript_strings.Target.NODEJS
27 if len(sys.argv) == 8 and sys.argv[7] == 'browser':
28 target = typescript_strings.Target.BROWSER
30 print("Only java or typescript can be set for lang")
34 consts = Consts(DEBUG, target=target, outdir=sys.argv[4])
36 local_git_version = os.getenv("LDK_GARBAGECOLLECTED_GIT_OVERRIDE")
37 if local_git_version is None:
38 local_git_version = subprocess.check_output(["git", "describe", '--tag', '--dirty']).decode("utf-8").strip()
40 from bindingstypes import *
47 def camel_to_snake(s):
48 # Convert camel case to snake case, in a way that appears to match cbindgen
54 if lastchar.isupper():
55 if not char.isupper() and not lastund:
60 ret = ret + lastchar.lower()
63 if char.isupper() and not lastund:
71 return (ret + lastchar.lower()).strip("_")
73 def doc_to_field_nullable(doc):
76 for line in doc.splitlines():
77 if "Note that this (or a relevant inner pointer) may be NULL or all-0s to represent None" in line:
81 def doc_to_params_ret_nullable(doc):
86 for line in doc.splitlines():
87 if "may be NULL or all-0s to represent None" not in line:
89 if "Note that the return value" in line:
91 elif "Note that " in line:
92 param = line.split("Note that ")[1].split(" ")[0]
94 return (params, ret_null)
97 # Map from enum name to "contains trait object"
99 opaque_structs = set()
104 var_is_arr_regex = re.compile("\(\* ?([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
105 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
106 java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
107 def java_c_types(fn_arg, ret_arr_len):
108 fn_arg = fn_arg.strip()
109 if fn_arg.startswith("MUST_USE_RES "):
112 if fn_arg.startswith("const "):
115 if fn_arg.startswith("struct "):
117 if fn_arg.startswith("enum "):
119 nonnull_ptr = "NONNULL_PTR" in fn_arg
120 fn_arg = fn_arg.replace("NONNULL_PTR", "")
127 if fn_arg.startswith("LDKPaymentPreimage") or fn_arg.startswith("LDKPaymentSecret") or fn_arg.startswith("LDKPaymentHash"):
128 if fn_arg.startswith("LDKPaymentPreimage"):
129 fn_arg = "uint8_t (*" + fn_arg[19:] + ")[32]"
130 elif fn_arg.startswith("LDKPaymentSecret"):
131 fn_arg = "uint8_t (*" + fn_arg[17:] + ")[32]"
132 elif fn_arg.startswith("LDKPaymentHash"):
133 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[32]"
134 assert var_is_arr_regex.match(fn_arg[8:])
135 rust_obj = "LDKThirtyTwoBytes"
137 elif fn_arg.startswith("LDKThirtyTwoBytes"):
138 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
139 assert var_is_arr_regex.match(fn_arg[8:])
140 rust_obj = "LDKThirtyTwoBytes"
142 elif fn_arg.startswith("LDKTxid"):
143 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
144 assert var_is_arr_regex.match(fn_arg[8:])
145 rust_obj = "LDKThirtyTwoBytes"
147 elif fn_arg.startswith("LDKPublicKey"):
148 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
149 assert var_is_arr_regex.match(fn_arg[8:])
150 rust_obj = "LDKPublicKey"
151 arr_access = "compressed_form"
152 elif fn_arg.startswith("LDKSecretKey"):
153 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
154 assert var_is_arr_regex.match(fn_arg[8:])
155 rust_obj = "LDKSecretKey"
157 elif fn_arg.startswith("LDKSignature"):
158 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
159 assert var_is_arr_regex.match(fn_arg[8:])
160 rust_obj = "LDKSignature"
161 arr_access = "compact_form"
162 elif fn_arg.startswith("LDKRecoverableSignature"):
163 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
164 assert var_is_arr_regex.match(fn_arg[8:])
165 rust_obj = "LDKRecoverableSignature"
166 arr_access = "serialized_form"
167 elif fn_arg.startswith("LDKThreeBytes"):
168 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
169 assert var_is_arr_regex.match(fn_arg[8:])
170 rust_obj = "LDKThreeBytes"
172 elif fn_arg.startswith("LDKFourBytes"):
173 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
174 assert var_is_arr_regex.match(fn_arg[8:])
175 rust_obj = "LDKFourBytes"
177 elif fn_arg.startswith("LDKSixteenBytes"):
178 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
179 assert var_is_arr_regex.match(fn_arg[8:])
180 rust_obj = "LDKSixteenBytes"
182 elif fn_arg.startswith("LDKTwentyBytes"):
183 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
184 assert var_is_arr_regex.match(fn_arg[8:])
185 rust_obj = "LDKTwentyBytes"
187 elif fn_arg.startswith("LDKTwelveBytes"):
188 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
189 assert var_is_arr_regex.match(fn_arg[8:])
190 rust_obj = "LDKTwelveBytes"
192 elif fn_arg.startswith("LDKu8slice"):
193 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
194 assert var_is_arr_regex.match(fn_arg[8:])
195 rust_obj = "LDKu8slice"
197 elif fn_arg.startswith("LDKCVec_u8Z"):
198 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
199 rust_obj = "LDKCVec_u8Z"
200 assert var_is_arr_regex.match(fn_arg[8:])
202 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
203 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
204 rust_obj = "LDKTransaction"
205 assert var_is_arr_regex.match(fn_arg[8:])
207 elif fn_arg.startswith("LDKCVec_"):
210 fn_arg = fn_arg.replace("*", "")
213 tyn = fn_arg[8:].split(" ")
214 assert tyn[0].endswith("Z")
218 new_arg = "LDK" + tyn[0][:-1]
220 new_arg = new_arg + " " + a
221 res = java_c_types(new_arg, ret_arr_len)
223 assert java_c_types_none_allowed
226 res.pass_by_ref = True
227 java_ty = consts.java_arr_ty_str(res.java_ty)
228 if res.is_native_primitive or res.passed_as_ptr:
229 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
230 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
231 nonnull_ptr=nonnull_ptr, is_const=is_const,
232 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
234 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
235 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
236 nonnull_ptr=nonnull_ptr, is_const=is_const,
237 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
240 contains_trait = False
243 java_type_plural = None
245 if fn_arg.startswith("void"):
249 fn_arg = fn_arg[4:].strip()
251 elif fn_arg.startswith("bool"):
256 fn_arg = fn_arg[4:].strip()
258 elif fn_arg.startswith("uint8_t"):
259 mapped_type = consts.c_type_map['uint8_t']
260 java_ty = mapped_type[0]
264 fn_arg = fn_arg[7:].strip()
266 elif fn_arg.startswith("LDKu5") or fn_arg.startswith("LDKWitnessVersion"):
267 java_ty = consts.c_type_map['uint8_t'][0]
268 if fn_arg.startswith("LDKu5"):
271 fn_arg = fn_arg[6:].strip()
273 java_hu_ty = "WitnessVersion"
274 rust_obj = "LDKWitnessVersion"
275 fn_arg = fn_arg[18:].strip()
279 elif fn_arg.startswith("uint16_t"):
280 mapped_type = consts.c_type_map['uint16_t']
281 java_ty = mapped_type[0]
285 fn_arg = fn_arg[8:].strip()
287 elif fn_arg.startswith("uint32_t"):
288 mapped_type = consts.c_type_map['uint32_t']
289 java_ty = mapped_type[0]
293 fn_arg = fn_arg[8:].strip()
295 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
296 # TODO: uintptr_t is arch-dependent :(
297 mapped_type = consts.c_type_map['uint64_t']
298 java_ty = mapped_type[0]
300 if fn_arg.startswith("uint64_t"):
303 fn_arg = fn_arg[8:].strip()
305 java_ty = consts.usize_native_ty
306 c_ty = consts.usize_c_ty
308 rust_obj = "uintptr_t"
309 fn_arg = fn_arg[9:].strip()
311 elif is_const and fn_arg.startswith("char *"):
312 java_ty = consts.java_type_map["String"]
313 java_hu_ty = consts.java_hu_type_map["String"]
316 fn_ty_arg = "Ljava/lang/String;"
317 fn_arg = fn_arg[6:].strip()
318 elif fn_arg.startswith("LDKStr"):
321 java_ty = consts.java_type_map["String"]
322 java_hu_ty = consts.java_hu_type_map["String"]
324 fn_ty_arg = "Ljava/lang/String;"
325 fn_arg = fn_arg[6:].strip()
328 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
329 java_ty = consts.c_type_map['uint32_t'][0]
330 java_hu_ty = "UnqualifiedError"
331 rust_obj = "LDKError"
335 fn_arg = fn_arg[8:].strip()
337 ma = var_ty_regex.match(fn_arg)
338 arr_ty = ma.group(1).strip()
339 if ma.group(1).strip() in unitary_enums:
340 assert ma.group(1).strip().startswith("LDK")
341 java_ty = ma.group(1).strip()[3:]
343 c_ty = consts.result_c_ty
344 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
345 fn_arg = ma.group(2).strip()
346 rust_obj = ma.group(1).strip()
348 c_ty = consts.ptr_c_ty
349 java_ty = consts.ptr_native_ty
350 java_hu_ty = ma.group(1).strip()
351 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
352 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
353 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
354 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
355 java_hu_ty = java_hu_ty.replace("LDK", "")
357 fn_arg = ma.group(2).strip()
358 rust_obj = ma.group(1).strip()
359 if rust_obj in trait_structs:
360 contains_trait = True
361 elif rust_obj in complex_enums:
362 contains_trait = complex_enums[rust_obj]
365 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
366 fn_arg = fn_arg.replace("*", "").strip()
368 c_ty = consts.ptr_c_ty
369 java_ty = consts.ptr_native_ty
372 var_is_arr = var_is_arr_regex.match(fn_arg)
374 if var_is_arr is not None or ret_arr_len is not None:
375 assert(not take_by_ptr)
377 # is there a special case for plurals?
378 if len(mapped_type) == 3:
379 java_ty = mapped_type[1]
380 java_hu_ty = mapped_type[2]
382 java_ty = java_ty + "[]"
384 c_ty = c_ty + "Array"
386 subty = java_c_types(arr_ty, None)
388 assert java_c_types_none_allowed
391 subty.pass_by_ref = True
393 if var_is_arr is not None:
394 if var_is_arr.group(1) == "":
395 return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
396 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
397 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
398 return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
399 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
400 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
402 if java_hu_ty is None:
404 return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg=fn_ty_arg, c_ty=c_ty, passed_as_ptr=is_ptr or take_by_ptr,
405 is_const=is_const, is_ptr=is_ptr, nonnull_ptr=nonnull_ptr, var_name=fn_arg, arr_len=arr_len, arr_access=arr_access, is_native_primitive=is_primitive,
406 contains_trait=contains_trait, subty=subty)
408 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
409 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
410 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
414 from gen_type_mapping import TypeMappingGenerator
415 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
417 with open(sys.argv[1]) as in_h:
419 reg_fn = reg_fn_regex.match(line)
420 if reg_fn is not None:
421 if reg_fn.group(2).endswith("_clone"):
422 clone_fns.add(reg_fn.group(2))
424 rty = java_c_types(reg_fn.group(1), None)
425 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
426 constructor_fns[rty.rust_obj] = reg_fn.group(3)
428 arr_fn = fn_ret_arr_regex.match(line)
429 if arr_fn is not None:
430 if arr_fn.group(2).endswith("_clone"):
431 clone_fns.add(arr_fn.group(2))
432 # No object constructors return arrays, as then they wouldn't be an object constructor
435 # Define some manual clones...
436 clone_fns.add("ThirtyTwoBytes_clone")
437 write_c("static inline struct LDKThirtyTwoBytes ThirtyTwoBytes_clone(const struct LDKThirtyTwoBytes *orig) { struct LDKThirtyTwoBytes ret; memcpy(ret.data, orig->data, 32); return ret; }\n\n")
440 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
441 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
442 write_c("\tif (sizeof(void*) == 4) {\n")
443 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
444 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
445 write_c("\t} else {\n")
446 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
447 write_c("\t\t// use bit 9 ^ bit 10.\n")
448 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
449 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
450 write_c("#ifdef LDK_DEBUG_BUILD\n")
451 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
452 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
453 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
454 write_c("\t\tp ^= 1ULL << 53;\n")
456 write_c("\t\treturn (void*)p;\n")
460 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
461 write_c("\tif(ptr < 4096) return true;\n")
462 write_c("\tif (sizeof(void*) == 4) {\n")
463 write_c("\t\treturn ptr & (1ULL << 32);\n")
464 write_c("\t} else {\n")
465 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
466 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
467 write_c("#ifdef LDK_DEBUG_BUILD\n")
468 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
469 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
470 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
472 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
476 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
477 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
478 write_c("\tif (sizeof(void*) == 4) {\n")
479 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
480 write_c("\t} else {\n")
481 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
482 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
483 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
484 write_c("#ifdef LDK_DEBUG_BUILD\n")
485 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
486 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
487 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
488 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
489 write_c("\t\tt ^= 1ULL << 53;\n")
491 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
492 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
493 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
494 write_c("\t\treturn t;\n")
498 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
500 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
501 util.write(consts.util_fn_pfx)
503 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
504 # Map a top-level function
505 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
506 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
507 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
508 method_return_type = re_match.group(1)
509 method_name = re_match.group(2)
510 method_comma_separated_arguments = re_match.group(3)
511 method_arguments = method_comma_separated_arguments.split(',')
513 if method_name.startswith("__"):
516 is_free = method_name.endswith("_free")
517 if method_name.startswith("COption") or method_name.startswith("CResult"):
518 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
519 expected_struct = "LDKC" + struct_meth
520 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
521 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
522 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
523 if method_name.startswith("C2Tuple"):
524 struct_meth = "Two" + tuple_name
525 expected_struct = "LDKC2" + tuple_name
527 struct_meth = "Three" + tuple_name
528 expected_struct = "LDKC3" + tuple_name
529 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
531 struct_meth = method_name.split("_")[0]
532 expected_struct = "LDK" + struct_meth
533 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
535 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
537 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
539 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
541 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
542 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
543 write_c("static inline " + meth_line + " {\n")
544 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
545 write_c(method_name + "(arg)")
546 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
547 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
548 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
551 default_constructor_args = {}
553 takes_self_ptr = False
555 for argument_index, argument in enumerate(method_arguments):
556 arg_ty = type_mapping_generator.java_c_types(argument, None)
557 argument_conversion_info = None
558 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
559 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
561 if argument_conversion_info.ty_info.is_ptr:
562 takes_self_ptr = True
563 elif arg_ty.var_name in params_nullable:
564 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
565 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
566 arg_ty_info = java_c_types(argument, None)
567 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
568 print(" The argument appears to require a move, or not clonable, and is nullable.")
569 print(" Normally for arguments that require a move and are not clonable, we split")
570 print(" the argument into the type's constructor's arguments and just use those to")
571 print(" construct a new object on the fly.")
572 print(" However, because the object is nullable, doing so would mean we can no")
573 print(" longer allow the user to pass null, as we now have an argument list instead.")
574 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
575 print(" It may or may not actually be a reference, but its the simplest mapping option")
576 print(" and also the only use of this code today.")
577 arg_ty_info.requires_clone = False
578 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
579 assert argument_conversion_info.nullable
580 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
582 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
584 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
585 if argument_conversion_info.rust_obj in constructor_fns:
587 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
588 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
589 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
590 continue # (void) is C lingo for "no arguments)
591 if explode_arg_conv.c_ty == "void":
593 if not argument_conversion_info.arg_name in default_constructor_args:
594 default_constructor_args[argument_conversion_info.arg_name] = []
595 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
596 argument_types.append(argument_conversion_info)
598 if not takes_self and return_type_info.java_hu_ty != struct_meth:
599 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
600 struct_meth_name = method_name
604 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
605 expected_struct in complex_enums or expected_struct in complex_enums or
606 expected_struct in result_types or expected_struct in tuple_types) and not is_free
607 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
608 not method_name.startswith("TxOut") and not method_name.startswith("BigEndianScalar") and
609 not method_name.startswith("_") and
610 method_name != "check_platform" and method_name != "Result_read" and
611 not expected_struct in unitary_enums and
612 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
613 or method_name.endswith("_read")))
615 # If we're adding a static method, and it returns a primitive or an array of primitives,
616 # and a variable conversion adds a reference on the return type (via `this`), skip the
617 # variable's conversion reference-add (as we obviously cannot need a reference).
618 if impl_on_utils and (return_type_info.is_native_primitive or
619 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
620 for arg in argument_types:
621 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
622 if "this" in arg.from_hu_conv[1]:
623 arg.from_hu_conv = (arg.from_hu_conv[0], "")
625 out_java.write("\t// " + line)
626 args_known = True # We no longer ever set this to false
627 (out_java_delta, out_c_delta, out_java_struct_delta) = \
628 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)
629 out_java.write(out_java_delta)
632 assert len(argument_types) == 1
633 assert return_type_info.c_ty == "void"
634 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")
635 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
636 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
638 for info in argument_types:
639 if info.arg_conv is not None:
640 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
641 assert c_call_string is None
642 write_c("\t" + method_name + "(")
643 if argument_types[0].arg_conv_name is not None:
644 write_c(argument_types[0].arg_conv_name)
646 for info in argument_types:
647 if info.arg_conv_cleanup is not None:
648 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
653 out_java_struct = None
655 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
656 out_java_struct.write(out_java_struct_delta)
658 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
659 for line in out_java_struct_delta.splitlines():
660 out_java_struct.write(line + "\n")
662 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
663 assert struct_name.startswith("LDK")
664 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
665 unitary_enums.add(struct_name)
666 for idx, (struct_line, _) in enumerate(field_lines):
668 assert(struct_line == "typedef enum %s {" % struct_name)
669 elif idx == len(field_lines) - 3:
670 assert(struct_line.endswith("_Sentinel,"))
671 elif idx == len(field_lines) - 2:
672 assert(struct_line == "} %s;" % struct_name)
673 elif idx == len(field_lines) - 1:
674 assert(struct_line == "")
675 assert struct_name.startswith("LDK")
676 (c_out, native_file_out, native_out) = consts.native_c_unitary_enum_map(struct_name[3:], [(x.strip().strip(","), y) for x, y in field_lines[1:-3]], enum_doc_comment)
678 out_java_enum.write(native_file_out)
679 out_java.write(native_out)
681 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
682 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
685 tag_field_lines = union_enum_items["field_lines"]
686 contains_trait = False
687 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
689 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
690 elif idx == len(tag_field_lines) - 3:
691 assert(struct_line.endswith("_Sentinel,"))
692 elif idx == len(tag_field_lines) - 2:
693 assert(struct_line == "} %s_Tag;" % struct_name)
694 elif idx == len(tag_field_lines) - 1:
695 assert(struct_line == "")
697 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
699 if "LDK" + variant_name in union_enum_items:
700 enum_var_lines = union_enum_items["LDK" + variant_name]
701 for idx, (field, field_docs) in enumerate(enum_var_lines):
702 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
703 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
704 contains_trait |= field_ty.contains_trait
705 if field_docs is not None and doc_to_field_nullable(field_docs):
706 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
708 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
709 fields.append((field_conv, field_docs))
710 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
711 elif camel_to_snake(variant_name) in inline_enum_variants:
712 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
713 # docs through to there, and then potentially mark the field nullable.
714 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
715 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
716 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
717 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
718 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
720 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
721 contains_trait |= mapped.ty_info.contains_trait
722 fields.append((mapped, None))
723 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
725 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
726 complex_enums[struct_name] = contains_trait
728 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
729 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
731 out_java_enum.write(out_java_enum_addendum)
732 out_java.write(out_java_addendum)
733 write_c(out_c_addendum)
735 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
736 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
738 flattened_field_var_convs = []
739 for var_line in field_var_lines:
740 if var_line.group(1) in trait_structs:
741 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
742 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
743 flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
745 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
746 field_var_convs.append(mapped)
747 flattened_field_var_convs.append(mapped)
748 trait_structs[struct_name] = field_var_convs
751 for fn_docs, fn_line in trait_fn_lines:
752 if fn_line == "cloned":
753 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
754 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
756 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
758 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
759 ret_ty_info.nullable = True
761 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
762 is_const = fn_line.group(4) is not None
765 for idx, arg in enumerate(fn_line.group(5).split(',')):
768 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
769 if arg_ty_info.var_name in nullable_params:
770 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
771 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
773 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
774 arg_tys.append(arg_conv_info)
775 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
777 (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)
778 write_c(out_c_addendum)
779 out_java_trait.write(out_java_trait_addendum)
780 out_java.write(out_java_addendum)
782 for fn_docs, fn_line in trait_fn_lines:
783 if fn_line == "cloned":
785 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
786 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
787 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
788 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"
789 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)
790 for idx, var_line in enumerate(field_var_lines):
791 if var_line.group(1) not in trait_structs:
792 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
793 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
794 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
795 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
797 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"
798 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)
800 def map_result(struct_name, res_ty, err_ty):
801 result_types.add(struct_name)
802 human_ty = struct_name.replace("LDKCResult", "Result")
803 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
804 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
805 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
806 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
807 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
808 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
809 out_java_struct.write(java_hu_struct)
811 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
812 field_ty = java_c_types(field_decl + " " + field_name, None)
813 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
814 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
817 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
818 fn_defn = owned_fn_defn
819 write_c("static inline " + fn_defn + "{\n")
820 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
821 write_c("\tret.is_owned = false;\n")
822 write_c("\treturn ret;\n")
823 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
824 fn_defn = owned_fn_defn
825 write_c("static inline " + fn_defn + "{\n")
826 if check_sfx is not None:
827 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
828 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
829 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
830 fn_defn = owned_fn_defn
831 write_c("static inline " + fn_defn + "{\n")
832 if check_sfx is not None:
833 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
834 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
837 fn_defn = ptr_fn_defn
838 write_c("static inline " + fn_defn + "{\n")
839 if check_sfx is not None:
840 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
841 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
844 dummy_line = fn_defn + ";\n"
845 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
847 def map_tuple(struct_name, field_lines):
848 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
849 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
850 out_java_struct.write(consts.map_tuple(struct_name))
852 for idx, (line, _) in enumerate(field_lines):
853 if idx != 0 and idx < len(field_lines) - 2:
854 ty_list.append(java_c_types(line.strip(';'), None))
855 tuple_types[struct_name] = (ty_list, struct_name)
857 # Map virtual getter functions
858 for idx, (line, _) in enumerate(field_lines):
859 if idx != 0 and idx < len(field_lines) - 2:
860 field_name = chr(ord('a') + idx - 1)
861 assert line.endswith(" " + field_name + ";")
862 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
864 out_java.write(consts.bindings_header)
865 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
866 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
868 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
869 out_java_struct.write(consts.common_base)
872 last_block_comment = None
875 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
877 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
878 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
879 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
880 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
881 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
882 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
883 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
884 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
885 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
886 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
887 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
888 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
889 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
890 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
891 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
893 union_enum_items = {}
894 result_ptr_struct_items = {}
896 if block_comment is not None:
897 if line.endswith("*/\n"):
898 last_block_comment = block_comment.strip("\n")
901 block_comment = block_comment + line.strip(" /*")
902 elif cur_block_obj is not None:
903 cur_block_obj = cur_block_obj + line
904 if line.startswith("} "):
908 obj_lines = cur_block_obj.split("\n")
910 result_contents = None
911 is_unitary_enum = False
912 is_union_enum = False
917 last_struct_block_comment = None
919 for idx, struct_line in enumerate(obj_lines):
920 if struct_line.strip().startswith("/*"):
921 block_comment = struct_line.strip(" /*")
922 if block_comment is not None:
923 if struct_line.endswith("*/"):
924 last_struct_block_comment = block_comment.strip("\n")
927 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
929 struct_name_match = struct_name_regex.match(struct_line)
930 if struct_name_match is not None:
931 struct_name = struct_name_match.group(3)
932 if struct_name_match.group(1) == "enum":
933 if not struct_name.endswith("_Tag"):
934 is_unitary_enum = True
937 elif struct_name_match.group(1) == "union":
939 if line_indicates_opaque_regex.match(struct_line):
941 result_match = line_indicates_result_regex.match(struct_line)
942 if result_match is not None:
943 result_contents = result_match.group(1)
944 vec_ty_match = line_indicates_vec_regex.match(struct_line)
945 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
946 vec_ty = vec_ty_match.group(2)
947 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
949 trait_fn_match = line_indicates_trait_regex.match(struct_line)
950 if trait_fn_match is not None:
951 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
952 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
953 if trait_clone_fn_match is not None:
954 trait_fn_lines.append((last_struct_block_comment, "cloned"))
955 field_var_match = line_field_var_regex.match(struct_line)
956 if field_var_match is not None:
957 field_var_lines.append(field_var_match)
958 field_lines.append((struct_line, last_struct_block_comment))
959 last_struct_block_comment = None
961 assert(struct_name is not None)
962 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))
963 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))
964 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))
965 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))
966 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))
967 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))
968 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))
971 opaque_structs.add(struct_name)
972 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
973 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
974 last_block_comment = None
975 out_java_struct.write(out_opaque_struct_human)
976 elif result_contents is not None:
977 assert result_contents in result_ptr_struct_items
978 res_ty, err_ty = result_ptr_struct_items[result_contents]
979 map_result(struct_name, res_ty, err_ty)
980 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
981 for line, _ in field_lines:
982 if line.endswith("*result;"):
983 res_ty = line[:-8].strip()
984 elif line.endswith("*err;"):
985 err_ty = line[:-5].strip()
986 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
987 result_types.add(struct_name[:-3])
989 map_tuple(struct_name, field_lines)
990 elif vec_ty is not None:
991 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
992 if ty_info.is_native_primitive:
993 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
994 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
995 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
996 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
997 write_c("\treturn ret;\n}\n")
998 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
999 ty_name = struct_name.replace("LDK", "")
1000 clone_fns.add(ty_name + "_clone")
1001 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1002 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1003 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1004 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1005 write_c("\t}\n\treturn ret;\n}\n")
1007 assert(struct_name.endswith("_Tag"))
1008 struct_name = struct_name[:-4]
1009 union_enum_items[struct_name] = {"field_lines": field_lines}
1010 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1011 enum_var_name = struct_name.split("_")
1012 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1013 elif struct_name in union_enum_items:
1016 for line, field_block_comment in field_lines:
1017 if line == " struct {":
1021 elif elem_items > -1:
1023 if line.startswith("struct "):
1025 elif line.startswith("enum "):
1027 split = line.split(" ")
1028 assert len(split) == 2
1029 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1032 # We don't currently support tuple variant with more than one element
1034 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1035 last_block_comment = None
1036 elif is_unitary_enum:
1037 map_unitary_enum(struct_name, field_lines, last_block_comment)
1038 last_block_comment = None
1039 elif len(trait_fn_lines) > 0:
1040 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1041 elif struct_name == "LDKTxOut":
1042 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1043 out_java_struct.write(consts.hu_struct_file_prefix)
1044 out_java_struct.write(consts.txout_defn)
1045 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1046 write_c(fn_line + " {")
1047 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1049 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1050 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1051 write_c(fn_line + " {")
1052 write_c("\treturn thing->value;")
1054 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1055 elif struct_name == "LDKBigEndianScalar":
1056 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1057 out_java_struct.write(consts.hu_struct_file_prefix)
1058 out_java_struct.write(consts.scalar_defn)
1059 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1060 write_c(fn_line + " {\n")
1061 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1062 write_c("\treturn ret;\n")
1064 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1066 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1067 # there's nothing heap-allocated inside it the C bindings don't bother
1068 # exposing a `_free` method. Instead, we have to manually write one here,
1069 # though it doesn't need to do anything, the autogenerated wrapper will do
1070 # the required FREE.
1071 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1072 write_c(fn_line + " {}\n")
1073 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1075 pass # Everything remaining is a byte[] of some form
1076 cur_block_obj = None
1078 fn_ptr = fn_ptr_regex.match(line)
1079 fn_ret_arr = fn_ret_arr_regex.match(line)
1080 reg_fn = reg_fn_regex.match(line)
1081 const_val = const_val_regex.match(line)
1083 if line.startswith("#include <"):
1085 elif line.startswith("/*"):
1086 if not line.endswith("*/\n"):
1087 block_comment = line.strip(" /*")
1088 elif line.startswith("typedef enum "):
1089 cur_block_obj = line
1090 elif line.startswith("typedef struct "):
1091 cur_block_obj = line
1092 elif line.startswith("typedef union "):
1093 cur_block_obj = line
1094 elif fn_ptr is not None:
1095 map_fn(line, fn_ptr, None, None, last_block_comment)
1096 last_block_comment = None
1097 elif fn_ret_arr is not None:
1098 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1099 last_block_comment = None
1100 elif reg_fn is not None:
1101 map_fn(line, reg_fn, None, None, last_block_comment)
1102 last_block_comment = None
1103 elif const_val_regex is not None:
1104 # TODO Map const variables
1107 assert(line == "\n")
1109 out_java.write(consts.bindings_footer)
1110 for struct_name in opaque_structs:
1111 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1112 out_java_struct.write("}\n")
1113 for struct_name in trait_structs:
1114 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1115 out_java_struct.write("}\n")
1116 for struct_name in complex_enums:
1117 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1118 out_java_struct.write("}\n")
1119 for struct_name in result_types:
1120 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1121 out_java_struct.write("}\n")
1122 for struct_name in tuple_types:
1123 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1124 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1125 out_java_struct.write("}\n")
1127 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1128 out_c.write(consts.c_file_pfx)
1129 out_c.write(consts.init_str())
1131 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1132 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1133 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1134 util.write(consts.util_fn_sfx)