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].startswith("c_sharp"):
33 from csharp_strings import Consts
34 if sys.argv[6] == "c_sharp-win":
35 target = csharp_strings.Target.WINDOWS
36 elif sys.argv[6] == "c_sharp-darwin":
37 target = csharp_strings.Target.PTHREAD
38 elif sys.argv[6] == "c_sharp-linux":
39 target = csharp_strings.Target.LINUX
42 elif sys.argv[6] == "python":
44 from python_strings import Consts
45 target = python_strings.Target.PYTHON
47 print("Only java, typescript, python, or c_sharp can be set for lang")
50 consts = Consts(DEBUG, target=target, outdir=sys.argv[4])
52 local_git_version = os.getenv("LDK_GARBAGECOLLECTED_GIT_OVERRIDE")
53 if local_git_version is None:
54 local_git_version = subprocess.check_output(["git", "describe", '--tag', '--dirty']).decode("utf-8").strip()
56 from bindingstypes import *
63 def camel_to_snake(s):
64 # Convert camel case to snake case, in a way that appears to match cbindgen
70 if lastchar.isupper():
71 if not char.isupper() and not lastund:
76 ret = ret + lastchar.lower()
79 if char.isupper() and not lastund:
87 return (ret + lastchar.lower()).strip("_")
89 def doc_to_field_nullable(doc):
92 for line in doc.splitlines():
93 if "Note that this (or a relevant inner pointer) may be NULL or all-0s to represent None" in line:
97 def doc_to_params_ret_nullable(doc):
102 for line in doc.splitlines():
103 if "may be NULL or all-0s to represent None" not in line:
105 if "Note that the return value" in line:
107 elif "Note that " in line:
108 param = line.split("Note that ")[1].split(" ")[0]
110 return (params, ret_null)
112 unitary_enums = set()
113 # Map from enum name to "contains trait object"
115 opaque_structs = set()
120 var_is_arr_regex = re.compile("\(\* ?([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
121 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
122 java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
123 def java_c_types(fn_arg, ret_arr_len):
124 fn_arg = fn_arg.strip()
125 if fn_arg.startswith("MUST_USE_RES "):
128 if fn_arg.startswith("const "):
131 if fn_arg.startswith("struct "):
133 if fn_arg.startswith("enum "):
135 nonnull_ptr = "NONNULL_PTR" in fn_arg
136 fn_arg = fn_arg.replace("NONNULL_PTR", "")
143 if fn_arg.startswith("LDKThirtyTwoBytes"):
144 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
145 assert var_is_arr_regex.match(fn_arg[8:])
146 rust_obj = "LDKThirtyTwoBytes"
148 elif fn_arg.startswith("LDKThirtyTwoU16s"):
149 fn_arg = "uint16_t (*" + fn_arg[17:] + ")[32]"
150 assert var_is_arr_regex.match(fn_arg[9:])
151 rust_obj = "LDKThirtyTwoU16s"
153 elif fn_arg.startswith("LDKU128"):
154 if fn_arg == "LDKU128":
155 fn_arg = "LDKU128 arg"
156 if fn_arg.startswith("LDKU128*") or fn_arg.startswith("LDKU128 *"):
157 fn_arg = "uint8_t (" + fn_arg[8:] + ")[16]"
159 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[16]"
160 assert var_is_arr_regex.match(fn_arg[8:])
162 arr_access = "le_bytes"
163 elif fn_arg.startswith("LDKPublicKey"):
164 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
165 assert var_is_arr_regex.match(fn_arg[8:])
166 rust_obj = "LDKPublicKey"
167 arr_access = "compressed_form"
168 elif fn_arg.startswith("LDKSecretKey"):
169 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
170 assert var_is_arr_regex.match(fn_arg[8:])
171 rust_obj = "LDKSecretKey"
173 elif fn_arg.startswith("LDKECDSASignature"):
174 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[64]"
175 assert var_is_arr_regex.match(fn_arg[8:])
176 rust_obj = "LDKECDSASignature"
177 arr_access = "compact_form"
178 elif fn_arg.startswith("LDKSchnorrSignature"):
179 fn_arg = "uint8_t (*" + fn_arg[20:] + ")[64]"
180 assert var_is_arr_regex.match(fn_arg[8:])
181 rust_obj = "LDKSchnorrSignature"
182 arr_access = "compact_form"
183 elif fn_arg.startswith("LDKRecoverableSignature"):
184 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
185 assert var_is_arr_regex.match(fn_arg[8:])
186 rust_obj = "LDKRecoverableSignature"
187 arr_access = "serialized_form"
188 elif fn_arg.startswith("LDKThreeBytes"):
189 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
190 assert var_is_arr_regex.match(fn_arg[8:])
191 rust_obj = "LDKThreeBytes"
193 elif fn_arg.startswith("LDKFourBytes"):
194 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
195 assert var_is_arr_regex.match(fn_arg[8:])
196 rust_obj = "LDKFourBytes"
198 elif fn_arg.startswith("LDKSixteenBytes"):
199 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
200 assert var_is_arr_regex.match(fn_arg[8:])
201 rust_obj = "LDKSixteenBytes"
203 elif fn_arg.startswith("LDKTwentyBytes"):
204 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
205 assert var_is_arr_regex.match(fn_arg[8:])
206 rust_obj = "LDKTwentyBytes"
208 elif fn_arg.startswith("LDKTwelveBytes"):
209 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
210 assert var_is_arr_regex.match(fn_arg[8:])
211 rust_obj = "LDKTwelveBytes"
213 elif fn_arg.startswith("LDKu8slice"):
214 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
215 assert var_is_arr_regex.match(fn_arg[8:])
216 rust_obj = "LDKu8slice"
218 elif fn_arg.startswith("LDKCVec_u8Z"):
219 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
220 rust_obj = "LDKCVec_u8Z"
221 assert var_is_arr_regex.match(fn_arg[8:])
223 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
224 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
225 rust_obj = "LDKTransaction"
226 assert var_is_arr_regex.match(fn_arg[8:])
228 elif fn_arg.startswith("LDKTransactionOutputs "):
229 fn_arg = "C2Tuple_ThirtyTwoBytesCVec_C2Tuple_u32TxOutZZZ"
230 rust_obj = "C2Tuple_ThirtyTwoBytesCVec_C2Tuple_u32TxOutZZZ"
231 elif fn_arg.startswith("LDKWitness ") or fn_arg == "LDKWitness":
232 if len(fn_arg) > 12 and fn_arg[11] == "*":
233 fn_arg = "uint8_t (" + fn_arg[11:] + ")[datalen]"
235 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
236 rust_obj = "LDKWitness"
237 assert var_is_arr_regex.match(fn_arg[8:])
239 elif fn_arg.startswith("LDKCVec_"):
242 fn_arg = fn_arg.replace("*", "")
245 tyn = fn_arg[8:].split(" ")
246 assert tyn[0].endswith("Z")
250 new_arg = "LDK" + tyn[0][:-1]
252 new_arg = new_arg + " " + a
253 res = java_c_types(new_arg, ret_arr_len)
255 assert java_c_types_none_allowed
258 res.pass_by_ref = True
259 java_ty = consts.java_arr_ty_str(res.java_ty)
260 if res.is_native_primitive or res.passed_as_ptr:
261 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
262 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
263 nonnull_ptr=nonnull_ptr, is_const=is_const,
264 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
266 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
267 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
268 nonnull_ptr=nonnull_ptr, is_const=is_const,
269 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
272 contains_trait = False
275 java_type_plural = None
277 if fn_arg.startswith("void"):
281 fn_arg = fn_arg[4:].strip()
283 elif fn_arg.startswith("bool"):
284 java_ty = consts.c_type_map['bool'][0]
288 fn_arg = fn_arg[4:].strip()
290 elif fn_arg.startswith("uint8_t"):
291 mapped_type = consts.c_type_map['uint8_t']
292 java_ty = mapped_type[0]
296 fn_arg = fn_arg[7:].strip()
298 elif fn_arg.startswith("LDKU5") or fn_arg.startswith("LDKWitnessVersion"):
299 java_ty = consts.c_type_map['uint8_t'][0]
300 if fn_arg.startswith("LDKU5"):
303 fn_arg = fn_arg[6:].strip()
305 java_hu_ty = "WitnessVersion"
306 rust_obj = "LDKWitnessVersion"
307 fn_arg = fn_arg[18:].strip()
311 elif fn_arg.startswith("uint16_t"):
312 mapped_type = consts.c_type_map['uint16_t']
313 java_ty = mapped_type[0]
317 fn_arg = fn_arg[8:].strip()
319 elif fn_arg.startswith("uint32_t"):
320 mapped_type = consts.c_type_map['uint32_t']
321 java_ty = mapped_type[0]
325 fn_arg = fn_arg[8:].strip()
327 elif fn_arg.startswith("int64_t"):
328 mapped_type = consts.c_type_map['int64_t']
329 java_ty = mapped_type[0]
333 fn_arg = fn_arg[7:].strip()
335 elif fn_arg.startswith("double"):
336 mapped_type = consts.c_type_map['double']
337 java_ty = mapped_type[0]
341 fn_arg = fn_arg[6:].strip()
343 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
344 # TODO: uintptr_t is arch-dependent :(
345 mapped_type = consts.c_type_map['uint64_t']
346 java_ty = mapped_type[0]
348 if fn_arg.startswith("uint64_t"):
351 fn_arg = fn_arg[8:].strip()
353 java_ty = consts.usize_native_ty
354 c_ty = consts.usize_c_ty
356 rust_obj = "uintptr_t"
357 fn_arg = fn_arg[9:].strip()
359 elif is_const and fn_arg.startswith("char *"):
360 java_ty = consts.java_type_map["String"]
361 java_hu_ty = consts.java_hu_type_map["String"]
364 fn_ty_arg = "Ljava/lang/String;"
365 fn_arg = fn_arg[6:].strip()
366 elif fn_arg.startswith("LDKStr") or fn_arg.startswith("LDKAddress"):
369 java_ty = consts.java_type_map["String"]
370 java_hu_ty = consts.java_hu_type_map["String"]
372 fn_ty_arg = "Ljava/lang/String;"
373 if fn_arg.startswith("LDKAddress"):
374 fn_arg = fn_arg[10:].strip()
376 fn_arg = fn_arg[6:].strip()
379 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
380 java_ty = consts.c_type_map['uint32_t'][0]
381 java_hu_ty = "UnqualifiedError"
382 rust_obj = "LDKError"
386 fn_arg = fn_arg[8:].strip()
388 ma = var_ty_regex.match(fn_arg)
389 arr_ty = ma.group(1).strip()
390 if ma.group(1).strip() in unitary_enums:
391 assert ma.group(1).strip().startswith("LDK")
392 java_ty = ma.group(1).strip()[3:]
394 c_ty = consts.unitary_enum_c_ty
395 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
396 fn_arg = ma.group(2).strip()
397 rust_obj = ma.group(1).strip()
399 c_ty = consts.ptr_c_ty
400 java_ty = consts.ptr_native_ty
401 java_hu_ty = ma.group(1).strip()
402 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
403 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
404 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
405 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
406 java_hu_ty = java_hu_ty.replace("LDKC4Tuple", "FourTuple")
407 java_hu_ty = java_hu_ty.replace("LDK", "")
409 fn_arg = ma.group(2).strip()
410 rust_obj = ma.group(1).strip()
411 if rust_obj in trait_structs:
412 contains_trait = True
413 elif rust_obj in complex_enums:
414 contains_trait = complex_enums[rust_obj]
417 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
418 fn_arg = fn_arg.replace("*", "").strip()
420 c_ty = consts.ptr_c_ty
421 java_ty = consts.ptr_native_ty
424 var_is_arr = var_is_arr_regex.match(fn_arg)
426 if var_is_arr is not None or ret_arr_len is not None:
427 assert(not take_by_ptr)
429 # is there a special case for plurals?
430 if len(mapped_type) == 3:
431 java_ty = mapped_type[1]
432 java_hu_ty = mapped_type[2]
434 java_ty = java_ty + "[]"
436 if rust_obj == "LDKU128":
437 java_hu_ty = consts.u128_native_ty
438 c_ty = c_ty + "Array"
440 subty = java_c_types(arr_ty, None)
442 assert java_c_types_none_allowed
445 subty.pass_by_ref = True
447 if var_is_arr is not None:
448 if var_is_arr.group(1) == "":
449 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,
450 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
451 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
452 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,
453 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
454 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
456 if java_hu_ty is None:
458 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,
459 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,
460 contains_trait=contains_trait, subty=subty)
462 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
463 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
464 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
468 from gen_type_mapping import TypeMappingGenerator
469 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
471 with open(sys.argv[1]) as in_h:
473 reg_fn = reg_fn_regex.match(line)
474 if reg_fn is not None:
475 if reg_fn.group(2).endswith("_clone"):
476 clone_fns.add(reg_fn.group(2))
478 rty = java_c_types(reg_fn.group(1), None)
479 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
480 constructor_fns[rty.rust_obj] = reg_fn.group(3)
482 arr_fn = fn_ret_arr_regex.match(line)
483 if arr_fn is not None:
484 if arr_fn.group(2).endswith("_clone"):
485 clone_fns.add(arr_fn.group(2))
486 # No object constructors return arrays, as then they wouldn't be an object constructor
489 # Define some manual clones...
490 clone_fns.add("ThirtyTwoBytes_clone")
491 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")
494 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
495 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
496 write_c("\tif (sizeof(void*) == 4) {\n")
497 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
498 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
499 write_c("\t} else {\n")
500 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
501 write_c("\t\t// use bit 9 ^ bit 10.\n")
502 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
503 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
504 write_c("#ifdef LDK_DEBUG_BUILD\n")
505 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
506 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
507 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
508 write_c("\t\tp ^= 1ULL << 53;\n")
510 write_c("\t\treturn (void*)p;\n")
514 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
515 write_c("\tif(ptr < 4096) return true;\n")
516 write_c("\tif (sizeof(void*) == 4) {\n")
517 write_c("\t\treturn ptr & (1ULL << 32);\n")
518 write_c("\t} else {\n")
519 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
520 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
521 write_c("#ifdef LDK_DEBUG_BUILD\n")
522 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
523 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
524 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
526 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
530 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
531 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
532 write_c("\tif (sizeof(void*) == 4) {\n")
533 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
534 write_c("\t} else {\n")
535 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
536 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
537 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
538 write_c("#ifdef LDK_DEBUG_BUILD\n")
539 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
540 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
541 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
542 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
543 write_c("\t\tt ^= 1ULL << 53;\n")
545 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
546 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
547 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
548 write_c("\t\treturn t;\n")
552 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
554 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
555 util.write(consts.util_fn_pfx)
557 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
558 # Map a top-level function
559 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
560 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
561 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
562 method_return_type = re_match.group(1)
563 method_name = re_match.group(2)
564 method_comma_separated_arguments = re_match.group(3)
565 method_arguments = method_comma_separated_arguments.split(',')
567 if method_name.startswith("__"):
570 is_free = method_name.endswith("_free")
571 if method_name.startswith("COption") or method_name.startswith("CResult"):
572 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
573 expected_struct = "LDKC" + struct_meth
574 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
575 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple") or method_name.startswith("C4Tuple"):
576 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
577 if method_name.startswith("C2Tuple"):
578 struct_meth = "Two" + tuple_name
579 expected_struct = "LDKC2" + tuple_name
580 elif method_name.startswith("C3Tuple"):
581 struct_meth = "Three" + tuple_name
582 expected_struct = "LDKC3" + tuple_name
584 struct_meth = "Four" + tuple_name
585 expected_struct = "LDKC4" + tuple_name
586 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
588 struct_meth = method_name.split("_")[0]
589 expected_struct = "LDK" + struct_meth
590 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
592 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
594 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
596 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
598 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
599 # LDKWitness is mapped as an array, so no need to implement clone
600 if expected_struct == "LDKWitness":
602 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
603 write_c("static inline " + meth_line + " {\n")
604 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
605 write_c(method_name + "(arg)")
606 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
607 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
608 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
611 default_constructor_args = {}
613 takes_self_ptr = False
615 for argument_index, argument in enumerate(method_arguments):
616 arg_ty = type_mapping_generator.java_c_types(argument, None)
617 argument_conversion_info = None
618 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
619 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
621 if argument_conversion_info.ty_info.is_ptr:
622 takes_self_ptr = True
623 elif arg_ty.var_name in params_nullable:
624 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
625 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
626 arg_ty_info = java_c_types(argument, None)
627 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
628 print(" The argument appears to require a move, or not clonable, and is nullable.")
629 print(" Normally for arguments that require a move and are not clonable, we split")
630 print(" the argument into the type's constructor's arguments and just use those to")
631 print(" construct a new object on the fly.")
632 print(" However, because the object is nullable, doing so would mean we can no")
633 print(" longer allow the user to pass null, as we now have an argument list instead.")
634 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
635 print(" It may or may not actually be a reference, but its the simplest mapping option")
636 print(" and also the only use of this code today.")
637 arg_ty_info.requires_clone = False
638 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
639 assert argument_conversion_info.nullable
640 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
642 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
644 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
645 if argument_conversion_info.rust_obj in constructor_fns:
647 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
648 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
649 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
650 continue # (void) is C lingo for "no arguments)
651 if explode_arg_conv.c_ty == "void":
653 if not argument_conversion_info.arg_name in default_constructor_args:
654 default_constructor_args[argument_conversion_info.arg_name] = []
655 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
656 argument_types.append(argument_conversion_info)
658 if not takes_self and return_type_info.java_hu_ty != struct_meth:
659 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
660 struct_meth_name = method_name
664 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
665 expected_struct in complex_enums or expected_struct in complex_enums or
666 expected_struct in result_types or expected_struct in tuple_types) and not is_free
667 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
668 not method_name.startswith("TxOut") and not method_name.startswith("TxIn") and
669 not method_name.startswith("BigEndianScalar") and not method_name.startswith("WitnessProgram") and
670 not method_name.startswith("_") and
671 method_name != "check_platform" and method_name != "Result_read" and
672 not expected_struct in unitary_enums and
673 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_") and not method_name.startswith("C4Tuple_"))
674 or method_name.endswith("_read")))
676 # If we're adding a static method, and it returns a primitive or an array of primitives,
677 # and a variable conversion adds a reference on the return type (via `this`), skip the
678 # variable's conversion reference-add (as we obviously cannot need a reference).
679 if impl_on_utils and (return_type_info.is_native_primitive or
680 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
681 for arg in argument_types:
682 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
683 if "this" in arg.from_hu_conv[1]:
684 arg.from_hu_conv = (arg.from_hu_conv[0], "")
686 out_java.write("\t// " + line)
687 args_known = True # We no longer ever set this to false
688 (out_java_delta, out_c_delta, out_java_struct_delta) = \
689 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)
690 out_java.write(out_java_delta)
693 assert len(argument_types) == 1
694 assert return_type_info.c_ty == "void"
695 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")
696 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
697 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
699 for info in argument_types:
700 if info.arg_conv is not None:
701 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
702 assert c_call_string is None
703 write_c("\t" + method_name + "(")
704 if argument_types[0].arg_conv_name is not None:
705 write_c(argument_types[0].arg_conv_name)
707 for info in argument_types:
708 if info.arg_conv_cleanup is not None:
709 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
714 out_java_struct = None
716 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
717 out_java_struct.write(out_java_struct_delta)
719 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
720 for line in out_java_struct_delta.splitlines():
721 out_java_struct.write(line + "\n")
723 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
724 assert struct_name.startswith("LDK")
725 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
726 unitary_enums.add(struct_name)
727 for idx, (struct_line, _) in enumerate(field_lines):
729 assert(struct_line == "typedef enum %s {" % struct_name)
730 elif idx == len(field_lines) - 3:
731 assert(struct_line.endswith("_Sentinel,"))
732 elif idx == len(field_lines) - 2:
733 assert(struct_line == "} %s;" % struct_name)
734 elif idx == len(field_lines) - 1:
735 assert(struct_line == "")
736 assert struct_name.startswith("LDK")
737 (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)
739 out_java_enum.write(native_file_out)
740 out_java.write(native_out)
742 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
743 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
746 tag_field_lines = union_enum_items["field_lines"]
747 contains_trait = False
748 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
750 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
751 elif idx == len(tag_field_lines) - 3:
752 assert(struct_line.endswith("_Sentinel,"))
753 elif idx == len(tag_field_lines) - 2:
754 assert(struct_line == "} %s_Tag;" % struct_name)
755 elif idx == len(tag_field_lines) - 1:
756 assert(struct_line == "")
758 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
760 if "LDK" + variant_name in union_enum_items:
761 enum_var_lines = union_enum_items["LDK" + variant_name]
762 for idx, (field, field_docs) in enumerate(enum_var_lines):
763 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
764 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
765 contains_trait |= field_ty.contains_trait
766 if field_docs is not None and doc_to_field_nullable(field_docs):
767 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
769 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
770 fields.append((field_conv, field_docs))
771 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
772 elif camel_to_snake(variant_name) in inline_enum_variants:
773 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
774 # docs through to there, and then potentially mark the field nullable.
775 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
776 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
777 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
778 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
779 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
781 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
782 contains_trait |= mapped.ty_info.contains_trait
783 fields.append((mapped, None))
784 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
786 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
787 complex_enums[struct_name] = contains_trait
789 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
790 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
792 out_java_enum.write(out_java_enum_addendum)
793 out_java.write(out_java_addendum)
794 write_c(out_c_addendum)
796 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
797 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
799 flattened_field_var_convs = []
800 for var_line in field_var_lines:
801 if var_line.group(1) in trait_structs:
802 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
803 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), var_line.group(2)))
804 for field_var in trait_structs[var_line.group(1)]:
805 if isinstance(field_var, ConvInfo):
806 flattened_field_var_convs.append(field_var)
808 path = var_line.group(2)
809 if len(field_var) > 2:
810 path = var_line.group(2) + "." + field_var[2]
811 flattened_field_var_convs.append((field_var[0], field_var[1], path))
813 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
814 field_var_convs.append(mapped)
815 flattened_field_var_convs.append(mapped)
816 trait_structs[struct_name] = flattened_field_var_convs
819 for fn_docs, fn_line in trait_fn_lines:
820 if fn_line == "cloned":
821 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
822 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
824 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
826 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
827 ret_ty_info.nullable = True
829 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
830 is_const = fn_line.group(4) is not None
833 for idx, arg in enumerate(fn_line.group(5).split(',')):
836 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
837 if arg_ty_info.var_name in nullable_params:
838 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
839 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
841 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
842 arg_tys.append(arg_conv_info)
843 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
845 (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)
846 write_c(out_c_addendum)
847 out_java_trait.write(out_java_trait_addendum)
848 out_java.write(out_java_addendum)
850 for fn_docs, fn_line in trait_fn_lines:
851 if fn_line == "cloned":
853 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
854 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
855 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
856 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"
857 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)
858 for idx, var_line in enumerate(field_var_lines):
859 if var_line.group(1) not in trait_structs:
860 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
861 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
862 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
863 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
865 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"
866 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)
868 def map_result(struct_name, res_ty, err_ty):
869 result_types.add(struct_name)
870 human_ty = struct_name.replace("LDKCResult", "Result")
871 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
872 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
873 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
874 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
875 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
876 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
877 out_java_struct.write(java_hu_struct)
879 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
880 field_ty = java_c_types(field_decl + " " + field_name, None)
881 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
882 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
885 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
886 fn_defn = owned_fn_defn
887 write_c("static inline " + fn_defn + "{\n")
888 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
889 write_c("\tret.is_owned = false;\n")
890 write_c("\treturn ret;\n")
891 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
892 fn_defn = owned_fn_defn
893 write_c("static inline " + fn_defn + "{\n")
894 if check_sfx is not None:
895 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
896 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
897 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
898 fn_defn = owned_fn_defn
899 write_c("static inline " + fn_defn + "{\n")
900 if check_sfx is not None:
901 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
902 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
905 fn_defn = ptr_fn_defn
906 write_c("static inline " + fn_defn + "{\n")
907 if check_sfx is not None:
908 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
909 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
912 dummy_line = fn_defn + ";\n"
913 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
915 def map_tuple(struct_name, field_lines):
916 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple").replace("LDKC4Tuple", "FourTuple")
917 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
918 out_java_struct.write(consts.map_tuple(struct_name))
920 for idx, (line, _) in enumerate(field_lines):
921 if idx != 0 and idx < len(field_lines) - 2:
922 ty_list.append(java_c_types(line.strip(';'), None))
923 tuple_types[struct_name] = (ty_list, struct_name)
925 # Map virtual getter functions
926 for idx, (line, _) in enumerate(field_lines):
927 if idx != 0 and idx < len(field_lines) - 2:
928 field_name = chr(ord('a') + idx - 1)
929 assert line.endswith(" " + field_name + ";")
930 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
932 out_java.write(consts.bindings_header)
933 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
934 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
936 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
937 out_java_struct.write(consts.common_base)
940 last_block_comment = None
943 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
945 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
946 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
947 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
948 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
949 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
950 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
951 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
952 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
953 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
954 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
955 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
956 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
957 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
958 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
959 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
961 union_enum_items = {}
962 result_ptr_struct_items = {}
964 if block_comment is not None:
965 if line.endswith("*/\n"):
966 last_block_comment = block_comment.strip("\n")
969 block_comment = block_comment + line.strip(" /*")
970 elif cur_block_obj is not None:
971 cur_block_obj = cur_block_obj + line
972 if line.startswith("} "):
976 obj_lines = cur_block_obj.split("\n")
978 result_contents = None
979 is_unitary_enum = False
980 is_union_enum = False
985 last_struct_block_comment = None
987 for idx, struct_line in enumerate(obj_lines):
988 if struct_line.strip().startswith("/*"):
989 block_comment = struct_line.strip(" /*")
990 if block_comment is not None:
991 if struct_line.endswith("*/"):
992 last_struct_block_comment = block_comment.strip("\n")
995 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
997 struct_name_match = struct_name_regex.match(struct_line)
998 if struct_name_match is not None:
999 struct_name = struct_name_match.group(3)
1000 if struct_name_match.group(1) == "enum":
1001 if not struct_name.endswith("_Tag"):
1002 is_unitary_enum = True
1004 is_union_enum = True
1005 elif struct_name_match.group(1) == "union":
1007 if line_indicates_opaque_regex.match(struct_line):
1009 result_match = line_indicates_result_regex.match(struct_line)
1010 if result_match is not None:
1011 result_contents = result_match.group(1)
1012 vec_ty_match = line_indicates_vec_regex.match(struct_line)
1013 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
1014 vec_ty = vec_ty_match.group(2)
1015 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_") or struct_name.startswith("LDKC4Tuple_"):
1017 trait_fn_match = line_indicates_trait_regex.match(struct_line)
1018 if trait_fn_match is not None:
1019 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
1020 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
1021 if trait_clone_fn_match is not None:
1022 trait_fn_lines.append((last_struct_block_comment, "cloned"))
1023 field_var_match = line_field_var_regex.match(struct_line)
1024 if field_var_match is not None:
1025 field_var_lines.append(field_var_match)
1026 field_lines.append((struct_line, last_struct_block_comment))
1027 last_struct_block_comment = None
1029 assert(struct_name is not None)
1030 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))
1031 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))
1032 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))
1033 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))
1034 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))
1035 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))
1036 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))
1039 opaque_structs.add(struct_name)
1040 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
1041 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
1042 last_block_comment = None
1043 out_java_struct.write(out_opaque_struct_human)
1044 elif result_contents is not None:
1045 assert result_contents in result_ptr_struct_items
1046 res_ty, err_ty = result_ptr_struct_items[result_contents]
1047 map_result(struct_name, res_ty, err_ty)
1048 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1049 for line, _ in field_lines:
1050 if line.endswith("*result;"):
1051 res_ty = line[:-8].strip()
1052 elif line.endswith("*err;"):
1053 err_ty = line[:-5].strip()
1054 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1055 result_types.add(struct_name[:-3])
1057 map_tuple(struct_name, field_lines)
1058 elif vec_ty is not None:
1059 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1060 if ty_info.is_native_primitive:
1061 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1062 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1063 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1064 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1065 write_c("\treturn ret;\n}\n")
1066 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1067 ty_name = struct_name.replace("LDK", "")
1068 clone_fns.add(ty_name + "_clone")
1069 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1070 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1071 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1072 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1073 write_c("\t}\n\treturn ret;\n}\n")
1075 assert(struct_name.endswith("_Tag"))
1076 struct_name = struct_name[:-4]
1077 union_enum_items[struct_name] = {"field_lines": field_lines}
1078 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1079 enum_var_name = struct_name.split("_")
1080 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1081 elif struct_name in union_enum_items:
1084 for line, field_block_comment in field_lines:
1085 if line == " struct {":
1089 elif elem_items > -1:
1091 if line.startswith("struct "):
1093 elif line.startswith("enum "):
1095 split = line.split(" ")
1096 assert len(split) == 2
1097 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1100 # We don't currently support tuple variant with more than one element
1102 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1103 last_block_comment = None
1104 elif is_unitary_enum:
1105 map_unitary_enum(struct_name, field_lines, last_block_comment)
1106 last_block_comment = None
1107 elif len(trait_fn_lines) > 0:
1108 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1109 elif struct_name == "LDKTxOut":
1110 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1111 out_java_struct.write(consts.hu_struct_file_prefix)
1112 out_java_struct.write(consts.txout_defn)
1113 out_java_struct.write(consts.hu_struct_file_suffix)
1114 elif struct_name == "LDKTxIn":
1115 with open(f"{sys.argv[3]}/structs/TxIn{consts.file_ext}", "w") as out_java_struct:
1116 out_java_struct.write(consts.hu_struct_file_prefix)
1117 out_java_struct.write(consts.txin_defn)
1118 out_java_struct.write(consts.hu_struct_file_suffix)
1119 elif struct_name == "LDKBigEndianScalar":
1120 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1121 out_java_struct.write(consts.hu_struct_file_prefix)
1122 out_java_struct.write(consts.scalar_defn)
1123 out_java_struct.write(consts.hu_struct_file_suffix)
1124 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1125 write_c(fn_line + " {\n")
1126 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1127 write_c("\treturn ret;\n")
1129 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1131 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1132 # there's nothing heap-allocated inside it the C bindings don't bother
1133 # exposing a `_free` method. Instead, we have to manually write one here,
1134 # though it doesn't need to do anything, the autogenerated wrapper will do
1135 # the required FREE.
1136 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1137 write_c(fn_line + " {}\n")
1138 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1139 elif struct_name == "LDKWitnessProgram":
1140 with open(f"{sys.argv[3]}/structs/WitnessProgram{consts.file_ext}", "w") as out_java_struct:
1141 out_java_struct.write(consts.hu_struct_file_prefix)
1142 out_java_struct.write(consts.witness_program_defn)
1143 out_java_struct.write(consts.hu_struct_file_suffix)
1145 pass # Everything remaining is a byte[] of some form
1146 cur_block_obj = None
1148 fn_ptr = fn_ptr_regex.match(line)
1149 fn_ret_arr = fn_ret_arr_regex.match(line)
1150 reg_fn = reg_fn_regex.match(line)
1151 const_val = const_val_regex.match(line)
1153 if line.startswith("#include <"):
1155 elif line.startswith("/*"):
1156 if not line.endswith("*/\n"):
1157 block_comment = line.strip(" /*")
1158 elif line.startswith("typedef enum "):
1159 cur_block_obj = line
1160 elif line.startswith("typedef struct "):
1161 cur_block_obj = line
1162 elif line.startswith("typedef union "):
1163 cur_block_obj = line
1164 elif fn_ptr is not None:
1165 map_fn(line, fn_ptr, None, None, last_block_comment)
1166 last_block_comment = None
1167 elif fn_ret_arr is not None:
1168 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1169 last_block_comment = None
1170 elif reg_fn is not None:
1171 map_fn(line, reg_fn, None, None, last_block_comment)
1172 last_block_comment = None
1173 elif const_val_regex is not None:
1174 # TODO Map const variables
1177 assert(line == "\n")
1179 out_java.write(consts.bindings_footer())
1180 for struct_name in opaque_structs:
1181 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1182 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1183 for struct_name in trait_structs:
1184 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1185 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1186 for struct_name in complex_enums:
1187 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1188 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1189 for struct_name in result_types:
1190 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1191 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1192 for struct_name in tuple_types:
1193 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple").replace("LDKC4Tuple", "FourTuple")
1194 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1195 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1197 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1198 out_c.write(consts.c_file_pfx)
1199 out_c.write(consts.init_str())
1201 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1202 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1203 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1204 util.write(consts.util_fn_sfx)