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("LDKThirtyTwoBytes"):
137 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
138 assert var_is_arr_regex.match(fn_arg[8:])
139 rust_obj = "LDKThirtyTwoBytes"
141 elif fn_arg.startswith("LDKThirtyTwoU16s"):
142 fn_arg = "uint16_t (*" + fn_arg[17:] + ")[32]"
143 assert var_is_arr_regex.match(fn_arg[9:])
144 rust_obj = "LDKThirtyTwoU16s"
146 elif fn_arg.startswith("LDKU128"):
147 if fn_arg == "LDKU128":
148 fn_arg = "LDKU128 arg"
149 if fn_arg.startswith("LDKU128*") or fn_arg.startswith("LDKU128 *"):
150 fn_arg = "uint8_t (" + fn_arg[8:] + ")[16]"
152 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[16]"
153 assert var_is_arr_regex.match(fn_arg[8:])
155 arr_access = "le_bytes"
156 elif fn_arg.startswith("LDKPublicKey"):
157 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
158 assert var_is_arr_regex.match(fn_arg[8:])
159 rust_obj = "LDKPublicKey"
160 arr_access = "compressed_form"
161 elif fn_arg.startswith("LDKSecretKey"):
162 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
163 assert var_is_arr_regex.match(fn_arg[8:])
164 rust_obj = "LDKSecretKey"
166 elif fn_arg.startswith("LDKECDSASignature"):
167 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[64]"
168 assert var_is_arr_regex.match(fn_arg[8:])
169 rust_obj = "LDKECDSASignature"
170 arr_access = "compact_form"
171 elif fn_arg.startswith("LDKSchnorrSignature"):
172 fn_arg = "uint8_t (*" + fn_arg[20:] + ")[64]"
173 assert var_is_arr_regex.match(fn_arg[8:])
174 rust_obj = "LDKSchnorrSignature"
175 arr_access = "compact_form"
176 elif fn_arg.startswith("LDKRecoverableSignature"):
177 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
178 assert var_is_arr_regex.match(fn_arg[8:])
179 rust_obj = "LDKRecoverableSignature"
180 arr_access = "serialized_form"
181 elif fn_arg.startswith("LDKThreeBytes"):
182 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
183 assert var_is_arr_regex.match(fn_arg[8:])
184 rust_obj = "LDKThreeBytes"
186 elif fn_arg.startswith("LDKFourBytes"):
187 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
188 assert var_is_arr_regex.match(fn_arg[8:])
189 rust_obj = "LDKFourBytes"
191 elif fn_arg.startswith("LDKSixteenBytes"):
192 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
193 assert var_is_arr_regex.match(fn_arg[8:])
194 rust_obj = "LDKSixteenBytes"
196 elif fn_arg.startswith("LDKTwentyBytes"):
197 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
198 assert var_is_arr_regex.match(fn_arg[8:])
199 rust_obj = "LDKTwentyBytes"
201 elif fn_arg.startswith("LDKTwelveBytes"):
202 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
203 assert var_is_arr_regex.match(fn_arg[8:])
204 rust_obj = "LDKTwelveBytes"
206 elif fn_arg.startswith("LDKu8slice"):
207 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
208 assert var_is_arr_regex.match(fn_arg[8:])
209 rust_obj = "LDKu8slice"
211 elif fn_arg.startswith("LDKCVec_u8Z"):
212 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
213 rust_obj = "LDKCVec_u8Z"
214 assert var_is_arr_regex.match(fn_arg[8:])
216 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
217 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
218 rust_obj = "LDKTransaction"
219 assert var_is_arr_regex.match(fn_arg[8:])
221 elif fn_arg.startswith("LDKTransactionOutputs "):
222 fn_arg = "C2Tuple_ThirtyTwoBytesCVec_C2Tuple_u32TxOutZZZ"
223 rust_obj = "C2Tuple_ThirtyTwoBytesCVec_C2Tuple_u32TxOutZZZ"
224 elif fn_arg.startswith("LDKWitness ") or fn_arg == "LDKWitness":
225 if len(fn_arg) > 12 and fn_arg[11] == "*":
226 fn_arg = "uint8_t (" + fn_arg[11:] + ")[datalen]"
228 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
229 rust_obj = "LDKWitness"
230 assert var_is_arr_regex.match(fn_arg[8:])
232 elif fn_arg.startswith("LDKCVec_"):
235 fn_arg = fn_arg.replace("*", "")
238 tyn = fn_arg[8:].split(" ")
239 assert tyn[0].endswith("Z")
243 new_arg = "LDK" + tyn[0][:-1]
245 new_arg = new_arg + " " + a
246 res = java_c_types(new_arg, ret_arr_len)
248 assert java_c_types_none_allowed
251 res.pass_by_ref = True
252 java_ty = consts.java_arr_ty_str(res.java_ty)
253 if res.is_native_primitive or res.passed_as_ptr:
254 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
255 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
256 nonnull_ptr=nonnull_ptr, is_const=is_const,
257 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
259 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
260 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
261 nonnull_ptr=nonnull_ptr, is_const=is_const,
262 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
265 contains_trait = False
268 java_type_plural = None
270 if fn_arg.startswith("void"):
274 fn_arg = fn_arg[4:].strip()
276 elif fn_arg.startswith("bool"):
277 java_ty = consts.c_type_map['bool'][0]
281 fn_arg = fn_arg[4:].strip()
283 elif fn_arg.startswith("uint8_t"):
284 mapped_type = consts.c_type_map['uint8_t']
285 java_ty = mapped_type[0]
289 fn_arg = fn_arg[7:].strip()
291 elif fn_arg.startswith("LDKU5") or fn_arg.startswith("LDKWitnessVersion"):
292 java_ty = consts.c_type_map['uint8_t'][0]
293 if fn_arg.startswith("LDKU5"):
296 fn_arg = fn_arg[6:].strip()
298 java_hu_ty = "WitnessVersion"
299 rust_obj = "LDKWitnessVersion"
300 fn_arg = fn_arg[18:].strip()
304 elif fn_arg.startswith("uint16_t"):
305 mapped_type = consts.c_type_map['uint16_t']
306 java_ty = mapped_type[0]
310 fn_arg = fn_arg[8:].strip()
312 elif fn_arg.startswith("uint32_t"):
313 mapped_type = consts.c_type_map['uint32_t']
314 java_ty = mapped_type[0]
318 fn_arg = fn_arg[8:].strip()
320 elif fn_arg.startswith("int64_t"):
321 mapped_type = consts.c_type_map['int64_t']
322 java_ty = mapped_type[0]
326 fn_arg = fn_arg[7:].strip()
328 elif fn_arg.startswith("double"):
329 mapped_type = consts.c_type_map['double']
330 java_ty = mapped_type[0]
334 fn_arg = fn_arg[6:].strip()
336 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
337 # TODO: uintptr_t is arch-dependent :(
338 mapped_type = consts.c_type_map['uint64_t']
339 java_ty = mapped_type[0]
341 if fn_arg.startswith("uint64_t"):
344 fn_arg = fn_arg[8:].strip()
346 java_ty = consts.usize_native_ty
347 c_ty = consts.usize_c_ty
349 rust_obj = "uintptr_t"
350 fn_arg = fn_arg[9:].strip()
352 elif is_const and fn_arg.startswith("char *"):
353 java_ty = consts.java_type_map["String"]
354 java_hu_ty = consts.java_hu_type_map["String"]
357 fn_ty_arg = "Ljava/lang/String;"
358 fn_arg = fn_arg[6:].strip()
359 elif fn_arg.startswith("LDKStr") or fn_arg.startswith("LDKAddress"):
362 java_ty = consts.java_type_map["String"]
363 java_hu_ty = consts.java_hu_type_map["String"]
365 fn_ty_arg = "Ljava/lang/String;"
366 if fn_arg.startswith("LDKAddress"):
367 fn_arg = fn_arg[10:].strip()
369 fn_arg = fn_arg[6:].strip()
372 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
373 java_ty = consts.c_type_map['uint32_t'][0]
374 java_hu_ty = "UnqualifiedError"
375 rust_obj = "LDKError"
379 fn_arg = fn_arg[8:].strip()
381 ma = var_ty_regex.match(fn_arg)
382 arr_ty = ma.group(1).strip()
383 if ma.group(1).strip() in unitary_enums:
384 assert ma.group(1).strip().startswith("LDK")
385 java_ty = ma.group(1).strip()[3:]
387 c_ty = consts.unitary_enum_c_ty
388 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
389 fn_arg = ma.group(2).strip()
390 rust_obj = ma.group(1).strip()
392 c_ty = consts.ptr_c_ty
393 java_ty = consts.ptr_native_ty
394 java_hu_ty = ma.group(1).strip()
395 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
396 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
397 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
398 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
399 java_hu_ty = java_hu_ty.replace("LDK", "")
401 fn_arg = ma.group(2).strip()
402 rust_obj = ma.group(1).strip()
403 if rust_obj in trait_structs:
404 contains_trait = True
405 elif rust_obj in complex_enums:
406 contains_trait = complex_enums[rust_obj]
409 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
410 fn_arg = fn_arg.replace("*", "").strip()
412 c_ty = consts.ptr_c_ty
413 java_ty = consts.ptr_native_ty
416 var_is_arr = var_is_arr_regex.match(fn_arg)
418 if var_is_arr is not None or ret_arr_len is not None:
419 assert(not take_by_ptr)
421 # is there a special case for plurals?
422 if len(mapped_type) == 3:
423 java_ty = mapped_type[1]
424 java_hu_ty = mapped_type[2]
426 java_ty = java_ty + "[]"
428 if rust_obj == "LDKU128":
429 java_hu_ty = consts.u128_native_ty
430 c_ty = c_ty + "Array"
432 subty = java_c_types(arr_ty, None)
434 assert java_c_types_none_allowed
437 subty.pass_by_ref = True
439 if var_is_arr is not None:
440 if var_is_arr.group(1) == "":
441 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,
442 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
443 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
444 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,
445 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
446 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
448 if java_hu_ty is None:
450 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,
451 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,
452 contains_trait=contains_trait, subty=subty)
454 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
455 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
456 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
460 from gen_type_mapping import TypeMappingGenerator
461 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
463 with open(sys.argv[1]) as in_h:
465 reg_fn = reg_fn_regex.match(line)
466 if reg_fn is not None:
467 if reg_fn.group(2).endswith("_clone"):
468 clone_fns.add(reg_fn.group(2))
470 rty = java_c_types(reg_fn.group(1), None)
471 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
472 constructor_fns[rty.rust_obj] = reg_fn.group(3)
474 arr_fn = fn_ret_arr_regex.match(line)
475 if arr_fn is not None:
476 if arr_fn.group(2).endswith("_clone"):
477 clone_fns.add(arr_fn.group(2))
478 # No object constructors return arrays, as then they wouldn't be an object constructor
481 # Define some manual clones...
482 clone_fns.add("ThirtyTwoBytes_clone")
483 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")
486 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
487 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
488 write_c("\tif (sizeof(void*) == 4) {\n")
489 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
490 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
491 write_c("\t} else {\n")
492 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
493 write_c("\t\t// use bit 9 ^ bit 10.\n")
494 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
495 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
496 write_c("#ifdef LDK_DEBUG_BUILD\n")
497 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
498 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
499 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
500 write_c("\t\tp ^= 1ULL << 53;\n")
502 write_c("\t\treturn (void*)p;\n")
506 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
507 write_c("\tif(ptr < 4096) return true;\n")
508 write_c("\tif (sizeof(void*) == 4) {\n")
509 write_c("\t\treturn ptr & (1ULL << 32);\n")
510 write_c("\t} else {\n")
511 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
512 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
513 write_c("#ifdef LDK_DEBUG_BUILD\n")
514 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
515 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
516 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
518 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
522 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
523 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
524 write_c("\tif (sizeof(void*) == 4) {\n")
525 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
526 write_c("\t} else {\n")
527 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
528 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
529 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
530 write_c("#ifdef LDK_DEBUG_BUILD\n")
531 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
532 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
533 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
534 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
535 write_c("\t\tt ^= 1ULL << 53;\n")
537 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
538 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
539 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
540 write_c("\t\treturn t;\n")
544 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
546 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
547 util.write(consts.util_fn_pfx)
549 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
550 # Map a top-level function
551 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
552 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
553 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
554 method_return_type = re_match.group(1)
555 method_name = re_match.group(2)
556 method_comma_separated_arguments = re_match.group(3)
557 method_arguments = method_comma_separated_arguments.split(',')
559 if method_name.startswith("__"):
562 is_free = method_name.endswith("_free")
563 if method_name.startswith("COption") or method_name.startswith("CResult"):
564 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
565 expected_struct = "LDKC" + struct_meth
566 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
567 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
568 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
569 if method_name.startswith("C2Tuple"):
570 struct_meth = "Two" + tuple_name
571 expected_struct = "LDKC2" + tuple_name
573 struct_meth = "Three" + tuple_name
574 expected_struct = "LDKC3" + tuple_name
575 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
577 struct_meth = method_name.split("_")[0]
578 expected_struct = "LDK" + struct_meth
579 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
581 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
583 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
585 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
587 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
588 # LDKWitness is mapped as an array, so no need to implement clone
589 if expected_struct == "LDKWitness":
591 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
592 write_c("static inline " + meth_line + " {\n")
593 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
594 write_c(method_name + "(arg)")
595 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
596 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
597 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
600 default_constructor_args = {}
602 takes_self_ptr = False
604 for argument_index, argument in enumerate(method_arguments):
605 arg_ty = type_mapping_generator.java_c_types(argument, None)
606 argument_conversion_info = None
607 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
608 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
610 if argument_conversion_info.ty_info.is_ptr:
611 takes_self_ptr = True
612 elif arg_ty.var_name in params_nullable:
613 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
614 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
615 arg_ty_info = java_c_types(argument, None)
616 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
617 print(" The argument appears to require a move, or not clonable, and is nullable.")
618 print(" Normally for arguments that require a move and are not clonable, we split")
619 print(" the argument into the type's constructor's arguments and just use those to")
620 print(" construct a new object on the fly.")
621 print(" However, because the object is nullable, doing so would mean we can no")
622 print(" longer allow the user to pass null, as we now have an argument list instead.")
623 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
624 print(" It may or may not actually be a reference, but its the simplest mapping option")
625 print(" and also the only use of this code today.")
626 arg_ty_info.requires_clone = False
627 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
628 assert argument_conversion_info.nullable
629 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
631 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
633 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
634 if argument_conversion_info.rust_obj in constructor_fns:
636 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
637 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
638 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
639 continue # (void) is C lingo for "no arguments)
640 if explode_arg_conv.c_ty == "void":
642 if not argument_conversion_info.arg_name in default_constructor_args:
643 default_constructor_args[argument_conversion_info.arg_name] = []
644 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
645 argument_types.append(argument_conversion_info)
647 if not takes_self and return_type_info.java_hu_ty != struct_meth:
648 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
649 struct_meth_name = method_name
653 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
654 expected_struct in complex_enums or expected_struct in complex_enums or
655 expected_struct in result_types or expected_struct in tuple_types) and not is_free
656 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
657 not method_name.startswith("TxOut") and not method_name.startswith("TxIn") and
658 not method_name.startswith("BigEndianScalar") and not method_name.startswith("_") and
659 method_name != "check_platform" and method_name != "Result_read" and
660 not expected_struct in unitary_enums and
661 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
662 or method_name.endswith("_read")))
664 # If we're adding a static method, and it returns a primitive or an array of primitives,
665 # and a variable conversion adds a reference on the return type (via `this`), skip the
666 # variable's conversion reference-add (as we obviously cannot need a reference).
667 if impl_on_utils and (return_type_info.is_native_primitive or
668 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
669 for arg in argument_types:
670 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
671 if "this" in arg.from_hu_conv[1]:
672 arg.from_hu_conv = (arg.from_hu_conv[0], "")
674 out_java.write("\t// " + line)
675 args_known = True # We no longer ever set this to false
676 (out_java_delta, out_c_delta, out_java_struct_delta) = \
677 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)
678 out_java.write(out_java_delta)
681 assert len(argument_types) == 1
682 assert return_type_info.c_ty == "void"
683 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")
684 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
685 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
687 for info in argument_types:
688 if info.arg_conv is not None:
689 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
690 assert c_call_string is None
691 write_c("\t" + method_name + "(")
692 if argument_types[0].arg_conv_name is not None:
693 write_c(argument_types[0].arg_conv_name)
695 for info in argument_types:
696 if info.arg_conv_cleanup is not None:
697 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
702 out_java_struct = None
704 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
705 out_java_struct.write(out_java_struct_delta)
707 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
708 for line in out_java_struct_delta.splitlines():
709 out_java_struct.write(line + "\n")
711 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
712 assert struct_name.startswith("LDK")
713 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
714 unitary_enums.add(struct_name)
715 for idx, (struct_line, _) in enumerate(field_lines):
717 assert(struct_line == "typedef enum %s {" % struct_name)
718 elif idx == len(field_lines) - 3:
719 assert(struct_line.endswith("_Sentinel,"))
720 elif idx == len(field_lines) - 2:
721 assert(struct_line == "} %s;" % struct_name)
722 elif idx == len(field_lines) - 1:
723 assert(struct_line == "")
724 assert struct_name.startswith("LDK")
725 (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)
727 out_java_enum.write(native_file_out)
728 out_java.write(native_out)
730 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
731 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
734 tag_field_lines = union_enum_items["field_lines"]
735 contains_trait = False
736 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
738 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
739 elif idx == len(tag_field_lines) - 3:
740 assert(struct_line.endswith("_Sentinel,"))
741 elif idx == len(tag_field_lines) - 2:
742 assert(struct_line == "} %s_Tag;" % struct_name)
743 elif idx == len(tag_field_lines) - 1:
744 assert(struct_line == "")
746 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
748 if "LDK" + variant_name in union_enum_items:
749 enum_var_lines = union_enum_items["LDK" + variant_name]
750 for idx, (field, field_docs) in enumerate(enum_var_lines):
751 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
752 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
753 contains_trait |= field_ty.contains_trait
754 if field_docs is not None and doc_to_field_nullable(field_docs):
755 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
757 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
758 fields.append((field_conv, field_docs))
759 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
760 elif camel_to_snake(variant_name) in inline_enum_variants:
761 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
762 # docs through to there, and then potentially mark the field nullable.
763 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
764 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
765 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
766 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
767 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
769 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
770 contains_trait |= mapped.ty_info.contains_trait
771 fields.append((mapped, None))
772 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
774 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
775 complex_enums[struct_name] = contains_trait
777 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
778 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
780 out_java_enum.write(out_java_enum_addendum)
781 out_java.write(out_java_addendum)
782 write_c(out_c_addendum)
784 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
785 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
787 flattened_field_var_convs = []
788 for var_line in field_var_lines:
789 if var_line.group(1) in trait_structs:
790 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
791 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), var_line.group(2)))
792 for field_var in trait_structs[var_line.group(1)]:
793 if isinstance(field_var, ConvInfo):
794 flattened_field_var_convs.append(field_var)
796 path = var_line.group(2)
797 if len(field_var) > 2:
798 path = var_line.group(2) + "." + field_var[2]
799 flattened_field_var_convs.append((field_var[0], field_var[1], path))
801 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
802 field_var_convs.append(mapped)
803 flattened_field_var_convs.append(mapped)
804 trait_structs[struct_name] = flattened_field_var_convs
807 for fn_docs, fn_line in trait_fn_lines:
808 if fn_line == "cloned":
809 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
810 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
812 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
814 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
815 ret_ty_info.nullable = True
817 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
818 is_const = fn_line.group(4) is not None
821 for idx, arg in enumerate(fn_line.group(5).split(',')):
824 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
825 if arg_ty_info.var_name in nullable_params:
826 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
827 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
829 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
830 arg_tys.append(arg_conv_info)
831 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
833 (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)
834 write_c(out_c_addendum)
835 out_java_trait.write(out_java_trait_addendum)
836 out_java.write(out_java_addendum)
838 for fn_docs, fn_line in trait_fn_lines:
839 if fn_line == "cloned":
841 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
842 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
843 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
844 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"
845 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)
846 for idx, var_line in enumerate(field_var_lines):
847 if var_line.group(1) not in trait_structs:
848 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
849 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
850 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
851 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
853 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"
854 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)
856 def map_result(struct_name, res_ty, err_ty):
857 result_types.add(struct_name)
858 human_ty = struct_name.replace("LDKCResult", "Result")
859 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
860 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
861 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
862 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
863 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
864 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
865 out_java_struct.write(java_hu_struct)
867 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
868 field_ty = java_c_types(field_decl + " " + field_name, None)
869 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
870 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
873 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
874 fn_defn = owned_fn_defn
875 write_c("static inline " + fn_defn + "{\n")
876 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
877 write_c("\tret.is_owned = false;\n")
878 write_c("\treturn ret;\n")
879 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
880 fn_defn = owned_fn_defn
881 write_c("static inline " + fn_defn + "{\n")
882 if check_sfx is not None:
883 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
884 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
885 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
886 fn_defn = owned_fn_defn
887 write_c("static inline " + fn_defn + "{\n")
888 if check_sfx is not None:
889 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
890 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
893 fn_defn = ptr_fn_defn
894 write_c("static inline " + fn_defn + "{\n")
895 if check_sfx is not None:
896 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
897 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
900 dummy_line = fn_defn + ";\n"
901 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
903 def map_tuple(struct_name, field_lines):
904 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
905 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
906 out_java_struct.write(consts.map_tuple(struct_name))
908 for idx, (line, _) in enumerate(field_lines):
909 if idx != 0 and idx < len(field_lines) - 2:
910 ty_list.append(java_c_types(line.strip(';'), None))
911 tuple_types[struct_name] = (ty_list, struct_name)
913 # Map virtual getter functions
914 for idx, (line, _) in enumerate(field_lines):
915 if idx != 0 and idx < len(field_lines) - 2:
916 field_name = chr(ord('a') + idx - 1)
917 assert line.endswith(" " + field_name + ";")
918 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
920 out_java.write(consts.bindings_header)
921 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
922 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
924 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
925 out_java_struct.write(consts.common_base)
928 last_block_comment = None
931 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
933 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
934 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
935 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
936 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
937 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
938 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
939 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
940 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
941 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
942 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
943 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
944 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
945 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
946 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
947 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
949 union_enum_items = {}
950 result_ptr_struct_items = {}
952 if block_comment is not None:
953 if line.endswith("*/\n"):
954 last_block_comment = block_comment.strip("\n")
957 block_comment = block_comment + line.strip(" /*")
958 elif cur_block_obj is not None:
959 cur_block_obj = cur_block_obj + line
960 if line.startswith("} "):
964 obj_lines = cur_block_obj.split("\n")
966 result_contents = None
967 is_unitary_enum = False
968 is_union_enum = False
973 last_struct_block_comment = None
975 for idx, struct_line in enumerate(obj_lines):
976 if struct_line.strip().startswith("/*"):
977 block_comment = struct_line.strip(" /*")
978 if block_comment is not None:
979 if struct_line.endswith("*/"):
980 last_struct_block_comment = block_comment.strip("\n")
983 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
985 struct_name_match = struct_name_regex.match(struct_line)
986 if struct_name_match is not None:
987 struct_name = struct_name_match.group(3)
988 if struct_name_match.group(1) == "enum":
989 if not struct_name.endswith("_Tag"):
990 is_unitary_enum = True
993 elif struct_name_match.group(1) == "union":
995 if line_indicates_opaque_regex.match(struct_line):
997 result_match = line_indicates_result_regex.match(struct_line)
998 if result_match is not None:
999 result_contents = result_match.group(1)
1000 vec_ty_match = line_indicates_vec_regex.match(struct_line)
1001 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
1002 vec_ty = vec_ty_match.group(2)
1003 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
1005 trait_fn_match = line_indicates_trait_regex.match(struct_line)
1006 if trait_fn_match is not None:
1007 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
1008 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
1009 if trait_clone_fn_match is not None:
1010 trait_fn_lines.append((last_struct_block_comment, "cloned"))
1011 field_var_match = line_field_var_regex.match(struct_line)
1012 if field_var_match is not None:
1013 field_var_lines.append(field_var_match)
1014 field_lines.append((struct_line, last_struct_block_comment))
1015 last_struct_block_comment = None
1017 assert(struct_name is not None)
1018 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))
1019 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))
1020 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))
1021 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))
1022 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))
1023 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))
1024 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))
1027 opaque_structs.add(struct_name)
1028 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
1029 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
1030 last_block_comment = None
1031 out_java_struct.write(out_opaque_struct_human)
1032 elif result_contents is not None:
1033 assert result_contents in result_ptr_struct_items
1034 res_ty, err_ty = result_ptr_struct_items[result_contents]
1035 map_result(struct_name, res_ty, err_ty)
1036 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1037 for line, _ in field_lines:
1038 if line.endswith("*result;"):
1039 res_ty = line[:-8].strip()
1040 elif line.endswith("*err;"):
1041 err_ty = line[:-5].strip()
1042 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1043 result_types.add(struct_name[:-3])
1045 map_tuple(struct_name, field_lines)
1046 elif vec_ty is not None:
1047 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1048 if ty_info.is_native_primitive:
1049 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1050 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1051 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1052 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1053 write_c("\treturn ret;\n}\n")
1054 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1055 ty_name = struct_name.replace("LDK", "")
1056 clone_fns.add(ty_name + "_clone")
1057 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1058 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1059 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1060 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1061 write_c("\t}\n\treturn ret;\n}\n")
1063 assert(struct_name.endswith("_Tag"))
1064 struct_name = struct_name[:-4]
1065 union_enum_items[struct_name] = {"field_lines": field_lines}
1066 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1067 enum_var_name = struct_name.split("_")
1068 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1069 elif struct_name in union_enum_items:
1072 for line, field_block_comment in field_lines:
1073 if line == " struct {":
1077 elif elem_items > -1:
1079 if line.startswith("struct "):
1081 elif line.startswith("enum "):
1083 split = line.split(" ")
1084 assert len(split) == 2
1085 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1088 # We don't currently support tuple variant with more than one element
1090 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1091 last_block_comment = None
1092 elif is_unitary_enum:
1093 map_unitary_enum(struct_name, field_lines, last_block_comment)
1094 last_block_comment = None
1095 elif len(trait_fn_lines) > 0:
1096 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1097 elif struct_name == "LDKTxOut":
1098 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1099 out_java_struct.write(consts.hu_struct_file_prefix)
1100 out_java_struct.write(consts.txout_defn)
1101 out_java_struct.write(consts.hu_struct_file_suffix)
1102 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1103 write_c(fn_line + " {")
1104 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1106 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1107 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1108 write_c(fn_line + " {")
1109 write_c("\treturn thing->value;")
1111 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1112 elif struct_name == "LDKTxIn":
1113 with open(f"{sys.argv[3]}/structs/TxIn{consts.file_ext}", "w") as out_java_struct:
1114 out_java_struct.write(consts.hu_struct_file_prefix)
1115 out_java_struct.write(consts.txin_defn)
1116 out_java_struct.write(consts.hu_struct_file_suffix)
1117 fn_line = "struct LDKWitness TxIn_get_witness (struct LDKTxIn* thing)"
1118 write_c(fn_line + " {")
1119 write_c("\treturn Witness_clone(&thing->witness);")
1121 map_fn(fn_line + "\n", re.compile("(.*) (TxIn_get_witness) \((.*)\)").match(fn_line), None, None, None)
1122 fn_line = "struct LDKCVec_u8Z TxIn_get_script_sig (struct LDKTxIn* thing)"
1123 write_c(fn_line + " {")
1124 write_c("\treturn CVec_u8Z_clone(&thing->script_sig);")
1126 map_fn(fn_line + "\n", re.compile("(.*) (TxIn_get_script_sig) \((.*)\)").match(fn_line), None, None, None)
1127 fn_line = "LDKThirtyTwoBytes TxIn_get_previous_txid (struct LDKTxIn* thing)"
1128 write_c(fn_line + " {")
1129 write_c("\treturn thing->previous_txid;")
1131 map_fn(fn_line + "\n", re.compile("(.*) (TxIn_get_previous_txid) \((.*)\)").match(fn_line), None, None, None)
1132 fn_line = "uint32_t TxIn_get_previous_vout (struct LDKTxIn* thing)"
1133 write_c(fn_line + " {")
1134 write_c("\treturn thing->previous_vout;")
1136 map_fn(fn_line + "\n", re.compile("(.*) (TxIn_get_previous_vout) \((.*)\)").match(fn_line), None, None, None)
1137 fn_line = "uint32_t TxIn_get_sequence (struct LDKTxIn* thing)"
1138 write_c(fn_line + " {")
1139 write_c("\treturn thing->sequence;")
1141 map_fn(fn_line + "\n", re.compile("(.*) (TxIn_get_sequence) \((.*)\)").match(fn_line), None, None, None)
1142 elif struct_name == "LDKBigEndianScalar":
1143 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1144 out_java_struct.write(consts.hu_struct_file_prefix)
1145 out_java_struct.write(consts.scalar_defn)
1146 out_java_struct.write(consts.hu_struct_file_suffix)
1147 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1148 write_c(fn_line + " {\n")
1149 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1150 write_c("\treturn ret;\n")
1152 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1154 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1155 # there's nothing heap-allocated inside it the C bindings don't bother
1156 # exposing a `_free` method. Instead, we have to manually write one here,
1157 # though it doesn't need to do anything, the autogenerated wrapper will do
1158 # the required FREE.
1159 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1160 write_c(fn_line + " {}\n")
1161 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1163 pass # Everything remaining is a byte[] of some form
1164 cur_block_obj = None
1166 fn_ptr = fn_ptr_regex.match(line)
1167 fn_ret_arr = fn_ret_arr_regex.match(line)
1168 reg_fn = reg_fn_regex.match(line)
1169 const_val = const_val_regex.match(line)
1171 if line.startswith("#include <"):
1173 elif line.startswith("/*"):
1174 if not line.endswith("*/\n"):
1175 block_comment = line.strip(" /*")
1176 elif line.startswith("typedef enum "):
1177 cur_block_obj = line
1178 elif line.startswith("typedef struct "):
1179 cur_block_obj = line
1180 elif line.startswith("typedef union "):
1181 cur_block_obj = line
1182 elif fn_ptr is not None:
1183 map_fn(line, fn_ptr, None, None, last_block_comment)
1184 last_block_comment = None
1185 elif fn_ret_arr is not None:
1186 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1187 last_block_comment = None
1188 elif reg_fn is not None:
1189 map_fn(line, reg_fn, None, None, last_block_comment)
1190 last_block_comment = None
1191 elif const_val_regex is not None:
1192 # TODO Map const variables
1195 assert(line == "\n")
1197 out_java.write(consts.bindings_footer())
1198 for struct_name in opaque_structs:
1199 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1200 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1201 for struct_name in trait_structs:
1202 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1203 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1204 for struct_name in complex_enums:
1205 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1206 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1207 for struct_name in result_types:
1208 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1209 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1210 for struct_name in tuple_types:
1211 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1212 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1213 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1215 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1216 out_c.write(consts.c_file_pfx)
1217 out_c.write(consts.init_str())
1219 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1220 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1221 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1222 util.write(consts.util_fn_sfx)