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("LDKU128"):
143 if fn_arg == "LDKU128":
144 fn_arg = "LDKU128 arg"
145 if fn_arg.startswith("LDKU128*") or fn_arg.startswith("LDKU128 *"):
146 fn_arg = "uint8_t (" + fn_arg[8:] + ")[16]"
148 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[16]"
149 assert var_is_arr_regex.match(fn_arg[8:])
151 arr_access = "le_bytes"
152 elif fn_arg.startswith("LDKTxid"):
153 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
154 assert var_is_arr_regex.match(fn_arg[8:])
155 rust_obj = "LDKThirtyTwoBytes"
157 elif fn_arg.startswith("LDKPublicKey"):
158 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
159 assert var_is_arr_regex.match(fn_arg[8:])
160 rust_obj = "LDKPublicKey"
161 arr_access = "compressed_form"
162 elif fn_arg.startswith("LDKSecretKey"):
163 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
164 assert var_is_arr_regex.match(fn_arg[8:])
165 rust_obj = "LDKSecretKey"
167 elif fn_arg.startswith("LDKSignature"):
168 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
169 assert var_is_arr_regex.match(fn_arg[8:])
170 rust_obj = "LDKSignature"
171 arr_access = "compact_form"
172 elif fn_arg.startswith("LDKRecoverableSignature"):
173 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
174 assert var_is_arr_regex.match(fn_arg[8:])
175 rust_obj = "LDKRecoverableSignature"
176 arr_access = "serialized_form"
177 elif fn_arg.startswith("LDKThreeBytes"):
178 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
179 assert var_is_arr_regex.match(fn_arg[8:])
180 rust_obj = "LDKThreeBytes"
182 elif fn_arg.startswith("LDKFourBytes"):
183 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
184 assert var_is_arr_regex.match(fn_arg[8:])
185 rust_obj = "LDKFourBytes"
187 elif fn_arg.startswith("LDKSixteenBytes"):
188 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
189 assert var_is_arr_regex.match(fn_arg[8:])
190 rust_obj = "LDKSixteenBytes"
192 elif fn_arg.startswith("LDKTwentyBytes"):
193 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
194 assert var_is_arr_regex.match(fn_arg[8:])
195 rust_obj = "LDKTwentyBytes"
197 elif fn_arg.startswith("LDKTwelveBytes"):
198 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
199 assert var_is_arr_regex.match(fn_arg[8:])
200 rust_obj = "LDKTwelveBytes"
202 elif fn_arg.startswith("LDKu8slice"):
203 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
204 assert var_is_arr_regex.match(fn_arg[8:])
205 rust_obj = "LDKu8slice"
207 elif fn_arg.startswith("LDKCVec_u8Z"):
208 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
209 rust_obj = "LDKCVec_u8Z"
210 assert var_is_arr_regex.match(fn_arg[8:])
212 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
213 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
214 rust_obj = "LDKTransaction"
215 assert var_is_arr_regex.match(fn_arg[8:])
217 elif fn_arg.startswith("LDKCVec_"):
220 fn_arg = fn_arg.replace("*", "")
223 tyn = fn_arg[8:].split(" ")
224 assert tyn[0].endswith("Z")
228 new_arg = "LDK" + tyn[0][:-1]
230 new_arg = new_arg + " " + a
231 res = java_c_types(new_arg, ret_arr_len)
233 assert java_c_types_none_allowed
236 res.pass_by_ref = True
237 java_ty = consts.java_arr_ty_str(res.java_ty)
238 if res.is_native_primitive or res.passed_as_ptr:
239 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
240 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
241 nonnull_ptr=nonnull_ptr, is_const=is_const,
242 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
244 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
245 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
246 nonnull_ptr=nonnull_ptr, is_const=is_const,
247 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
250 contains_trait = False
253 java_type_plural = None
255 if fn_arg.startswith("void"):
259 fn_arg = fn_arg[4:].strip()
261 elif fn_arg.startswith("bool"):
266 fn_arg = fn_arg[4:].strip()
268 elif fn_arg.startswith("uint8_t"):
269 mapped_type = consts.c_type_map['uint8_t']
270 java_ty = mapped_type[0]
274 fn_arg = fn_arg[7:].strip()
276 elif fn_arg.startswith("LDKu5") or fn_arg.startswith("LDKWitnessVersion"):
277 java_ty = consts.c_type_map['uint8_t'][0]
278 if fn_arg.startswith("LDKu5"):
281 fn_arg = fn_arg[6:].strip()
283 java_hu_ty = "WitnessVersion"
284 rust_obj = "LDKWitnessVersion"
285 fn_arg = fn_arg[18:].strip()
289 elif fn_arg.startswith("uint16_t"):
290 mapped_type = consts.c_type_map['uint16_t']
291 java_ty = mapped_type[0]
295 fn_arg = fn_arg[8:].strip()
297 elif fn_arg.startswith("uint32_t"):
298 mapped_type = consts.c_type_map['uint32_t']
299 java_ty = mapped_type[0]
303 fn_arg = fn_arg[8:].strip()
305 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
306 # TODO: uintptr_t is arch-dependent :(
307 mapped_type = consts.c_type_map['uint64_t']
308 java_ty = mapped_type[0]
310 if fn_arg.startswith("uint64_t"):
313 fn_arg = fn_arg[8:].strip()
315 java_ty = consts.usize_native_ty
316 c_ty = consts.usize_c_ty
318 rust_obj = "uintptr_t"
319 fn_arg = fn_arg[9:].strip()
321 elif is_const and fn_arg.startswith("char *"):
322 java_ty = consts.java_type_map["String"]
323 java_hu_ty = consts.java_hu_type_map["String"]
326 fn_ty_arg = "Ljava/lang/String;"
327 fn_arg = fn_arg[6:].strip()
328 elif fn_arg.startswith("LDKStr"):
331 java_ty = consts.java_type_map["String"]
332 java_hu_ty = consts.java_hu_type_map["String"]
334 fn_ty_arg = "Ljava/lang/String;"
335 fn_arg = fn_arg[6:].strip()
338 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
339 java_ty = consts.c_type_map['uint32_t'][0]
340 java_hu_ty = "UnqualifiedError"
341 rust_obj = "LDKError"
345 fn_arg = fn_arg[8:].strip()
347 ma = var_ty_regex.match(fn_arg)
348 arr_ty = ma.group(1).strip()
349 if ma.group(1).strip() in unitary_enums:
350 assert ma.group(1).strip().startswith("LDK")
351 java_ty = ma.group(1).strip()[3:]
353 c_ty = consts.result_c_ty
354 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
355 fn_arg = ma.group(2).strip()
356 rust_obj = ma.group(1).strip()
358 c_ty = consts.ptr_c_ty
359 java_ty = consts.ptr_native_ty
360 java_hu_ty = ma.group(1).strip()
361 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
362 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
363 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
364 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
365 java_hu_ty = java_hu_ty.replace("LDK", "")
367 fn_arg = ma.group(2).strip()
368 rust_obj = ma.group(1).strip()
369 if rust_obj in trait_structs:
370 contains_trait = True
371 elif rust_obj in complex_enums:
372 contains_trait = complex_enums[rust_obj]
375 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
376 fn_arg = fn_arg.replace("*", "").strip()
378 c_ty = consts.ptr_c_ty
379 java_ty = consts.ptr_native_ty
382 var_is_arr = var_is_arr_regex.match(fn_arg)
384 if var_is_arr is not None or ret_arr_len is not None:
385 assert(not take_by_ptr)
387 # is there a special case for plurals?
388 if len(mapped_type) == 3:
389 java_ty = mapped_type[1]
390 java_hu_ty = mapped_type[2]
392 java_ty = java_ty + "[]"
394 if rust_obj == "LDKU128":
395 java_hu_ty = consts.u128_native_ty
396 c_ty = c_ty + "Array"
398 subty = java_c_types(arr_ty, None)
400 assert java_c_types_none_allowed
403 subty.pass_by_ref = True
405 if var_is_arr is not None:
406 if var_is_arr.group(1) == "":
407 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,
408 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
409 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
410 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,
411 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
412 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
414 if java_hu_ty is None:
416 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,
417 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,
418 contains_trait=contains_trait, subty=subty)
420 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
421 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
422 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
426 from gen_type_mapping import TypeMappingGenerator
427 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
429 with open(sys.argv[1]) as in_h:
431 reg_fn = reg_fn_regex.match(line)
432 if reg_fn is not None:
433 if reg_fn.group(2).endswith("_clone"):
434 clone_fns.add(reg_fn.group(2))
436 rty = java_c_types(reg_fn.group(1), None)
437 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
438 constructor_fns[rty.rust_obj] = reg_fn.group(3)
440 arr_fn = fn_ret_arr_regex.match(line)
441 if arr_fn is not None:
442 if arr_fn.group(2).endswith("_clone"):
443 clone_fns.add(arr_fn.group(2))
444 # No object constructors return arrays, as then they wouldn't be an object constructor
447 # Define some manual clones...
448 clone_fns.add("ThirtyTwoBytes_clone")
449 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")
452 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
453 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
454 write_c("\tif (sizeof(void*) == 4) {\n")
455 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
456 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
457 write_c("\t} else {\n")
458 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
459 write_c("\t\t// use bit 9 ^ bit 10.\n")
460 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
461 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
462 write_c("#ifdef LDK_DEBUG_BUILD\n")
463 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
464 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
465 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
466 write_c("\t\tp ^= 1ULL << 53;\n")
468 write_c("\t\treturn (void*)p;\n")
472 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
473 write_c("\tif(ptr < 4096) return true;\n")
474 write_c("\tif (sizeof(void*) == 4) {\n")
475 write_c("\t\treturn ptr & (1ULL << 32);\n")
476 write_c("\t} else {\n")
477 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
478 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
479 write_c("#ifdef LDK_DEBUG_BUILD\n")
480 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
481 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
482 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
484 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
488 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
489 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
490 write_c("\tif (sizeof(void*) == 4) {\n")
491 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
492 write_c("\t} else {\n")
493 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
494 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
495 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
496 write_c("#ifdef LDK_DEBUG_BUILD\n")
497 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
498 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
499 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
500 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
501 write_c("\t\tt ^= 1ULL << 53;\n")
503 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
504 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
505 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
506 write_c("\t\treturn t;\n")
510 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
512 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
513 util.write(consts.util_fn_pfx)
515 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
516 # Map a top-level function
517 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
518 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
519 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
520 method_return_type = re_match.group(1)
521 method_name = re_match.group(2)
522 method_comma_separated_arguments = re_match.group(3)
523 method_arguments = method_comma_separated_arguments.split(',')
525 if method_name.startswith("__"):
528 is_free = method_name.endswith("_free")
529 if method_name.startswith("COption") or method_name.startswith("CResult"):
530 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
531 expected_struct = "LDKC" + struct_meth
532 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
533 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
534 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
535 if method_name.startswith("C2Tuple"):
536 struct_meth = "Two" + tuple_name
537 expected_struct = "LDKC2" + tuple_name
539 struct_meth = "Three" + tuple_name
540 expected_struct = "LDKC3" + tuple_name
541 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
543 struct_meth = method_name.split("_")[0]
544 expected_struct = "LDK" + struct_meth
545 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
547 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
549 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
551 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
553 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
554 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
555 write_c("static inline " + meth_line + " {\n")
556 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
557 write_c(method_name + "(arg)")
558 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
559 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
560 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
563 default_constructor_args = {}
565 takes_self_ptr = False
567 for argument_index, argument in enumerate(method_arguments):
568 arg_ty = type_mapping_generator.java_c_types(argument, None)
569 argument_conversion_info = None
570 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
571 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
573 if argument_conversion_info.ty_info.is_ptr:
574 takes_self_ptr = True
575 elif arg_ty.var_name in params_nullable:
576 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
577 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
578 arg_ty_info = java_c_types(argument, None)
579 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
580 print(" The argument appears to require a move, or not clonable, and is nullable.")
581 print(" Normally for arguments that require a move and are not clonable, we split")
582 print(" the argument into the type's constructor's arguments and just use those to")
583 print(" construct a new object on the fly.")
584 print(" However, because the object is nullable, doing so would mean we can no")
585 print(" longer allow the user to pass null, as we now have an argument list instead.")
586 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
587 print(" It may or may not actually be a reference, but its the simplest mapping option")
588 print(" and also the only use of this code today.")
589 arg_ty_info.requires_clone = False
590 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
591 assert argument_conversion_info.nullable
592 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
594 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
596 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
597 if argument_conversion_info.rust_obj in constructor_fns:
599 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
600 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
601 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
602 continue # (void) is C lingo for "no arguments)
603 if explode_arg_conv.c_ty == "void":
605 if not argument_conversion_info.arg_name in default_constructor_args:
606 default_constructor_args[argument_conversion_info.arg_name] = []
607 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
608 argument_types.append(argument_conversion_info)
610 if not takes_self and return_type_info.java_hu_ty != struct_meth:
611 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
612 struct_meth_name = method_name
616 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
617 expected_struct in complex_enums or expected_struct in complex_enums or
618 expected_struct in result_types or expected_struct in tuple_types) and not is_free
619 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
620 not method_name.startswith("TxOut") and not method_name.startswith("BigEndianScalar") and
621 not method_name.startswith("_") and
622 method_name != "check_platform" and method_name != "Result_read" and
623 not expected_struct in unitary_enums and
624 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
625 or method_name.endswith("_read")))
627 # If we're adding a static method, and it returns a primitive or an array of primitives,
628 # and a variable conversion adds a reference on the return type (via `this`), skip the
629 # variable's conversion reference-add (as we obviously cannot need a reference).
630 if impl_on_utils and (return_type_info.is_native_primitive or
631 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
632 for arg in argument_types:
633 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
634 if "this" in arg.from_hu_conv[1]:
635 arg.from_hu_conv = (arg.from_hu_conv[0], "")
637 out_java.write("\t// " + line)
638 args_known = True # We no longer ever set this to false
639 (out_java_delta, out_c_delta, out_java_struct_delta) = \
640 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)
641 out_java.write(out_java_delta)
644 assert len(argument_types) == 1
645 assert return_type_info.c_ty == "void"
646 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")
647 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
648 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
650 for info in argument_types:
651 if info.arg_conv is not None:
652 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
653 assert c_call_string is None
654 write_c("\t" + method_name + "(")
655 if argument_types[0].arg_conv_name is not None:
656 write_c(argument_types[0].arg_conv_name)
658 for info in argument_types:
659 if info.arg_conv_cleanup is not None:
660 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
665 out_java_struct = None
667 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
668 out_java_struct.write(out_java_struct_delta)
670 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
671 for line in out_java_struct_delta.splitlines():
672 out_java_struct.write(line + "\n")
674 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
675 assert struct_name.startswith("LDK")
676 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
677 unitary_enums.add(struct_name)
678 for idx, (struct_line, _) in enumerate(field_lines):
680 assert(struct_line == "typedef enum %s {" % struct_name)
681 elif idx == len(field_lines) - 3:
682 assert(struct_line.endswith("_Sentinel,"))
683 elif idx == len(field_lines) - 2:
684 assert(struct_line == "} %s;" % struct_name)
685 elif idx == len(field_lines) - 1:
686 assert(struct_line == "")
687 assert struct_name.startswith("LDK")
688 (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)
690 out_java_enum.write(native_file_out)
691 out_java.write(native_out)
693 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
694 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
697 tag_field_lines = union_enum_items["field_lines"]
698 contains_trait = False
699 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
701 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
702 elif idx == len(tag_field_lines) - 3:
703 assert(struct_line.endswith("_Sentinel,"))
704 elif idx == len(tag_field_lines) - 2:
705 assert(struct_line == "} %s_Tag;" % struct_name)
706 elif idx == len(tag_field_lines) - 1:
707 assert(struct_line == "")
709 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
711 if "LDK" + variant_name in union_enum_items:
712 enum_var_lines = union_enum_items["LDK" + variant_name]
713 for idx, (field, field_docs) in enumerate(enum_var_lines):
714 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
715 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
716 contains_trait |= field_ty.contains_trait
717 if field_docs is not None and doc_to_field_nullable(field_docs):
718 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
720 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
721 fields.append((field_conv, field_docs))
722 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
723 elif camel_to_snake(variant_name) in inline_enum_variants:
724 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
725 # docs through to there, and then potentially mark the field nullable.
726 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
727 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
728 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
729 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
730 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
732 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
733 contains_trait |= mapped.ty_info.contains_trait
734 fields.append((mapped, None))
735 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
737 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
738 complex_enums[struct_name] = contains_trait
740 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
741 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
743 out_java_enum.write(out_java_enum_addendum)
744 out_java.write(out_java_addendum)
745 write_c(out_c_addendum)
747 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
748 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
750 flattened_field_var_convs = []
751 for var_line in field_var_lines:
752 if var_line.group(1) in trait_structs:
753 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
754 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
755 flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
757 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
758 field_var_convs.append(mapped)
759 flattened_field_var_convs.append(mapped)
760 trait_structs[struct_name] = field_var_convs
763 for fn_docs, fn_line in trait_fn_lines:
764 if fn_line == "cloned":
765 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
766 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
768 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
770 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
771 ret_ty_info.nullable = True
773 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
774 is_const = fn_line.group(4) is not None
777 for idx, arg in enumerate(fn_line.group(5).split(',')):
780 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
781 if arg_ty_info.var_name in nullable_params:
782 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
783 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
785 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
786 arg_tys.append(arg_conv_info)
787 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
789 (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)
790 write_c(out_c_addendum)
791 out_java_trait.write(out_java_trait_addendum)
792 out_java.write(out_java_addendum)
794 for fn_docs, fn_line in trait_fn_lines:
795 if fn_line == "cloned":
797 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
798 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
799 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
800 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"
801 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)
802 for idx, var_line in enumerate(field_var_lines):
803 if var_line.group(1) not in trait_structs:
804 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
805 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
806 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
807 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
809 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"
810 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)
812 def map_result(struct_name, res_ty, err_ty):
813 result_types.add(struct_name)
814 human_ty = struct_name.replace("LDKCResult", "Result")
815 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
816 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
817 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
818 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
819 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
820 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
821 out_java_struct.write(java_hu_struct)
823 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
824 field_ty = java_c_types(field_decl + " " + field_name, None)
825 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
826 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
829 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
830 fn_defn = owned_fn_defn
831 write_c("static inline " + fn_defn + "{\n")
832 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
833 write_c("\tret.is_owned = false;\n")
834 write_c("\treturn ret;\n")
835 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
836 fn_defn = owned_fn_defn
837 write_c("static inline " + fn_defn + "{\n")
838 if check_sfx is not None:
839 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
840 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
841 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
842 fn_defn = owned_fn_defn
843 write_c("static inline " + fn_defn + "{\n")
844 if check_sfx is not None:
845 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
846 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
849 fn_defn = ptr_fn_defn
850 write_c("static inline " + fn_defn + "{\n")
851 if check_sfx is not None:
852 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
853 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
856 dummy_line = fn_defn + ";\n"
857 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
859 def map_tuple(struct_name, field_lines):
860 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
861 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
862 out_java_struct.write(consts.map_tuple(struct_name))
864 for idx, (line, _) in enumerate(field_lines):
865 if idx != 0 and idx < len(field_lines) - 2:
866 ty_list.append(java_c_types(line.strip(';'), None))
867 tuple_types[struct_name] = (ty_list, struct_name)
869 # Map virtual getter functions
870 for idx, (line, _) in enumerate(field_lines):
871 if idx != 0 and idx < len(field_lines) - 2:
872 field_name = chr(ord('a') + idx - 1)
873 assert line.endswith(" " + field_name + ";")
874 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
876 out_java.write(consts.bindings_header)
877 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
878 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
880 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
881 out_java_struct.write(consts.common_base)
884 last_block_comment = None
887 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
889 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
890 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
891 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
892 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
893 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
894 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
895 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
896 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
897 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
898 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
899 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
900 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
901 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
902 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
903 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
905 union_enum_items = {}
906 result_ptr_struct_items = {}
908 if block_comment is not None:
909 if line.endswith("*/\n"):
910 last_block_comment = block_comment.strip("\n")
913 block_comment = block_comment + line.strip(" /*")
914 elif cur_block_obj is not None:
915 cur_block_obj = cur_block_obj + line
916 if line.startswith("} "):
920 obj_lines = cur_block_obj.split("\n")
922 result_contents = None
923 is_unitary_enum = False
924 is_union_enum = False
929 last_struct_block_comment = None
931 for idx, struct_line in enumerate(obj_lines):
932 if struct_line.strip().startswith("/*"):
933 block_comment = struct_line.strip(" /*")
934 if block_comment is not None:
935 if struct_line.endswith("*/"):
936 last_struct_block_comment = block_comment.strip("\n")
939 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
941 struct_name_match = struct_name_regex.match(struct_line)
942 if struct_name_match is not None:
943 struct_name = struct_name_match.group(3)
944 if struct_name_match.group(1) == "enum":
945 if not struct_name.endswith("_Tag"):
946 is_unitary_enum = True
949 elif struct_name_match.group(1) == "union":
951 if line_indicates_opaque_regex.match(struct_line):
953 result_match = line_indicates_result_regex.match(struct_line)
954 if result_match is not None:
955 result_contents = result_match.group(1)
956 vec_ty_match = line_indicates_vec_regex.match(struct_line)
957 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
958 vec_ty = vec_ty_match.group(2)
959 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
961 trait_fn_match = line_indicates_trait_regex.match(struct_line)
962 if trait_fn_match is not None:
963 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
964 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
965 if trait_clone_fn_match is not None:
966 trait_fn_lines.append((last_struct_block_comment, "cloned"))
967 field_var_match = line_field_var_regex.match(struct_line)
968 if field_var_match is not None:
969 field_var_lines.append(field_var_match)
970 field_lines.append((struct_line, last_struct_block_comment))
971 last_struct_block_comment = None
973 assert(struct_name is not None)
974 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))
975 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))
976 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))
977 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))
978 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))
979 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))
980 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))
983 opaque_structs.add(struct_name)
984 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
985 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
986 last_block_comment = None
987 out_java_struct.write(out_opaque_struct_human)
988 elif result_contents is not None:
989 assert result_contents in result_ptr_struct_items
990 res_ty, err_ty = result_ptr_struct_items[result_contents]
991 map_result(struct_name, res_ty, err_ty)
992 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
993 for line, _ in field_lines:
994 if line.endswith("*result;"):
995 res_ty = line[:-8].strip()
996 elif line.endswith("*err;"):
997 err_ty = line[:-5].strip()
998 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
999 result_types.add(struct_name[:-3])
1001 map_tuple(struct_name, field_lines)
1002 elif vec_ty is not None:
1003 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1004 if ty_info.is_native_primitive:
1005 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1006 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1007 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1008 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1009 write_c("\treturn ret;\n}\n")
1010 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1011 ty_name = struct_name.replace("LDK", "")
1012 clone_fns.add(ty_name + "_clone")
1013 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1014 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1015 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1016 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1017 write_c("\t}\n\treturn ret;\n}\n")
1019 assert(struct_name.endswith("_Tag"))
1020 struct_name = struct_name[:-4]
1021 union_enum_items[struct_name] = {"field_lines": field_lines}
1022 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1023 enum_var_name = struct_name.split("_")
1024 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1025 elif struct_name in union_enum_items:
1028 for line, field_block_comment in field_lines:
1029 if line == " struct {":
1033 elif elem_items > -1:
1035 if line.startswith("struct "):
1037 elif line.startswith("enum "):
1039 split = line.split(" ")
1040 assert len(split) == 2
1041 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1044 # We don't currently support tuple variant with more than one element
1046 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1047 last_block_comment = None
1048 elif is_unitary_enum:
1049 map_unitary_enum(struct_name, field_lines, last_block_comment)
1050 last_block_comment = None
1051 elif len(trait_fn_lines) > 0:
1052 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1053 elif struct_name == "LDKTxOut":
1054 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1055 out_java_struct.write(consts.hu_struct_file_prefix)
1056 out_java_struct.write(consts.txout_defn)
1057 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1058 write_c(fn_line + " {")
1059 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1061 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1062 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1063 write_c(fn_line + " {")
1064 write_c("\treturn thing->value;")
1066 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1067 elif struct_name == "LDKBigEndianScalar":
1068 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1069 out_java_struct.write(consts.hu_struct_file_prefix)
1070 out_java_struct.write(consts.scalar_defn)
1071 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1072 write_c(fn_line + " {\n")
1073 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1074 write_c("\treturn ret;\n")
1076 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1078 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1079 # there's nothing heap-allocated inside it the C bindings don't bother
1080 # exposing a `_free` method. Instead, we have to manually write one here,
1081 # though it doesn't need to do anything, the autogenerated wrapper will do
1082 # the required FREE.
1083 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1084 write_c(fn_line + " {}\n")
1085 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1087 pass # Everything remaining is a byte[] of some form
1088 cur_block_obj = None
1090 fn_ptr = fn_ptr_regex.match(line)
1091 fn_ret_arr = fn_ret_arr_regex.match(line)
1092 reg_fn = reg_fn_regex.match(line)
1093 const_val = const_val_regex.match(line)
1095 if line.startswith("#include <"):
1097 elif line.startswith("/*"):
1098 if not line.endswith("*/\n"):
1099 block_comment = line.strip(" /*")
1100 elif line.startswith("typedef enum "):
1101 cur_block_obj = line
1102 elif line.startswith("typedef struct "):
1103 cur_block_obj = line
1104 elif line.startswith("typedef union "):
1105 cur_block_obj = line
1106 elif fn_ptr is not None:
1107 map_fn(line, fn_ptr, None, None, last_block_comment)
1108 last_block_comment = None
1109 elif fn_ret_arr is not None:
1110 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1111 last_block_comment = None
1112 elif reg_fn is not None:
1113 map_fn(line, reg_fn, None, None, last_block_comment)
1114 last_block_comment = None
1115 elif const_val_regex is not None:
1116 # TODO Map const variables
1119 assert(line == "\n")
1121 out_java.write(consts.bindings_footer)
1122 for struct_name in opaque_structs:
1123 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1124 out_java_struct.write("}\n")
1125 for struct_name in trait_structs:
1126 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1127 out_java_struct.write("}\n")
1128 for struct_name in complex_enums:
1129 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1130 out_java_struct.write("}\n")
1131 for struct_name in result_types:
1132 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1133 out_java_struct.write("}\n")
1134 for struct_name in tuple_types:
1135 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1136 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1137 out_java_struct.write("}\n")
1139 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1140 out_c.write(consts.c_file_pfx)
1141 out_c.write(consts.init_str())
1143 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1144 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1145 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1146 util.write(consts.util_fn_sfx)