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("LDKTweakedPublicKey"):
169 fn_arg = "uint8_t (*" + fn_arg[21:] + ")[32]"
170 assert var_is_arr_regex.match(fn_arg[8:])
171 rust_obj = "LDKTweakedPublicKey"
172 arr_access = "x_coordinate"
173 elif fn_arg.startswith("LDKSecretKey"):
174 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
175 assert var_is_arr_regex.match(fn_arg[8:])
176 rust_obj = "LDKSecretKey"
178 elif fn_arg.startswith("LDKECDSASignature"):
179 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[64]"
180 assert var_is_arr_regex.match(fn_arg[8:])
181 rust_obj = "LDKECDSASignature"
182 arr_access = "compact_form"
183 elif fn_arg.startswith("LDKSchnorrSignature"):
184 fn_arg = "uint8_t (*" + fn_arg[20:] + ")[64]"
185 assert var_is_arr_regex.match(fn_arg[8:])
186 rust_obj = "LDKSchnorrSignature"
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("LDKTransactionOutputs "):
234 fn_arg = "C2Tuple_ThirtyTwoBytesCVec_C2Tuple_u32TxOutZZZ"
235 rust_obj = "C2Tuple_ThirtyTwoBytesCVec_C2Tuple_u32TxOutZZZ"
236 elif fn_arg.startswith("LDKWitness ") or fn_arg == "LDKWitness":
237 if len(fn_arg) > 12 and fn_arg[11] == "*":
238 fn_arg = "uint8_t (" + fn_arg[11:] + ")[datalen]"
240 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
241 rust_obj = "LDKWitness"
242 assert var_is_arr_regex.match(fn_arg[8:])
244 elif fn_arg.startswith("LDKCVec_"):
247 fn_arg = fn_arg.replace("*", "")
250 tyn = fn_arg[8:].split(" ")
251 assert tyn[0].endswith("Z")
255 new_arg = "LDK" + tyn[0][:-1]
257 new_arg = new_arg + " " + a
258 res = java_c_types(new_arg, ret_arr_len)
260 assert java_c_types_none_allowed
263 res.pass_by_ref = True
264 java_ty = consts.java_arr_ty_str(res.java_ty)
265 if res.is_native_primitive or res.passed_as_ptr:
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=res.c_ty + "Array", 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)
271 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
272 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
273 nonnull_ptr=nonnull_ptr, is_const=is_const,
274 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
277 contains_trait = False
280 java_type_plural = None
282 if fn_arg.startswith("void"):
286 fn_arg = fn_arg[4:].strip()
288 elif fn_arg.startswith("bool"):
289 java_ty = consts.c_type_map['bool'][0]
293 fn_arg = fn_arg[4:].strip()
295 elif fn_arg.startswith("uint8_t"):
296 mapped_type = consts.c_type_map['uint8_t']
297 java_ty = mapped_type[0]
301 fn_arg = fn_arg[7:].strip()
303 elif fn_arg.startswith("LDKU5") or fn_arg.startswith("LDKWitnessVersion"):
304 java_ty = consts.c_type_map['uint8_t'][0]
305 if fn_arg.startswith("LDKU5"):
308 fn_arg = fn_arg[6:].strip()
310 java_hu_ty = "WitnessVersion"
311 rust_obj = "LDKWitnessVersion"
312 fn_arg = fn_arg[18:].strip()
316 elif fn_arg.startswith("uint16_t"):
317 mapped_type = consts.c_type_map['uint16_t']
318 java_ty = mapped_type[0]
322 fn_arg = fn_arg[8:].strip()
324 elif fn_arg.startswith("uint32_t"):
325 mapped_type = consts.c_type_map['uint32_t']
326 java_ty = mapped_type[0]
330 fn_arg = fn_arg[8:].strip()
332 elif fn_arg.startswith("int64_t"):
333 mapped_type = consts.c_type_map['int64_t']
334 java_ty = mapped_type[0]
338 fn_arg = fn_arg[7:].strip()
340 elif fn_arg.startswith("double"):
341 mapped_type = consts.c_type_map['double']
342 java_ty = mapped_type[0]
346 fn_arg = fn_arg[6:].strip()
348 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
349 # TODO: uintptr_t is arch-dependent :(
350 mapped_type = consts.c_type_map['uint64_t']
351 java_ty = mapped_type[0]
353 if fn_arg.startswith("uint64_t"):
356 fn_arg = fn_arg[8:].strip()
358 java_ty = consts.usize_native_ty
359 c_ty = consts.usize_c_ty
361 rust_obj = "uintptr_t"
362 fn_arg = fn_arg[9:].strip()
364 elif is_const and fn_arg.startswith("char *"):
365 java_ty = consts.java_type_map["String"]
366 java_hu_ty = consts.java_hu_type_map["String"]
369 fn_ty_arg = "Ljava/lang/String;"
370 fn_arg = fn_arg[6:].strip()
371 elif fn_arg.startswith("LDKStr") or fn_arg.startswith("LDKAddress"):
374 java_ty = consts.java_type_map["String"]
375 java_hu_ty = consts.java_hu_type_map["String"]
377 fn_ty_arg = "Ljava/lang/String;"
378 if fn_arg.startswith("LDKAddress"):
379 fn_arg = fn_arg[10:].strip()
381 fn_arg = fn_arg[6:].strip()
384 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
385 java_ty = consts.c_type_map['uint32_t'][0]
386 java_hu_ty = "UnqualifiedError"
387 rust_obj = "LDKError"
391 fn_arg = fn_arg[8:].strip()
393 ma = var_ty_regex.match(fn_arg)
394 arr_ty = ma.group(1).strip()
395 if ma.group(1).strip() in unitary_enums:
396 assert ma.group(1).strip().startswith("LDK")
397 java_ty = ma.group(1).strip()[3:]
399 c_ty = consts.unitary_enum_c_ty
400 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
401 fn_arg = ma.group(2).strip()
402 rust_obj = ma.group(1).strip()
404 c_ty = consts.ptr_c_ty
405 java_ty = consts.ptr_native_ty
406 java_hu_ty = ma.group(1).strip()
407 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
408 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
409 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
410 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
411 java_hu_ty = java_hu_ty.replace("LDKC4Tuple", "FourTuple")
412 java_hu_ty = java_hu_ty.replace("LDK", "")
414 fn_arg = ma.group(2).strip()
415 rust_obj = ma.group(1).strip()
416 if rust_obj in trait_structs:
417 contains_trait = True
418 elif rust_obj in complex_enums:
419 contains_trait = complex_enums[rust_obj]
422 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
423 fn_arg = fn_arg.replace("*", "").strip()
425 c_ty = consts.ptr_c_ty
426 java_ty = consts.ptr_native_ty
429 var_is_arr = var_is_arr_regex.match(fn_arg)
431 if var_is_arr is not None or ret_arr_len is not None:
432 assert(not take_by_ptr)
434 # is there a special case for plurals?
435 if len(mapped_type) == 3:
436 java_ty = mapped_type[1]
437 java_hu_ty = mapped_type[2]
439 java_ty = java_ty + "[]"
441 if rust_obj == "LDKU128":
442 java_hu_ty = consts.u128_native_ty
443 c_ty = c_ty + "Array"
445 subty = java_c_types(arr_ty, None)
447 assert java_c_types_none_allowed
450 subty.pass_by_ref = True
452 if var_is_arr is not None:
453 if var_is_arr.group(1) == "":
454 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,
455 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
456 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
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, is_const=is_const,
458 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
459 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
461 if java_hu_ty is None:
463 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,
464 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,
465 contains_trait=contains_trait, subty=subty)
467 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
468 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
469 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
473 from gen_type_mapping import TypeMappingGenerator
474 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
476 with open(sys.argv[1]) as in_h:
478 reg_fn = reg_fn_regex.match(line)
479 if reg_fn is not None:
480 if reg_fn.group(2).endswith("_clone"):
481 clone_fns.add(reg_fn.group(2))
483 rty = java_c_types(reg_fn.group(1), None)
484 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
485 constructor_fns[rty.rust_obj] = reg_fn.group(3)
487 arr_fn = fn_ret_arr_regex.match(line)
488 if arr_fn is not None:
489 if arr_fn.group(2).endswith("_clone"):
490 clone_fns.add(arr_fn.group(2))
491 # No object constructors return arrays, as then they wouldn't be an object constructor
494 # Define some manual clones...
495 clone_fns.add("ThirtyTwoBytes_clone")
496 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")
499 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
500 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
501 write_c("\tif (sizeof(void*) == 4) {\n")
502 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
503 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
504 write_c("\t} else {\n")
505 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
506 write_c("\t\t// use bit 9 ^ bit 10.\n")
507 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
508 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
509 write_c("#ifdef LDK_DEBUG_BUILD\n")
510 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
511 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
512 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
513 write_c("\t\tp ^= 1ULL << 53;\n")
515 write_c("\t\treturn (void*)p;\n")
519 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
520 write_c("\tif(ptr < 4096) return true;\n")
521 write_c("\tif (sizeof(void*) == 4) {\n")
522 write_c("\t\treturn ptr & (1ULL << 32);\n")
523 write_c("\t} else {\n")
524 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
525 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
526 write_c("#ifdef LDK_DEBUG_BUILD\n")
527 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
528 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
529 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
531 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
535 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
536 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
537 write_c("\tif (sizeof(void*) == 4) {\n")
538 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
539 write_c("\t} else {\n")
540 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
541 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
542 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
543 write_c("#ifdef LDK_DEBUG_BUILD\n")
544 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
545 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
546 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
547 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
548 write_c("\t\tt ^= 1ULL << 53;\n")
550 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
551 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
552 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
553 write_c("\t\treturn t;\n")
557 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
559 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
560 util.write(consts.util_fn_pfx)
562 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
563 # Map a top-level function
564 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
565 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
566 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
567 method_return_type = re_match.group(1)
568 method_name = re_match.group(2)
569 method_comma_separated_arguments = re_match.group(3)
570 method_arguments = method_comma_separated_arguments.split(',')
572 if method_name.startswith("__"):
575 is_free = method_name.endswith("_free")
576 if method_name.startswith("COption") or method_name.startswith("CResult"):
577 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
578 expected_struct = "LDKC" + struct_meth
579 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
580 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple") or method_name.startswith("C4Tuple"):
581 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
582 if method_name.startswith("C2Tuple"):
583 struct_meth = "Two" + tuple_name
584 expected_struct = "LDKC2" + tuple_name
585 elif method_name.startswith("C3Tuple"):
586 struct_meth = "Three" + tuple_name
587 expected_struct = "LDKC3" + tuple_name
589 struct_meth = "Four" + tuple_name
590 expected_struct = "LDKC4" + tuple_name
591 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
593 struct_meth = method_name.split("_")[0]
594 expected_struct = "LDK" + struct_meth
595 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
597 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
599 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
601 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
603 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
604 # LDKWitness is mapped as an array, so no need to implement clone
605 if expected_struct == "LDKWitness":
607 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
608 write_c("static inline " + meth_line + " {\n")
609 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
610 write_c(method_name + "(arg)")
611 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
612 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
613 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
616 default_constructor_args = {}
618 takes_self_ptr = False
620 for argument_index, argument in enumerate(method_arguments):
621 arg_ty = type_mapping_generator.java_c_types(argument, None)
622 argument_conversion_info = None
623 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
624 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
626 if argument_conversion_info.ty_info.is_ptr:
627 takes_self_ptr = True
628 elif arg_ty.var_name in params_nullable:
629 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
630 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
631 arg_ty_info = java_c_types(argument, None)
632 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
633 print(" The argument appears to require a move, or not clonable, and is nullable.")
634 print(" Normally for arguments that require a move and are not clonable, we split")
635 print(" the argument into the type's constructor's arguments and just use those to")
636 print(" construct a new object on the fly.")
637 print(" However, because the object is nullable, doing so would mean we can no")
638 print(" longer allow the user to pass null, as we now have an argument list instead.")
639 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
640 print(" It may or may not actually be a reference, but its the simplest mapping option")
641 print(" and also the only use of this code today.")
642 arg_ty_info.requires_clone = False
643 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
644 assert argument_conversion_info.nullable
645 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
647 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
649 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
650 if argument_conversion_info.rust_obj in constructor_fns:
652 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
653 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
654 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
655 continue # (void) is C lingo for "no arguments)
656 if explode_arg_conv.c_ty == "void":
658 if not argument_conversion_info.arg_name in default_constructor_args:
659 default_constructor_args[argument_conversion_info.arg_name] = []
660 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
661 argument_types.append(argument_conversion_info)
663 if not takes_self and return_type_info.java_hu_ty != struct_meth:
664 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
665 struct_meth_name = method_name
669 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
670 expected_struct in complex_enums or expected_struct in complex_enums or
671 expected_struct in result_types or expected_struct in tuple_types) and not is_free
672 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
673 not method_name.startswith("TxOut") and not method_name.startswith("TxIn") and
674 not method_name.startswith("BigEndianScalar") and not method_name.startswith("WitnessProgram") and
675 not method_name.startswith("_") and
676 method_name != "check_platform" and method_name != "Result_read" and
677 not expected_struct in unitary_enums and
678 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_") and not method_name.startswith("C4Tuple_"))
679 or method_name.endswith("_read")))
681 # If we're adding a static method, and it returns a primitive or an array of primitives,
682 # and a variable conversion adds a reference on the return type (via `this`), skip the
683 # variable's conversion reference-add (as we obviously cannot need a reference).
684 if impl_on_utils and (return_type_info.is_native_primitive or
685 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
686 for arg in argument_types:
687 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
688 if "this" in arg.from_hu_conv[1]:
689 arg.from_hu_conv = (arg.from_hu_conv[0], "")
691 out_java.write("\t// " + line)
692 args_known = True # We no longer ever set this to false
693 (out_java_delta, out_c_delta, out_java_struct_delta) = \
694 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)
695 out_java.write(out_java_delta)
698 assert len(argument_types) == 1
699 assert return_type_info.c_ty == "void"
700 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")
701 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
702 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
704 for info in argument_types:
705 if info.arg_conv is not None:
706 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
707 assert c_call_string is None
708 write_c("\t" + method_name + "(")
709 if argument_types[0].arg_conv_name is not None:
710 write_c(argument_types[0].arg_conv_name)
712 for info in argument_types:
713 if info.arg_conv_cleanup is not None:
714 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
719 out_java_struct = None
721 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
722 out_java_struct.write(out_java_struct_delta)
724 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
725 for line in out_java_struct_delta.splitlines():
726 out_java_struct.write(line + "\n")
728 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
729 assert struct_name.startswith("LDK")
730 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
731 unitary_enums.add(struct_name)
732 for idx, (struct_line, _) in enumerate(field_lines):
734 assert(struct_line == "typedef enum %s {" % struct_name)
735 elif idx == len(field_lines) - 3:
736 assert(struct_line.endswith("_Sentinel,"))
737 elif idx == len(field_lines) - 2:
738 assert(struct_line == "} %s;" % struct_name)
739 elif idx == len(field_lines) - 1:
740 assert(struct_line == "")
741 assert struct_name.startswith("LDK")
742 (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)
744 out_java_enum.write(native_file_out)
745 out_java.write(native_out)
747 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
748 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
751 tag_field_lines = union_enum_items["field_lines"]
752 contains_trait = False
753 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
755 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
756 elif idx == len(tag_field_lines) - 3:
757 assert(struct_line.endswith("_Sentinel,"))
758 elif idx == len(tag_field_lines) - 2:
759 assert(struct_line == "} %s_Tag;" % struct_name)
760 elif idx == len(tag_field_lines) - 1:
761 assert(struct_line == "")
763 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
765 if "LDK" + variant_name in union_enum_items:
766 enum_var_lines = union_enum_items["LDK" + variant_name]
767 for idx, (field, field_docs) in enumerate(enum_var_lines):
768 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
769 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
770 contains_trait |= field_ty.contains_trait
771 if field_docs is not None and doc_to_field_nullable(field_docs):
772 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
774 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
775 fields.append((field_conv, field_docs))
776 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
777 elif camel_to_snake(variant_name) in inline_enum_variants:
778 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
779 # docs through to there, and then potentially mark the field nullable.
780 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
781 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
782 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
783 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
784 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
786 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
787 contains_trait |= mapped.ty_info.contains_trait
788 fields.append((mapped, None))
789 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
791 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
792 complex_enums[struct_name] = contains_trait
794 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
795 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
797 out_java_enum.write(out_java_enum_addendum)
798 out_java.write(out_java_addendum)
799 write_c(out_c_addendum)
801 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
802 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
804 flattened_field_var_convs = []
805 for var_line in field_var_lines:
806 if var_line.group(1) in trait_structs:
807 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
808 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), var_line.group(2)))
809 for field_var in trait_structs[var_line.group(1)]:
810 if isinstance(field_var, ConvInfo):
811 flattened_field_var_convs.append(field_var)
813 path = var_line.group(2)
814 if len(field_var) > 2:
815 path = var_line.group(2) + "." + field_var[2]
816 flattened_field_var_convs.append((field_var[0], field_var[1], path))
818 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
819 field_var_convs.append(mapped)
820 flattened_field_var_convs.append(mapped)
821 trait_structs[struct_name] = flattened_field_var_convs
824 for fn_docs, fn_line in trait_fn_lines:
825 if fn_line == "cloned":
826 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
827 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
829 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
831 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
832 ret_ty_info.nullable = True
834 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
835 is_const = fn_line.group(4) is not None
838 for idx, arg in enumerate(fn_line.group(5).split(',')):
841 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
842 if arg_ty_info.var_name in nullable_params:
843 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
844 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
846 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
847 arg_tys.append(arg_conv_info)
848 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
850 (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)
851 write_c(out_c_addendum)
852 out_java_trait.write(out_java_trait_addendum)
853 out_java.write(out_java_addendum)
855 for fn_docs, fn_line in trait_fn_lines:
856 if fn_line == "cloned":
858 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
859 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
860 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
861 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"
862 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)
863 for idx, var_line in enumerate(field_var_lines):
864 if var_line.group(1) not in trait_structs:
865 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
866 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
867 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
868 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
870 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"
871 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)
873 def map_result(struct_name, res_ty, err_ty):
874 result_types.add(struct_name)
875 human_ty = struct_name.replace("LDKCResult", "Result")
876 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
877 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
878 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
879 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
880 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
881 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
882 out_java_struct.write(java_hu_struct)
884 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
885 field_ty = java_c_types(field_decl + " " + field_name, None)
886 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
887 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
890 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
891 fn_defn = owned_fn_defn
892 write_c("static inline " + fn_defn + "{\n")
893 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
894 write_c("\tret.is_owned = false;\n")
895 write_c("\treturn ret;\n")
896 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
897 fn_defn = owned_fn_defn
898 write_c("static inline " + fn_defn + "{\n")
899 if check_sfx is not None:
900 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
901 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
902 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
903 fn_defn = owned_fn_defn
904 write_c("static inline " + fn_defn + "{\n")
905 if check_sfx is not None:
906 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
907 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
910 fn_defn = ptr_fn_defn
911 write_c("static inline " + fn_defn + "{\n")
912 if check_sfx is not None:
913 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
914 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
917 dummy_line = fn_defn + ";\n"
918 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
920 def map_tuple(struct_name, field_lines):
921 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple").replace("LDKC4Tuple", "FourTuple")
922 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
923 out_java_struct.write(consts.map_tuple(struct_name))
925 for idx, (line, _) in enumerate(field_lines):
926 if idx != 0 and idx < len(field_lines) - 2:
927 ty_list.append(java_c_types(line.strip(';'), None))
928 tuple_types[struct_name] = (ty_list, struct_name)
930 # Map virtual getter functions
931 for idx, (line, _) in enumerate(field_lines):
932 if idx != 0 and idx < len(field_lines) - 2:
933 field_name = chr(ord('a') + idx - 1)
934 assert line.endswith(" " + field_name + ";")
935 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
937 out_java.write(consts.bindings_header)
938 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
939 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
941 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
942 out_java_struct.write(consts.common_base)
945 last_block_comment = None
948 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
950 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
951 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
952 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
953 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
954 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
955 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
956 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
957 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
958 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
959 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
960 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
961 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
962 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
963 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
964 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
966 union_enum_items = {}
967 result_ptr_struct_items = {}
969 if block_comment is not None:
970 if line.endswith("*/\n"):
971 last_block_comment = block_comment.strip("\n")
974 block_comment = block_comment + line.strip(" /*")
975 elif cur_block_obj is not None:
976 cur_block_obj = cur_block_obj + line
977 if line.startswith("} "):
981 obj_lines = cur_block_obj.split("\n")
983 result_contents = None
984 is_unitary_enum = False
985 is_union_enum = False
990 last_struct_block_comment = None
992 for idx, struct_line in enumerate(obj_lines):
993 if struct_line.strip().startswith("/*"):
994 block_comment = struct_line.strip(" /*")
995 if block_comment is not None:
996 if struct_line.endswith("*/"):
997 last_struct_block_comment = block_comment.strip("\n")
1000 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
1002 struct_name_match = struct_name_regex.match(struct_line)
1003 if struct_name_match is not None:
1004 struct_name = struct_name_match.group(3)
1005 if struct_name_match.group(1) == "enum":
1006 if not struct_name.endswith("_Tag"):
1007 is_unitary_enum = True
1009 is_union_enum = True
1010 elif struct_name_match.group(1) == "union":
1012 if line_indicates_opaque_regex.match(struct_line):
1014 result_match = line_indicates_result_regex.match(struct_line)
1015 if result_match is not None:
1016 result_contents = result_match.group(1)
1017 vec_ty_match = line_indicates_vec_regex.match(struct_line)
1018 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
1019 vec_ty = vec_ty_match.group(2)
1020 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_") or struct_name.startswith("LDKC4Tuple_"):
1022 trait_fn_match = line_indicates_trait_regex.match(struct_line)
1023 if trait_fn_match is not None:
1024 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
1025 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
1026 if trait_clone_fn_match is not None:
1027 trait_fn_lines.append((last_struct_block_comment, "cloned"))
1028 field_var_match = line_field_var_regex.match(struct_line)
1029 if field_var_match is not None:
1030 field_var_lines.append(field_var_match)
1031 field_lines.append((struct_line, last_struct_block_comment))
1032 last_struct_block_comment = None
1034 assert(struct_name is not None)
1035 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))
1036 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))
1037 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))
1038 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))
1039 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))
1040 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))
1041 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))
1044 opaque_structs.add(struct_name)
1045 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
1046 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
1047 last_block_comment = None
1048 out_java_struct.write(out_opaque_struct_human)
1049 elif result_contents is not None:
1050 assert result_contents in result_ptr_struct_items
1051 res_ty, err_ty = result_ptr_struct_items[result_contents]
1052 map_result(struct_name, res_ty, err_ty)
1053 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1054 for line, _ in field_lines:
1055 if line.endswith("*result;"):
1056 res_ty = line[:-8].strip()
1057 elif line.endswith("*err;"):
1058 err_ty = line[:-5].strip()
1059 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1060 result_types.add(struct_name[:-3])
1062 map_tuple(struct_name, field_lines)
1063 elif vec_ty is not None:
1064 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1065 if ty_info.is_native_primitive:
1066 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1067 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1068 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1069 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1070 write_c("\treturn ret;\n}\n")
1071 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1072 ty_name = struct_name.replace("LDK", "")
1073 clone_fns.add(ty_name + "_clone")
1074 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1075 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1076 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1077 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1078 write_c("\t}\n\treturn ret;\n}\n")
1080 assert(struct_name.endswith("_Tag"))
1081 struct_name = struct_name[:-4]
1082 union_enum_items[struct_name] = {"field_lines": field_lines}
1083 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1084 enum_var_name = struct_name.split("_")
1085 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1086 elif struct_name in union_enum_items:
1089 for line, field_block_comment in field_lines:
1090 if line == " struct {":
1094 elif elem_items > -1:
1096 if line.startswith("struct "):
1098 elif line.startswith("enum "):
1100 split = line.split(" ")
1101 assert len(split) == 2
1102 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1105 # We don't currently support tuple variant with more than one element
1107 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1108 last_block_comment = None
1109 elif is_unitary_enum:
1110 map_unitary_enum(struct_name, field_lines, last_block_comment)
1111 last_block_comment = None
1112 elif len(trait_fn_lines) > 0:
1113 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1114 elif struct_name == "LDKTxOut":
1115 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1116 out_java_struct.write(consts.hu_struct_file_prefix)
1117 out_java_struct.write(consts.txout_defn)
1118 out_java_struct.write(consts.hu_struct_file_suffix)
1119 elif struct_name == "LDKTxIn":
1120 with open(f"{sys.argv[3]}/structs/TxIn{consts.file_ext}", "w") as out_java_struct:
1121 out_java_struct.write(consts.hu_struct_file_prefix)
1122 out_java_struct.write(consts.txin_defn)
1123 out_java_struct.write(consts.hu_struct_file_suffix)
1124 elif struct_name == "LDKBigEndianScalar":
1125 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1126 out_java_struct.write(consts.hu_struct_file_prefix)
1127 out_java_struct.write(consts.scalar_defn)
1128 out_java_struct.write(consts.hu_struct_file_suffix)
1129 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1130 write_c(fn_line + " {\n")
1131 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1132 write_c("\treturn ret;\n")
1134 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1136 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1137 # there's nothing heap-allocated inside it the C bindings don't bother
1138 # exposing a `_free` method. Instead, we have to manually write one here,
1139 # though it doesn't need to do anything, the autogenerated wrapper will do
1140 # the required FREE.
1141 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1142 write_c(fn_line + " {}\n")
1143 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1144 elif struct_name == "LDKWitnessProgram":
1145 with open(f"{sys.argv[3]}/structs/WitnessProgram{consts.file_ext}", "w") as out_java_struct:
1146 out_java_struct.write(consts.hu_struct_file_prefix)
1147 out_java_struct.write(consts.witness_program_defn)
1148 out_java_struct.write(consts.hu_struct_file_suffix)
1150 pass # Everything remaining is a byte[] of some form
1151 cur_block_obj = None
1153 fn_ptr = fn_ptr_regex.match(line)
1154 fn_ret_arr = fn_ret_arr_regex.match(line)
1155 reg_fn = reg_fn_regex.match(line)
1156 const_val = const_val_regex.match(line)
1158 if line.startswith("#include <"):
1160 elif line.startswith("/*"):
1161 if not line.endswith("*/\n"):
1162 block_comment = line.strip(" /*")
1163 elif line.startswith("typedef enum "):
1164 cur_block_obj = line
1165 elif line.startswith("typedef struct "):
1166 cur_block_obj = line
1167 elif line.startswith("typedef union "):
1168 cur_block_obj = line
1169 elif fn_ptr is not None:
1170 map_fn(line, fn_ptr, None, None, last_block_comment)
1171 last_block_comment = None
1172 elif fn_ret_arr is not None:
1173 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1174 last_block_comment = None
1175 elif reg_fn is not None:
1176 map_fn(line, reg_fn, None, None, last_block_comment)
1177 last_block_comment = None
1178 elif const_val_regex is not None:
1179 # TODO Map const variables
1182 assert(line == "\n")
1184 out_java.write(consts.bindings_footer())
1185 for struct_name in opaque_structs:
1186 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1187 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1188 for struct_name in trait_structs:
1189 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1190 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1191 for struct_name in complex_enums:
1192 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1193 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1194 for struct_name in result_types:
1195 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1196 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1197 for struct_name in tuple_types:
1198 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple").replace("LDKC4Tuple", "FourTuple")
1199 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1200 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1202 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1203 out_c.write(consts.c_file_pfx)
1204 out_c.write(consts.init_str())
1206 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1207 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1208 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1209 util.write(consts.util_fn_sfx)