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 target-tuple")
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 if "apple" in sys.argv[8]:
24 target = java_strings.Target.MACOS
25 elif sys.argv[6] == "typescript":
26 import typescript_strings
27 from typescript_strings import Consts
28 target = typescript_strings.Target.NODEJS
29 if len(sys.argv) == 8 and sys.argv[7] == 'browser':
30 target = typescript_strings.Target.BROWSER
31 elif sys.argv[6] == "c_sharp":
33 from csharp_strings import Consts
34 target = csharp_strings.Target.CSHARP
35 elif sys.argv[6] == "python":
37 from python_strings import Consts
38 target = python_strings.Target.PYTHON
40 print("Only java, typescript, python, or c_sharp can be set for lang")
43 consts = Consts(DEBUG, target=target, outdir=sys.argv[4])
45 local_git_version = os.getenv("LDK_GARBAGECOLLECTED_GIT_OVERRIDE")
46 if local_git_version is None:
47 local_git_version = subprocess.check_output(["git", "describe", '--tag', '--dirty']).decode("utf-8").strip()
49 from bindingstypes import *
56 def camel_to_snake(s):
57 # Convert camel case to snake case, in a way that appears to match cbindgen
63 if lastchar.isupper():
64 if not char.isupper() and not lastund:
69 ret = ret + lastchar.lower()
72 if char.isupper() and not lastund:
80 return (ret + lastchar.lower()).strip("_")
82 def doc_to_field_nullable(doc):
85 for line in doc.splitlines():
86 if "Note that this (or a relevant inner pointer) may be NULL or all-0s to represent None" in line:
90 def doc_to_params_ret_nullable(doc):
95 for line in doc.splitlines():
96 if "may be NULL or all-0s to represent None" not in line:
98 if "Note that the return value" in line:
100 elif "Note that " in line:
101 param = line.split("Note that ")[1].split(" ")[0]
103 return (params, ret_null)
105 unitary_enums = set()
106 # Map from enum name to "contains trait object"
108 opaque_structs = set()
113 var_is_arr_regex = re.compile("\(\* ?([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
114 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
115 java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
116 def java_c_types(fn_arg, ret_arr_len):
117 fn_arg = fn_arg.strip()
118 if fn_arg.startswith("MUST_USE_RES "):
121 if fn_arg.startswith("const "):
124 if fn_arg.startswith("struct "):
126 if fn_arg.startswith("enum "):
128 nonnull_ptr = "NONNULL_PTR" in fn_arg
129 fn_arg = fn_arg.replace("NONNULL_PTR", "")
136 if fn_arg.startswith("LDKPaymentPreimage") or fn_arg.startswith("LDKPaymentSecret") or fn_arg.startswith("LDKPaymentHash") or fn_arg.startswith("LDKChainHash"):
137 if fn_arg.startswith("LDKPaymentPreimage"):
138 fn_arg = "uint8_t (*" + fn_arg[19:] + ")[32]"
139 elif fn_arg.startswith("LDKPaymentSecret"):
140 fn_arg = "uint8_t (*" + fn_arg[17:] + ")[32]"
141 elif fn_arg.startswith("LDKPaymentHash"):
142 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[32]"
143 elif fn_arg.startswith("LDKChainHash"):
144 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
145 assert var_is_arr_regex.match(fn_arg[8:])
146 rust_obj = "LDKThirtyTwoBytes"
148 elif fn_arg.startswith("LDKThirtyTwoBytes"):
149 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
150 assert var_is_arr_regex.match(fn_arg[8:])
151 rust_obj = "LDKThirtyTwoBytes"
153 elif fn_arg.startswith("LDKEightU16s"):
154 fn_arg = "uint16_t (*" + fn_arg[13:] + ")[8]"
155 assert var_is_arr_regex.match(fn_arg[9:])
156 rust_obj = "LDKEightU16s"
158 elif fn_arg.startswith("LDKU128"):
159 if fn_arg == "LDKU128":
160 fn_arg = "LDKU128 arg"
161 if fn_arg.startswith("LDKU128*") or fn_arg.startswith("LDKU128 *"):
162 fn_arg = "uint8_t (" + fn_arg[8:] + ")[16]"
164 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[16]"
165 assert var_is_arr_regex.match(fn_arg[8:])
167 arr_access = "le_bytes"
168 elif fn_arg.startswith("LDKTxid"):
169 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
170 assert var_is_arr_regex.match(fn_arg[8:])
171 rust_obj = "LDKThirtyTwoBytes"
173 elif fn_arg.startswith("LDKPublicKey"):
174 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
175 assert var_is_arr_regex.match(fn_arg[8:])
176 rust_obj = "LDKPublicKey"
177 arr_access = "compressed_form"
178 elif fn_arg.startswith("LDKSecretKey"):
179 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
180 assert var_is_arr_regex.match(fn_arg[8:])
181 rust_obj = "LDKSecretKey"
183 elif fn_arg.startswith("LDKSignature"):
184 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
185 assert var_is_arr_regex.match(fn_arg[8:])
186 rust_obj = "LDKSignature"
187 arr_access = "compact_form"
188 elif fn_arg.startswith("LDKRecoverableSignature"):
189 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
190 assert var_is_arr_regex.match(fn_arg[8:])
191 rust_obj = "LDKRecoverableSignature"
192 arr_access = "serialized_form"
193 elif fn_arg.startswith("LDKThreeBytes"):
194 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
195 assert var_is_arr_regex.match(fn_arg[8:])
196 rust_obj = "LDKThreeBytes"
198 elif fn_arg.startswith("LDKFourBytes"):
199 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
200 assert var_is_arr_regex.match(fn_arg[8:])
201 rust_obj = "LDKFourBytes"
203 elif fn_arg.startswith("LDKSixteenBytes"):
204 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
205 assert var_is_arr_regex.match(fn_arg[8:])
206 rust_obj = "LDKSixteenBytes"
208 elif fn_arg.startswith("LDKTwentyBytes"):
209 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
210 assert var_is_arr_regex.match(fn_arg[8:])
211 rust_obj = "LDKTwentyBytes"
213 elif fn_arg.startswith("LDKTwelveBytes"):
214 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
215 assert var_is_arr_regex.match(fn_arg[8:])
216 rust_obj = "LDKTwelveBytes"
218 elif fn_arg.startswith("LDKu8slice"):
219 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
220 assert var_is_arr_regex.match(fn_arg[8:])
221 rust_obj = "LDKu8slice"
223 elif fn_arg.startswith("LDKCVec_u8Z"):
224 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
225 rust_obj = "LDKCVec_u8Z"
226 assert var_is_arr_regex.match(fn_arg[8:])
228 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
229 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
230 rust_obj = "LDKTransaction"
231 assert var_is_arr_regex.match(fn_arg[8:])
233 elif fn_arg.startswith("LDKWitness ") or fn_arg == "LDKWitness":
234 if len(fn_arg) > 12 and fn_arg[11] == "*":
235 fn_arg = "uint8_t (" + fn_arg[11:] + ")[datalen]"
237 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
238 rust_obj = "LDKWitness"
239 assert var_is_arr_regex.match(fn_arg[8:])
241 elif fn_arg.startswith("LDKCVec_"):
244 fn_arg = fn_arg.replace("*", "")
247 tyn = fn_arg[8:].split(" ")
248 assert tyn[0].endswith("Z")
252 new_arg = "LDK" + tyn[0][:-1]
254 new_arg = new_arg + " " + a
255 res = java_c_types(new_arg, ret_arr_len)
257 assert java_c_types_none_allowed
260 res.pass_by_ref = True
261 java_ty = consts.java_arr_ty_str(res.java_ty)
262 if res.is_native_primitive or res.passed_as_ptr:
263 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
264 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
265 nonnull_ptr=nonnull_ptr, is_const=is_const,
266 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
268 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
269 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
270 nonnull_ptr=nonnull_ptr, is_const=is_const,
271 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
274 contains_trait = False
277 java_type_plural = None
279 if fn_arg.startswith("void"):
283 fn_arg = fn_arg[4:].strip()
285 elif fn_arg.startswith("bool"):
286 java_ty = consts.c_type_map['bool'][0]
290 fn_arg = fn_arg[4:].strip()
292 elif fn_arg.startswith("uint8_t"):
293 mapped_type = consts.c_type_map['uint8_t']
294 java_ty = mapped_type[0]
298 fn_arg = fn_arg[7:].strip()
300 elif fn_arg.startswith("LDKU5") or fn_arg.startswith("LDKWitnessVersion"):
301 java_ty = consts.c_type_map['uint8_t'][0]
302 if fn_arg.startswith("LDKU5"):
305 fn_arg = fn_arg[6:].strip()
307 java_hu_ty = "WitnessVersion"
308 rust_obj = "LDKWitnessVersion"
309 fn_arg = fn_arg[18:].strip()
313 elif fn_arg.startswith("uint16_t"):
314 mapped_type = consts.c_type_map['uint16_t']
315 java_ty = mapped_type[0]
319 fn_arg = fn_arg[8:].strip()
321 elif fn_arg.startswith("uint32_t"):
322 mapped_type = consts.c_type_map['uint32_t']
323 java_ty = mapped_type[0]
327 fn_arg = fn_arg[8:].strip()
329 elif fn_arg.startswith("int64_t"):
330 mapped_type = consts.c_type_map['int64_t']
331 java_ty = mapped_type[0]
335 fn_arg = fn_arg[7:].strip()
337 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
338 # TODO: uintptr_t is arch-dependent :(
339 mapped_type = consts.c_type_map['uint64_t']
340 java_ty = mapped_type[0]
342 if fn_arg.startswith("uint64_t"):
345 fn_arg = fn_arg[8:].strip()
347 java_ty = consts.usize_native_ty
348 c_ty = consts.usize_c_ty
350 rust_obj = "uintptr_t"
351 fn_arg = fn_arg[9:].strip()
353 elif is_const and fn_arg.startswith("char *"):
354 java_ty = consts.java_type_map["String"]
355 java_hu_ty = consts.java_hu_type_map["String"]
358 fn_ty_arg = "Ljava/lang/String;"
359 fn_arg = fn_arg[6:].strip()
360 elif fn_arg.startswith("LDKStr") or fn_arg.startswith("LDKAddress"):
363 java_ty = consts.java_type_map["String"]
364 java_hu_ty = consts.java_hu_type_map["String"]
366 fn_ty_arg = "Ljava/lang/String;"
367 if fn_arg.startswith("LDKAddress"):
368 fn_arg = fn_arg[10:].strip()
370 fn_arg = fn_arg[6:].strip()
373 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
374 java_ty = consts.c_type_map['uint32_t'][0]
375 java_hu_ty = "UnqualifiedError"
376 rust_obj = "LDKError"
380 fn_arg = fn_arg[8:].strip()
382 ma = var_ty_regex.match(fn_arg)
383 arr_ty = ma.group(1).strip()
384 if ma.group(1).strip() in unitary_enums:
385 assert ma.group(1).strip().startswith("LDK")
386 java_ty = ma.group(1).strip()[3:]
388 c_ty = consts.result_c_ty
389 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
390 fn_arg = ma.group(2).strip()
391 rust_obj = ma.group(1).strip()
393 c_ty = consts.ptr_c_ty
394 java_ty = consts.ptr_native_ty
395 java_hu_ty = ma.group(1).strip()
396 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
397 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
398 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
399 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
400 java_hu_ty = java_hu_ty.replace("LDK", "")
402 fn_arg = ma.group(2).strip()
403 rust_obj = ma.group(1).strip()
404 if rust_obj in trait_structs:
405 contains_trait = True
406 elif rust_obj in complex_enums:
407 contains_trait = complex_enums[rust_obj]
410 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
411 fn_arg = fn_arg.replace("*", "").strip()
413 c_ty = consts.ptr_c_ty
414 java_ty = consts.ptr_native_ty
417 var_is_arr = var_is_arr_regex.match(fn_arg)
419 if var_is_arr is not None or ret_arr_len is not None:
420 assert(not take_by_ptr)
422 # is there a special case for plurals?
423 if len(mapped_type) == 3:
424 java_ty = mapped_type[1]
425 java_hu_ty = mapped_type[2]
427 java_ty = java_ty + "[]"
429 if rust_obj == "LDKU128":
430 java_hu_ty = consts.u128_native_ty
431 c_ty = c_ty + "Array"
433 subty = java_c_types(arr_ty, None)
435 assert java_c_types_none_allowed
438 subty.pass_by_ref = True
440 if var_is_arr is not None:
441 if var_is_arr.group(1) == "":
442 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,
443 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
444 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
445 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,
446 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
447 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
449 if java_hu_ty is None:
451 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,
452 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,
453 contains_trait=contains_trait, subty=subty)
455 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
456 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
457 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
461 from gen_type_mapping import TypeMappingGenerator
462 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
464 with open(sys.argv[1]) as in_h:
466 reg_fn = reg_fn_regex.match(line)
467 if reg_fn is not None:
468 if reg_fn.group(2).endswith("_clone"):
469 clone_fns.add(reg_fn.group(2))
471 rty = java_c_types(reg_fn.group(1), None)
472 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
473 constructor_fns[rty.rust_obj] = reg_fn.group(3)
475 arr_fn = fn_ret_arr_regex.match(line)
476 if arr_fn is not None:
477 if arr_fn.group(2).endswith("_clone"):
478 clone_fns.add(arr_fn.group(2))
479 # No object constructors return arrays, as then they wouldn't be an object constructor
482 # Define some manual clones...
483 clone_fns.add("ThirtyTwoBytes_clone")
484 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")
487 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
488 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
489 write_c("\tif (sizeof(void*) == 4) {\n")
490 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
491 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
492 write_c("\t} else {\n")
493 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
494 write_c("\t\t// use bit 9 ^ bit 10.\n")
495 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
496 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
497 write_c("#ifdef LDK_DEBUG_BUILD\n")
498 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
499 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
500 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
501 write_c("\t\tp ^= 1ULL << 53;\n")
503 write_c("\t\treturn (void*)p;\n")
507 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
508 write_c("\tif(ptr < 4096) return true;\n")
509 write_c("\tif (sizeof(void*) == 4) {\n")
510 write_c("\t\treturn ptr & (1ULL << 32);\n")
511 write_c("\t} else {\n")
512 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
513 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
514 write_c("#ifdef LDK_DEBUG_BUILD\n")
515 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
516 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
517 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
519 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
523 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
524 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
525 write_c("\tif (sizeof(void*) == 4) {\n")
526 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
527 write_c("\t} else {\n")
528 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
529 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
530 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
531 write_c("#ifdef LDK_DEBUG_BUILD\n")
532 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
533 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
534 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
535 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
536 write_c("\t\tt ^= 1ULL << 53;\n")
538 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
539 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
540 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
541 write_c("\t\treturn t;\n")
545 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
547 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
548 util.write(consts.util_fn_pfx)
550 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
551 # Map a top-level function
552 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
553 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
554 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
555 method_return_type = re_match.group(1)
556 method_name = re_match.group(2)
557 method_comma_separated_arguments = re_match.group(3)
558 method_arguments = method_comma_separated_arguments.split(',')
560 if method_name.startswith("__"):
563 is_free = method_name.endswith("_free")
564 if method_name.startswith("COption") or method_name.startswith("CResult"):
565 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
566 expected_struct = "LDKC" + struct_meth
567 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
568 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
569 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
570 if method_name.startswith("C2Tuple"):
571 struct_meth = "Two" + tuple_name
572 expected_struct = "LDKC2" + tuple_name
574 struct_meth = "Three" + tuple_name
575 expected_struct = "LDKC3" + tuple_name
576 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
578 struct_meth = method_name.split("_")[0]
579 expected_struct = "LDK" + struct_meth
580 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
582 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
584 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
586 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
588 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
589 # LDKWitness is mapped as an array, so no need to implement clone
590 if expected_struct == "LDKWitness":
592 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
593 write_c("static inline " + meth_line + " {\n")
594 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
595 write_c(method_name + "(arg)")
596 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
597 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
598 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
601 default_constructor_args = {}
603 takes_self_ptr = False
605 for argument_index, argument in enumerate(method_arguments):
606 arg_ty = type_mapping_generator.java_c_types(argument, None)
607 argument_conversion_info = None
608 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
609 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
611 if argument_conversion_info.ty_info.is_ptr:
612 takes_self_ptr = True
613 elif arg_ty.var_name in params_nullable:
614 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
615 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
616 arg_ty_info = java_c_types(argument, None)
617 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
618 print(" The argument appears to require a move, or not clonable, and is nullable.")
619 print(" Normally for arguments that require a move and are not clonable, we split")
620 print(" the argument into the type's constructor's arguments and just use those to")
621 print(" construct a new object on the fly.")
622 print(" However, because the object is nullable, doing so would mean we can no")
623 print(" longer allow the user to pass null, as we now have an argument list instead.")
624 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
625 print(" It may or may not actually be a reference, but its the simplest mapping option")
626 print(" and also the only use of this code today.")
627 arg_ty_info.requires_clone = False
628 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
629 assert argument_conversion_info.nullable
630 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
632 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
634 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
635 if argument_conversion_info.rust_obj in constructor_fns:
637 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
638 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
639 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
640 continue # (void) is C lingo for "no arguments)
641 if explode_arg_conv.c_ty == "void":
643 if not argument_conversion_info.arg_name in default_constructor_args:
644 default_constructor_args[argument_conversion_info.arg_name] = []
645 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
646 argument_types.append(argument_conversion_info)
648 if not takes_self and return_type_info.java_hu_ty != struct_meth:
649 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
650 struct_meth_name = method_name
654 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
655 expected_struct in complex_enums or expected_struct in complex_enums or
656 expected_struct in result_types or expected_struct in tuple_types) and not is_free
657 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
658 not method_name.startswith("TxOut") and not method_name.startswith("TxIn") and
659 not method_name.startswith("BigEndianScalar") and not method_name.startswith("_") and
660 method_name != "check_platform" and method_name != "Result_read" and
661 not expected_struct in unitary_enums and
662 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
663 or method_name.endswith("_read")))
665 # If we're adding a static method, and it returns a primitive or an array of primitives,
666 # and a variable conversion adds a reference on the return type (via `this`), skip the
667 # variable's conversion reference-add (as we obviously cannot need a reference).
668 if impl_on_utils and (return_type_info.is_native_primitive or
669 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
670 for arg in argument_types:
671 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
672 if "this" in arg.from_hu_conv[1]:
673 arg.from_hu_conv = (arg.from_hu_conv[0], "")
675 out_java.write("\t// " + line)
676 args_known = True # We no longer ever set this to false
677 (out_java_delta, out_c_delta, out_java_struct_delta) = \
678 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)
679 out_java.write(out_java_delta)
682 assert len(argument_types) == 1
683 assert return_type_info.c_ty == "void"
684 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")
685 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
686 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
688 for info in argument_types:
689 if info.arg_conv is not None:
690 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
691 assert c_call_string is None
692 write_c("\t" + method_name + "(")
693 if argument_types[0].arg_conv_name is not None:
694 write_c(argument_types[0].arg_conv_name)
696 for info in argument_types:
697 if info.arg_conv_cleanup is not None:
698 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
703 out_java_struct = None
705 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
706 out_java_struct.write(out_java_struct_delta)
708 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
709 for line in out_java_struct_delta.splitlines():
710 out_java_struct.write(line + "\n")
712 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
713 assert struct_name.startswith("LDK")
714 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
715 unitary_enums.add(struct_name)
716 for idx, (struct_line, _) in enumerate(field_lines):
718 assert(struct_line == "typedef enum %s {" % struct_name)
719 elif idx == len(field_lines) - 3:
720 assert(struct_line.endswith("_Sentinel,"))
721 elif idx == len(field_lines) - 2:
722 assert(struct_line == "} %s;" % struct_name)
723 elif idx == len(field_lines) - 1:
724 assert(struct_line == "")
725 assert struct_name.startswith("LDK")
726 (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)
728 out_java_enum.write(native_file_out)
729 out_java.write(native_out)
731 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
732 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
735 tag_field_lines = union_enum_items["field_lines"]
736 contains_trait = False
737 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
739 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
740 elif idx == len(tag_field_lines) - 3:
741 assert(struct_line.endswith("_Sentinel,"))
742 elif idx == len(tag_field_lines) - 2:
743 assert(struct_line == "} %s_Tag;" % struct_name)
744 elif idx == len(tag_field_lines) - 1:
745 assert(struct_line == "")
747 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
749 if "LDK" + variant_name in union_enum_items:
750 enum_var_lines = union_enum_items["LDK" + variant_name]
751 for idx, (field, field_docs) in enumerate(enum_var_lines):
752 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
753 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
754 contains_trait |= field_ty.contains_trait
755 if field_docs is not None and doc_to_field_nullable(field_docs):
756 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
758 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
759 fields.append((field_conv, field_docs))
760 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
761 elif camel_to_snake(variant_name) in inline_enum_variants:
762 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
763 # docs through to there, and then potentially mark the field nullable.
764 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
765 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
766 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
767 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
768 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
770 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
771 contains_trait |= mapped.ty_info.contains_trait
772 fields.append((mapped, None))
773 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
775 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
776 complex_enums[struct_name] = contains_trait
778 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
779 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
781 out_java_enum.write(out_java_enum_addendum)
782 out_java.write(out_java_addendum)
783 write_c(out_c_addendum)
785 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
786 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
788 flattened_field_var_convs = []
789 for var_line in field_var_lines:
790 if var_line.group(1) in trait_structs:
791 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
792 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), var_line.group(2)))
793 for field_var in trait_structs[var_line.group(1)]:
794 if isinstance(field_var, ConvInfo):
795 flattened_field_var_convs.append(field_var)
797 path = var_line.group(2)
798 if len(field_var) > 2:
799 path = var_line.group(2) + "." + field_var[2]
800 flattened_field_var_convs.append((field_var[0], field_var[1], path))
802 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
803 field_var_convs.append(mapped)
804 flattened_field_var_convs.append(mapped)
805 trait_structs[struct_name] = flattened_field_var_convs
808 for fn_docs, fn_line in trait_fn_lines:
809 if fn_line == "cloned":
810 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
811 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
813 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
815 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
816 ret_ty_info.nullable = True
818 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
819 is_const = fn_line.group(4) is not None
822 for idx, arg in enumerate(fn_line.group(5).split(',')):
825 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
826 if arg_ty_info.var_name in nullable_params:
827 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
828 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
830 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
831 arg_tys.append(arg_conv_info)
832 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
834 (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)
835 write_c(out_c_addendum)
836 out_java_trait.write(out_java_trait_addendum)
837 out_java.write(out_java_addendum)
839 for fn_docs, fn_line in trait_fn_lines:
840 if fn_line == "cloned":
842 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
843 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
844 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
845 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"
846 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)
847 for idx, var_line in enumerate(field_var_lines):
848 if var_line.group(1) not in trait_structs:
849 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
850 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
851 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
852 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
854 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"
855 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)
857 def map_result(struct_name, res_ty, err_ty):
858 result_types.add(struct_name)
859 human_ty = struct_name.replace("LDKCResult", "Result")
860 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
861 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
862 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
863 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
864 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
865 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
866 out_java_struct.write(java_hu_struct)
868 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
869 field_ty = java_c_types(field_decl + " " + field_name, None)
870 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
871 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
874 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
875 fn_defn = owned_fn_defn
876 write_c("static inline " + fn_defn + "{\n")
877 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
878 write_c("\tret.is_owned = false;\n")
879 write_c("\treturn ret;\n")
880 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
881 fn_defn = owned_fn_defn
882 write_c("static inline " + fn_defn + "{\n")
883 if check_sfx is not None:
884 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
885 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
886 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
887 fn_defn = owned_fn_defn
888 write_c("static inline " + fn_defn + "{\n")
889 if check_sfx is not None:
890 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
891 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
894 fn_defn = ptr_fn_defn
895 write_c("static inline " + fn_defn + "{\n")
896 if check_sfx is not None:
897 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
898 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
901 dummy_line = fn_defn + ";\n"
902 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
904 def map_tuple(struct_name, field_lines):
905 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
906 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
907 out_java_struct.write(consts.map_tuple(struct_name))
909 for idx, (line, _) in enumerate(field_lines):
910 if idx != 0 and idx < len(field_lines) - 2:
911 ty_list.append(java_c_types(line.strip(';'), None))
912 tuple_types[struct_name] = (ty_list, struct_name)
914 # Map virtual getter functions
915 for idx, (line, _) in enumerate(field_lines):
916 if idx != 0 and idx < len(field_lines) - 2:
917 field_name = chr(ord('a') + idx - 1)
918 assert line.endswith(" " + field_name + ";")
919 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
921 out_java.write(consts.bindings_header)
922 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
923 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
925 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
926 out_java_struct.write(consts.common_base)
929 last_block_comment = None
932 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
934 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
935 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
936 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
937 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
938 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
939 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
940 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
941 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
942 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
943 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
944 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
945 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
946 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
947 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
948 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
950 union_enum_items = {}
951 result_ptr_struct_items = {}
953 if block_comment is not None:
954 if line.endswith("*/\n"):
955 last_block_comment = block_comment.strip("\n")
958 block_comment = block_comment + line.strip(" /*")
959 elif cur_block_obj is not None:
960 cur_block_obj = cur_block_obj + line
961 if line.startswith("} "):
965 obj_lines = cur_block_obj.split("\n")
967 result_contents = None
968 is_unitary_enum = False
969 is_union_enum = False
974 last_struct_block_comment = None
976 for idx, struct_line in enumerate(obj_lines):
977 if struct_line.strip().startswith("/*"):
978 block_comment = struct_line.strip(" /*")
979 if block_comment is not None:
980 if struct_line.endswith("*/"):
981 last_struct_block_comment = block_comment.strip("\n")
984 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
986 struct_name_match = struct_name_regex.match(struct_line)
987 if struct_name_match is not None:
988 struct_name = struct_name_match.group(3)
989 if struct_name_match.group(1) == "enum":
990 if not struct_name.endswith("_Tag"):
991 is_unitary_enum = True
994 elif struct_name_match.group(1) == "union":
996 if line_indicates_opaque_regex.match(struct_line):
998 result_match = line_indicates_result_regex.match(struct_line)
999 if result_match is not None:
1000 result_contents = result_match.group(1)
1001 vec_ty_match = line_indicates_vec_regex.match(struct_line)
1002 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
1003 vec_ty = vec_ty_match.group(2)
1004 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
1006 trait_fn_match = line_indicates_trait_regex.match(struct_line)
1007 if trait_fn_match is not None:
1008 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
1009 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
1010 if trait_clone_fn_match is not None:
1011 trait_fn_lines.append((last_struct_block_comment, "cloned"))
1012 field_var_match = line_field_var_regex.match(struct_line)
1013 if field_var_match is not None:
1014 field_var_lines.append(field_var_match)
1015 field_lines.append((struct_line, last_struct_block_comment))
1016 last_struct_block_comment = None
1018 assert(struct_name is not None)
1019 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))
1020 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))
1021 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))
1022 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))
1023 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))
1024 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))
1025 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))
1028 opaque_structs.add(struct_name)
1029 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
1030 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
1031 last_block_comment = None
1032 out_java_struct.write(out_opaque_struct_human)
1033 elif result_contents is not None:
1034 assert result_contents in result_ptr_struct_items
1035 res_ty, err_ty = result_ptr_struct_items[result_contents]
1036 map_result(struct_name, res_ty, err_ty)
1037 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1038 for line, _ in field_lines:
1039 if line.endswith("*result;"):
1040 res_ty = line[:-8].strip()
1041 elif line.endswith("*err;"):
1042 err_ty = line[:-5].strip()
1043 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1044 result_types.add(struct_name[:-3])
1046 map_tuple(struct_name, field_lines)
1047 elif vec_ty is not None:
1048 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1049 if ty_info.is_native_primitive:
1050 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1051 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1052 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1053 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1054 write_c("\treturn ret;\n}\n")
1055 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1056 ty_name = struct_name.replace("LDK", "")
1057 clone_fns.add(ty_name + "_clone")
1058 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1059 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1060 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1061 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1062 write_c("\t}\n\treturn ret;\n}\n")
1064 assert(struct_name.endswith("_Tag"))
1065 struct_name = struct_name[:-4]
1066 union_enum_items[struct_name] = {"field_lines": field_lines}
1067 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1068 enum_var_name = struct_name.split("_")
1069 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1070 elif struct_name in union_enum_items:
1073 for line, field_block_comment in field_lines:
1074 if line == " struct {":
1078 elif elem_items > -1:
1080 if line.startswith("struct "):
1082 elif line.startswith("enum "):
1084 split = line.split(" ")
1085 assert len(split) == 2
1086 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1089 # We don't currently support tuple variant with more than one element
1091 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1092 last_block_comment = None
1093 elif is_unitary_enum:
1094 map_unitary_enum(struct_name, field_lines, last_block_comment)
1095 last_block_comment = None
1096 elif len(trait_fn_lines) > 0:
1097 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1098 elif struct_name == "LDKTxOut":
1099 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1100 out_java_struct.write(consts.hu_struct_file_prefix)
1101 out_java_struct.write(consts.txout_defn)
1102 out_java_struct.write(consts.hu_struct_file_suffix)
1103 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1104 write_c(fn_line + " {")
1105 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1107 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1108 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1109 write_c(fn_line + " {")
1110 write_c("\treturn thing->value;")
1112 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1113 elif struct_name == "LDKTxIn":
1114 with open(f"{sys.argv[3]}/structs/TxIn{consts.file_ext}", "w") as out_java_struct:
1115 out_java_struct.write(consts.hu_struct_file_prefix)
1116 out_java_struct.write(consts.txin_defn)
1117 out_java_struct.write(consts.hu_struct_file_suffix)
1118 fn_line = "struct LDKWitness TxIn_get_witness (struct LDKTxIn* thing)"
1119 write_c(fn_line + " {")
1120 write_c("\treturn Witness_clone(&thing->witness);")
1122 map_fn(fn_line + "\n", re.compile("(.*) (TxIn_get_witness) \((.*)\)").match(fn_line), None, None, None)
1123 fn_line = "struct LDKCVec_u8Z TxIn_get_script_sig (struct LDKTxIn* thing)"
1124 write_c(fn_line + " {")
1125 write_c("\treturn CVec_u8Z_clone(&thing->script_sig);")
1127 map_fn(fn_line + "\n", re.compile("(.*) (TxIn_get_script_sig) \((.*)\)").match(fn_line), None, None, None)
1128 fn_line = "LDKThirtyTwoBytes TxIn_get_previous_txid (struct LDKTxIn* thing)"
1129 write_c(fn_line + " {")
1130 write_c("\treturn thing->previous_txid;")
1132 map_fn(fn_line + "\n", re.compile("(.*) (TxIn_get_previous_txid) \((.*)\)").match(fn_line), None, None, None)
1133 fn_line = "uint32_t TxIn_get_previous_vout (struct LDKTxIn* thing)"
1134 write_c(fn_line + " {")
1135 write_c("\treturn thing->previous_vout;")
1137 map_fn(fn_line + "\n", re.compile("(.*) (TxIn_get_previous_vout) \((.*)\)").match(fn_line), None, None, None)
1138 fn_line = "uint32_t TxIn_get_sequence (struct LDKTxIn* thing)"
1139 write_c(fn_line + " {")
1140 write_c("\treturn thing->sequence;")
1142 map_fn(fn_line + "\n", re.compile("(.*) (TxIn_get_sequence) \((.*)\)").match(fn_line), None, None, None)
1143 elif struct_name == "LDKBigEndianScalar":
1144 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1145 out_java_struct.write(consts.hu_struct_file_prefix)
1146 out_java_struct.write(consts.scalar_defn)
1147 out_java_struct.write(consts.hu_struct_file_suffix)
1148 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1149 write_c(fn_line + " {\n")
1150 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1151 write_c("\treturn ret;\n")
1153 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1155 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1156 # there's nothing heap-allocated inside it the C bindings don't bother
1157 # exposing a `_free` method. Instead, we have to manually write one here,
1158 # though it doesn't need to do anything, the autogenerated wrapper will do
1159 # the required FREE.
1160 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1161 write_c(fn_line + " {}\n")
1162 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1164 pass # Everything remaining is a byte[] of some form
1165 cur_block_obj = None
1167 fn_ptr = fn_ptr_regex.match(line)
1168 fn_ret_arr = fn_ret_arr_regex.match(line)
1169 reg_fn = reg_fn_regex.match(line)
1170 const_val = const_val_regex.match(line)
1172 if line.startswith("#include <"):
1174 elif line.startswith("/*"):
1175 if not line.endswith("*/\n"):
1176 block_comment = line.strip(" /*")
1177 elif line.startswith("typedef enum "):
1178 cur_block_obj = line
1179 elif line.startswith("typedef struct "):
1180 cur_block_obj = line
1181 elif line.startswith("typedef union "):
1182 cur_block_obj = line
1183 elif fn_ptr is not None:
1184 map_fn(line, fn_ptr, None, None, last_block_comment)
1185 last_block_comment = None
1186 elif fn_ret_arr is not None:
1187 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1188 last_block_comment = None
1189 elif reg_fn is not None:
1190 map_fn(line, reg_fn, None, None, last_block_comment)
1191 last_block_comment = None
1192 elif const_val_regex is not None:
1193 # TODO Map const variables
1196 assert(line == "\n")
1198 out_java.write(consts.bindings_footer())
1199 for struct_name in opaque_structs:
1200 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1201 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1202 for struct_name in trait_structs:
1203 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1204 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1205 for struct_name in complex_enums:
1206 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1207 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1208 for struct_name in result_types:
1209 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1210 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1211 for struct_name in tuple_types:
1212 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1213 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1214 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1216 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1217 out_c.write(consts.c_file_pfx)
1218 out_c.write(consts.init_str())
1220 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1221 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1222 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1223 util.write(consts.util_fn_sfx)