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("LDK", "")
408 fn_arg = ma.group(2).strip()
409 rust_obj = ma.group(1).strip()
410 if rust_obj in trait_structs:
411 contains_trait = True
412 elif rust_obj in complex_enums:
413 contains_trait = complex_enums[rust_obj]
416 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
417 fn_arg = fn_arg.replace("*", "").strip()
419 c_ty = consts.ptr_c_ty
420 java_ty = consts.ptr_native_ty
423 var_is_arr = var_is_arr_regex.match(fn_arg)
425 if var_is_arr is not None or ret_arr_len is not None:
426 assert(not take_by_ptr)
428 # is there a special case for plurals?
429 if len(mapped_type) == 3:
430 java_ty = mapped_type[1]
431 java_hu_ty = mapped_type[2]
433 java_ty = java_ty + "[]"
435 if rust_obj == "LDKU128":
436 java_hu_ty = consts.u128_native_ty
437 c_ty = c_ty + "Array"
439 subty = java_c_types(arr_ty, None)
441 assert java_c_types_none_allowed
444 subty.pass_by_ref = True
446 if var_is_arr is not None:
447 if var_is_arr.group(1) == "":
448 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,
449 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
450 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
451 return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
452 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
453 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
455 if java_hu_ty is None:
457 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,
458 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,
459 contains_trait=contains_trait, subty=subty)
461 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
462 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
463 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
467 from gen_type_mapping import TypeMappingGenerator
468 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
470 with open(sys.argv[1]) as in_h:
472 reg_fn = reg_fn_regex.match(line)
473 if reg_fn is not None:
474 if reg_fn.group(2).endswith("_clone"):
475 clone_fns.add(reg_fn.group(2))
477 rty = java_c_types(reg_fn.group(1), None)
478 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
479 constructor_fns[rty.rust_obj] = reg_fn.group(3)
481 arr_fn = fn_ret_arr_regex.match(line)
482 if arr_fn is not None:
483 if arr_fn.group(2).endswith("_clone"):
484 clone_fns.add(arr_fn.group(2))
485 # No object constructors return arrays, as then they wouldn't be an object constructor
488 # Define some manual clones...
489 clone_fns.add("ThirtyTwoBytes_clone")
490 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")
493 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
494 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
495 write_c("\tif (sizeof(void*) == 4) {\n")
496 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
497 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
498 write_c("\t} else {\n")
499 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
500 write_c("\t\t// use bit 9 ^ bit 10.\n")
501 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
502 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
503 write_c("#ifdef LDK_DEBUG_BUILD\n")
504 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
505 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
506 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
507 write_c("\t\tp ^= 1ULL << 53;\n")
509 write_c("\t\treturn (void*)p;\n")
513 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
514 write_c("\tif(ptr < 4096) return true;\n")
515 write_c("\tif (sizeof(void*) == 4) {\n")
516 write_c("\t\treturn ptr & (1ULL << 32);\n")
517 write_c("\t} else {\n")
518 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
519 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
520 write_c("#ifdef LDK_DEBUG_BUILD\n")
521 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
522 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
523 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
525 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
529 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
530 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
531 write_c("\tif (sizeof(void*) == 4) {\n")
532 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
533 write_c("\t} else {\n")
534 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
535 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
536 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
537 write_c("#ifdef LDK_DEBUG_BUILD\n")
538 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
539 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
540 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
541 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
542 write_c("\t\tt ^= 1ULL << 53;\n")
544 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
545 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
546 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
547 write_c("\t\treturn t;\n")
551 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
553 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
554 util.write(consts.util_fn_pfx)
556 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
557 # Map a top-level function
558 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
559 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
560 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
561 method_return_type = re_match.group(1)
562 method_name = re_match.group(2)
563 method_comma_separated_arguments = re_match.group(3)
564 method_arguments = method_comma_separated_arguments.split(',')
566 if method_name.startswith("__"):
569 is_free = method_name.endswith("_free")
570 if method_name.startswith("COption") or method_name.startswith("CResult"):
571 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
572 expected_struct = "LDKC" + struct_meth
573 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
574 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
575 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
576 if method_name.startswith("C2Tuple"):
577 struct_meth = "Two" + tuple_name
578 expected_struct = "LDKC2" + tuple_name
580 struct_meth = "Three" + tuple_name
581 expected_struct = "LDKC3" + tuple_name
582 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
584 struct_meth = method_name.split("_")[0]
585 expected_struct = "LDK" + struct_meth
586 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
588 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
590 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
592 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
594 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
595 # LDKWitness is mapped as an array, so no need to implement clone
596 if expected_struct == "LDKWitness":
598 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
599 write_c("static inline " + meth_line + " {\n")
600 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
601 write_c(method_name + "(arg)")
602 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
603 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
604 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
607 default_constructor_args = {}
609 takes_self_ptr = False
611 for argument_index, argument in enumerate(method_arguments):
612 arg_ty = type_mapping_generator.java_c_types(argument, None)
613 argument_conversion_info = None
614 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
615 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
617 if argument_conversion_info.ty_info.is_ptr:
618 takes_self_ptr = True
619 elif arg_ty.var_name in params_nullable:
620 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
621 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
622 arg_ty_info = java_c_types(argument, None)
623 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
624 print(" The argument appears to require a move, or not clonable, and is nullable.")
625 print(" Normally for arguments that require a move and are not clonable, we split")
626 print(" the argument into the type's constructor's arguments and just use those to")
627 print(" construct a new object on the fly.")
628 print(" However, because the object is nullable, doing so would mean we can no")
629 print(" longer allow the user to pass null, as we now have an argument list instead.")
630 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
631 print(" It may or may not actually be a reference, but its the simplest mapping option")
632 print(" and also the only use of this code today.")
633 arg_ty_info.requires_clone = False
634 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
635 assert argument_conversion_info.nullable
636 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
638 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
640 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
641 if argument_conversion_info.rust_obj in constructor_fns:
643 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
644 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
645 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
646 continue # (void) is C lingo for "no arguments)
647 if explode_arg_conv.c_ty == "void":
649 if not argument_conversion_info.arg_name in default_constructor_args:
650 default_constructor_args[argument_conversion_info.arg_name] = []
651 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
652 argument_types.append(argument_conversion_info)
654 if not takes_self and return_type_info.java_hu_ty != struct_meth:
655 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
656 struct_meth_name = method_name
660 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
661 expected_struct in complex_enums or expected_struct in complex_enums or
662 expected_struct in result_types or expected_struct in tuple_types) and not is_free
663 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
664 not method_name.startswith("TxOut") and not method_name.startswith("TxIn") and
665 not method_name.startswith("BigEndianScalar") and not method_name.startswith("WitnessProgram") and
666 not method_name.startswith("_") and
667 method_name != "check_platform" and method_name != "Result_read" and
668 not expected_struct in unitary_enums and
669 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
670 or method_name.endswith("_read")))
672 # If we're adding a static method, and it returns a primitive or an array of primitives,
673 # and a variable conversion adds a reference on the return type (via `this`), skip the
674 # variable's conversion reference-add (as we obviously cannot need a reference).
675 if impl_on_utils and (return_type_info.is_native_primitive or
676 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
677 for arg in argument_types:
678 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
679 if "this" in arg.from_hu_conv[1]:
680 arg.from_hu_conv = (arg.from_hu_conv[0], "")
682 out_java.write("\t// " + line)
683 args_known = True # We no longer ever set this to false
684 (out_java_delta, out_c_delta, out_java_struct_delta) = \
685 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)
686 out_java.write(out_java_delta)
689 assert len(argument_types) == 1
690 assert return_type_info.c_ty == "void"
691 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")
692 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
693 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
695 for info in argument_types:
696 if info.arg_conv is not None:
697 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
698 assert c_call_string is None
699 write_c("\t" + method_name + "(")
700 if argument_types[0].arg_conv_name is not None:
701 write_c(argument_types[0].arg_conv_name)
703 for info in argument_types:
704 if info.arg_conv_cleanup is not None:
705 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
710 out_java_struct = None
712 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
713 out_java_struct.write(out_java_struct_delta)
715 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
716 for line in out_java_struct_delta.splitlines():
717 out_java_struct.write(line + "\n")
719 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
720 assert struct_name.startswith("LDK")
721 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
722 unitary_enums.add(struct_name)
723 for idx, (struct_line, _) in enumerate(field_lines):
725 assert(struct_line == "typedef enum %s {" % struct_name)
726 elif idx == len(field_lines) - 3:
727 assert(struct_line.endswith("_Sentinel,"))
728 elif idx == len(field_lines) - 2:
729 assert(struct_line == "} %s;" % struct_name)
730 elif idx == len(field_lines) - 1:
731 assert(struct_line == "")
732 assert struct_name.startswith("LDK")
733 (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)
735 out_java_enum.write(native_file_out)
736 out_java.write(native_out)
738 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
739 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
742 tag_field_lines = union_enum_items["field_lines"]
743 contains_trait = False
744 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
746 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
747 elif idx == len(tag_field_lines) - 3:
748 assert(struct_line.endswith("_Sentinel,"))
749 elif idx == len(tag_field_lines) - 2:
750 assert(struct_line == "} %s_Tag;" % struct_name)
751 elif idx == len(tag_field_lines) - 1:
752 assert(struct_line == "")
754 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
756 if "LDK" + variant_name in union_enum_items:
757 enum_var_lines = union_enum_items["LDK" + variant_name]
758 for idx, (field, field_docs) in enumerate(enum_var_lines):
759 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
760 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
761 contains_trait |= field_ty.contains_trait
762 if field_docs is not None and doc_to_field_nullable(field_docs):
763 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
765 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
766 fields.append((field_conv, field_docs))
767 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
768 elif camel_to_snake(variant_name) in inline_enum_variants:
769 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
770 # docs through to there, and then potentially mark the field nullable.
771 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
772 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
773 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
774 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
775 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
777 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
778 contains_trait |= mapped.ty_info.contains_trait
779 fields.append((mapped, None))
780 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
782 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
783 complex_enums[struct_name] = contains_trait
785 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
786 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
788 out_java_enum.write(out_java_enum_addendum)
789 out_java.write(out_java_addendum)
790 write_c(out_c_addendum)
792 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
793 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
795 flattened_field_var_convs = []
796 for var_line in field_var_lines:
797 if var_line.group(1) in trait_structs:
798 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
799 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), var_line.group(2)))
800 for field_var in trait_structs[var_line.group(1)]:
801 if isinstance(field_var, ConvInfo):
802 flattened_field_var_convs.append(field_var)
804 path = var_line.group(2)
805 if len(field_var) > 2:
806 path = var_line.group(2) + "." + field_var[2]
807 flattened_field_var_convs.append((field_var[0], field_var[1], path))
809 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
810 field_var_convs.append(mapped)
811 flattened_field_var_convs.append(mapped)
812 trait_structs[struct_name] = flattened_field_var_convs
815 for fn_docs, fn_line in trait_fn_lines:
816 if fn_line == "cloned":
817 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
818 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
820 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
822 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
823 ret_ty_info.nullable = True
825 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
826 is_const = fn_line.group(4) is not None
829 for idx, arg in enumerate(fn_line.group(5).split(',')):
832 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
833 if arg_ty_info.var_name in nullable_params:
834 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
835 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
837 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
838 arg_tys.append(arg_conv_info)
839 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
841 (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)
842 write_c(out_c_addendum)
843 out_java_trait.write(out_java_trait_addendum)
844 out_java.write(out_java_addendum)
846 for fn_docs, fn_line in trait_fn_lines:
847 if fn_line == "cloned":
849 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
850 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
851 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
852 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"
853 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)
854 for idx, var_line in enumerate(field_var_lines):
855 if var_line.group(1) not in trait_structs:
856 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
857 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
858 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
859 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
861 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"
862 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)
864 def map_result(struct_name, res_ty, err_ty):
865 result_types.add(struct_name)
866 human_ty = struct_name.replace("LDKCResult", "Result")
867 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
868 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
869 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
870 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
871 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
872 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
873 out_java_struct.write(java_hu_struct)
875 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
876 field_ty = java_c_types(field_decl + " " + field_name, None)
877 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
878 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
881 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
882 fn_defn = owned_fn_defn
883 write_c("static inline " + fn_defn + "{\n")
884 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
885 write_c("\tret.is_owned = false;\n")
886 write_c("\treturn ret;\n")
887 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
888 fn_defn = owned_fn_defn
889 write_c("static inline " + fn_defn + "{\n")
890 if check_sfx is not None:
891 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
892 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
893 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
894 fn_defn = owned_fn_defn
895 write_c("static inline " + fn_defn + "{\n")
896 if check_sfx is not None:
897 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
898 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
901 fn_defn = ptr_fn_defn
902 write_c("static inline " + fn_defn + "{\n")
903 if check_sfx is not None:
904 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
905 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
908 dummy_line = fn_defn + ";\n"
909 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
911 def map_tuple(struct_name, field_lines):
912 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
913 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
914 out_java_struct.write(consts.map_tuple(struct_name))
916 for idx, (line, _) in enumerate(field_lines):
917 if idx != 0 and idx < len(field_lines) - 2:
918 ty_list.append(java_c_types(line.strip(';'), None))
919 tuple_types[struct_name] = (ty_list, struct_name)
921 # Map virtual getter functions
922 for idx, (line, _) in enumerate(field_lines):
923 if idx != 0 and idx < len(field_lines) - 2:
924 field_name = chr(ord('a') + idx - 1)
925 assert line.endswith(" " + field_name + ";")
926 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
928 out_java.write(consts.bindings_header)
929 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
930 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
932 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
933 out_java_struct.write(consts.common_base)
936 last_block_comment = None
939 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
941 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
942 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
943 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
944 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
945 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
946 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
947 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
948 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
949 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
950 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
951 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
952 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
953 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
954 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
955 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
957 union_enum_items = {}
958 result_ptr_struct_items = {}
960 if block_comment is not None:
961 if line.endswith("*/\n"):
962 last_block_comment = block_comment.strip("\n")
965 block_comment = block_comment + line.strip(" /*")
966 elif cur_block_obj is not None:
967 cur_block_obj = cur_block_obj + line
968 if line.startswith("} "):
972 obj_lines = cur_block_obj.split("\n")
974 result_contents = None
975 is_unitary_enum = False
976 is_union_enum = False
981 last_struct_block_comment = None
983 for idx, struct_line in enumerate(obj_lines):
984 if struct_line.strip().startswith("/*"):
985 block_comment = struct_line.strip(" /*")
986 if block_comment is not None:
987 if struct_line.endswith("*/"):
988 last_struct_block_comment = block_comment.strip("\n")
991 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
993 struct_name_match = struct_name_regex.match(struct_line)
994 if struct_name_match is not None:
995 struct_name = struct_name_match.group(3)
996 if struct_name_match.group(1) == "enum":
997 if not struct_name.endswith("_Tag"):
998 is_unitary_enum = True
1000 is_union_enum = True
1001 elif struct_name_match.group(1) == "union":
1003 if line_indicates_opaque_regex.match(struct_line):
1005 result_match = line_indicates_result_regex.match(struct_line)
1006 if result_match is not None:
1007 result_contents = result_match.group(1)
1008 vec_ty_match = line_indicates_vec_regex.match(struct_line)
1009 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
1010 vec_ty = vec_ty_match.group(2)
1011 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
1013 trait_fn_match = line_indicates_trait_regex.match(struct_line)
1014 if trait_fn_match is not None:
1015 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
1016 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
1017 if trait_clone_fn_match is not None:
1018 trait_fn_lines.append((last_struct_block_comment, "cloned"))
1019 field_var_match = line_field_var_regex.match(struct_line)
1020 if field_var_match is not None:
1021 field_var_lines.append(field_var_match)
1022 field_lines.append((struct_line, last_struct_block_comment))
1023 last_struct_block_comment = None
1025 assert(struct_name is not None)
1026 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))
1027 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))
1028 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))
1029 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))
1030 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))
1031 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))
1032 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))
1035 opaque_structs.add(struct_name)
1036 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
1037 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
1038 last_block_comment = None
1039 out_java_struct.write(out_opaque_struct_human)
1040 elif result_contents is not None:
1041 assert result_contents in result_ptr_struct_items
1042 res_ty, err_ty = result_ptr_struct_items[result_contents]
1043 map_result(struct_name, res_ty, err_ty)
1044 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1045 for line, _ in field_lines:
1046 if line.endswith("*result;"):
1047 res_ty = line[:-8].strip()
1048 elif line.endswith("*err;"):
1049 err_ty = line[:-5].strip()
1050 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1051 result_types.add(struct_name[:-3])
1053 map_tuple(struct_name, field_lines)
1054 elif vec_ty is not None:
1055 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1056 if ty_info.is_native_primitive:
1057 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1058 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1059 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1060 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1061 write_c("\treturn ret;\n}\n")
1062 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1063 ty_name = struct_name.replace("LDK", "")
1064 clone_fns.add(ty_name + "_clone")
1065 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1066 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1067 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1068 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1069 write_c("\t}\n\treturn ret;\n}\n")
1071 assert(struct_name.endswith("_Tag"))
1072 struct_name = struct_name[:-4]
1073 union_enum_items[struct_name] = {"field_lines": field_lines}
1074 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1075 enum_var_name = struct_name.split("_")
1076 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1077 elif struct_name in union_enum_items:
1080 for line, field_block_comment in field_lines:
1081 if line == " struct {":
1085 elif elem_items > -1:
1087 if line.startswith("struct "):
1089 elif line.startswith("enum "):
1091 split = line.split(" ")
1092 assert len(split) == 2
1093 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1096 # We don't currently support tuple variant with more than one element
1098 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1099 last_block_comment = None
1100 elif is_unitary_enum:
1101 map_unitary_enum(struct_name, field_lines, last_block_comment)
1102 last_block_comment = None
1103 elif len(trait_fn_lines) > 0:
1104 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1105 elif struct_name == "LDKTxOut":
1106 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1107 out_java_struct.write(consts.hu_struct_file_prefix)
1108 out_java_struct.write(consts.txout_defn)
1109 out_java_struct.write(consts.hu_struct_file_suffix)
1110 elif struct_name == "LDKTxIn":
1111 with open(f"{sys.argv[3]}/structs/TxIn{consts.file_ext}", "w") as out_java_struct:
1112 out_java_struct.write(consts.hu_struct_file_prefix)
1113 out_java_struct.write(consts.txin_defn)
1114 out_java_struct.write(consts.hu_struct_file_suffix)
1115 elif struct_name == "LDKBigEndianScalar":
1116 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1117 out_java_struct.write(consts.hu_struct_file_prefix)
1118 out_java_struct.write(consts.scalar_defn)
1119 out_java_struct.write(consts.hu_struct_file_suffix)
1120 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1121 write_c(fn_line + " {\n")
1122 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1123 write_c("\treturn ret;\n")
1125 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1127 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1128 # there's nothing heap-allocated inside it the C bindings don't bother
1129 # exposing a `_free` method. Instead, we have to manually write one here,
1130 # though it doesn't need to do anything, the autogenerated wrapper will do
1131 # the required FREE.
1132 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1133 write_c(fn_line + " {}\n")
1134 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1135 elif struct_name == "LDKWitnessProgram":
1136 with open(f"{sys.argv[3]}/structs/WitnessProgram{consts.file_ext}", "w") as out_java_struct:
1137 out_java_struct.write(consts.hu_struct_file_prefix)
1138 out_java_struct.write(consts.witness_program_defn)
1139 out_java_struct.write(consts.hu_struct_file_suffix)
1141 pass # Everything remaining is a byte[] of some form
1142 cur_block_obj = None
1144 fn_ptr = fn_ptr_regex.match(line)
1145 fn_ret_arr = fn_ret_arr_regex.match(line)
1146 reg_fn = reg_fn_regex.match(line)
1147 const_val = const_val_regex.match(line)
1149 if line.startswith("#include <"):
1151 elif line.startswith("/*"):
1152 if not line.endswith("*/\n"):
1153 block_comment = line.strip(" /*")
1154 elif line.startswith("typedef enum "):
1155 cur_block_obj = line
1156 elif line.startswith("typedef struct "):
1157 cur_block_obj = line
1158 elif line.startswith("typedef union "):
1159 cur_block_obj = line
1160 elif fn_ptr is not None:
1161 map_fn(line, fn_ptr, None, None, last_block_comment)
1162 last_block_comment = None
1163 elif fn_ret_arr is not None:
1164 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1165 last_block_comment = None
1166 elif reg_fn is not None:
1167 map_fn(line, reg_fn, None, None, last_block_comment)
1168 last_block_comment = None
1169 elif const_val_regex is not None:
1170 # TODO Map const variables
1173 assert(line == "\n")
1175 out_java.write(consts.bindings_footer())
1176 for struct_name in opaque_structs:
1177 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1178 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1179 for struct_name in trait_structs:
1180 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1181 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1182 for struct_name in complex_enums:
1183 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1184 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1185 for struct_name in result_types:
1186 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1187 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1188 for struct_name in tuple_types:
1189 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1190 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1191 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1193 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1194 out_c.write(consts.c_file_pfx)
1195 out_c.write(consts.init_str())
1197 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1198 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1199 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1200 util.write(consts.util_fn_sfx)