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