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")
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 elif sys.argv[6] == "typescript":
24 import typescript_strings
25 from typescript_strings import Consts
26 target = typescript_strings.Target.NODEJS
27 if len(sys.argv) == 8 and sys.argv[7] == 'browser':
28 target = typescript_strings.Target.BROWSER
29 elif sys.argv[6] == "c_sharp":
31 from csharp_strings import Consts
32 target = csharp_strings.Target.CSHARP
34 print("Only java, typescript, or c_sharp can be set for lang")
38 consts = Consts(DEBUG, target=target, outdir=sys.argv[4])
40 local_git_version = os.getenv("LDK_GARBAGECOLLECTED_GIT_OVERRIDE")
41 if local_git_version is None:
42 local_git_version = subprocess.check_output(["git", "describe", '--tag', '--dirty']).decode("utf-8").strip()
44 from bindingstypes import *
51 def camel_to_snake(s):
52 # Convert camel case to snake case, in a way that appears to match cbindgen
58 if lastchar.isupper():
59 if not char.isupper() and not lastund:
64 ret = ret + lastchar.lower()
67 if char.isupper() and not lastund:
75 return (ret + lastchar.lower()).strip("_")
77 def doc_to_field_nullable(doc):
80 for line in doc.splitlines():
81 if "Note that this (or a relevant inner pointer) may be NULL or all-0s to represent None" in line:
85 def doc_to_params_ret_nullable(doc):
90 for line in doc.splitlines():
91 if "may be NULL or all-0s to represent None" not in line:
93 if "Note that the return value" in line:
95 elif "Note that " in line:
96 param = line.split("Note that ")[1].split(" ")[0]
98 return (params, ret_null)
100 unitary_enums = set()
101 # Map from enum name to "contains trait object"
103 opaque_structs = set()
108 var_is_arr_regex = re.compile("\(\* ?([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
109 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
110 java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
111 def java_c_types(fn_arg, ret_arr_len):
112 fn_arg = fn_arg.strip()
113 if fn_arg.startswith("MUST_USE_RES "):
116 if fn_arg.startswith("const "):
119 if fn_arg.startswith("struct "):
121 if fn_arg.startswith("enum "):
123 nonnull_ptr = "NONNULL_PTR" in fn_arg
124 fn_arg = fn_arg.replace("NONNULL_PTR", "")
131 if fn_arg.startswith("LDKPaymentPreimage") or fn_arg.startswith("LDKPaymentSecret") or fn_arg.startswith("LDKPaymentHash"):
132 if fn_arg.startswith("LDKPaymentPreimage"):
133 fn_arg = "uint8_t (*" + fn_arg[19:] + ")[32]"
134 elif fn_arg.startswith("LDKPaymentSecret"):
135 fn_arg = "uint8_t (*" + fn_arg[17:] + ")[32]"
136 elif fn_arg.startswith("LDKPaymentHash"):
137 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[32]"
138 assert var_is_arr_regex.match(fn_arg[8:])
139 rust_obj = "LDKThirtyTwoBytes"
141 elif fn_arg.startswith("LDKThirtyTwoBytes"):
142 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
143 assert var_is_arr_regex.match(fn_arg[8:])
144 rust_obj = "LDKThirtyTwoBytes"
146 elif fn_arg.startswith("LDKU128"):
147 if fn_arg == "LDKU128":
148 fn_arg = "LDKU128 arg"
149 if fn_arg.startswith("LDKU128*") or fn_arg.startswith("LDKU128 *"):
150 fn_arg = "uint8_t (" + fn_arg[8:] + ")[16]"
152 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[16]"
153 assert var_is_arr_regex.match(fn_arg[8:])
155 arr_access = "le_bytes"
156 elif fn_arg.startswith("LDKTxid"):
157 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
158 assert var_is_arr_regex.match(fn_arg[8:])
159 rust_obj = "LDKThirtyTwoBytes"
161 elif fn_arg.startswith("LDKPublicKey"):
162 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
163 assert var_is_arr_regex.match(fn_arg[8:])
164 rust_obj = "LDKPublicKey"
165 arr_access = "compressed_form"
166 elif fn_arg.startswith("LDKSecretKey"):
167 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
168 assert var_is_arr_regex.match(fn_arg[8:])
169 rust_obj = "LDKSecretKey"
171 elif fn_arg.startswith("LDKSignature"):
172 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
173 assert var_is_arr_regex.match(fn_arg[8:])
174 rust_obj = "LDKSignature"
175 arr_access = "compact_form"
176 elif fn_arg.startswith("LDKRecoverableSignature"):
177 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
178 assert var_is_arr_regex.match(fn_arg[8:])
179 rust_obj = "LDKRecoverableSignature"
180 arr_access = "serialized_form"
181 elif fn_arg.startswith("LDKThreeBytes"):
182 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
183 assert var_is_arr_regex.match(fn_arg[8:])
184 rust_obj = "LDKThreeBytes"
186 elif fn_arg.startswith("LDKFourBytes"):
187 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
188 assert var_is_arr_regex.match(fn_arg[8:])
189 rust_obj = "LDKFourBytes"
191 elif fn_arg.startswith("LDKSixteenBytes"):
192 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
193 assert var_is_arr_regex.match(fn_arg[8:])
194 rust_obj = "LDKSixteenBytes"
196 elif fn_arg.startswith("LDKTwentyBytes"):
197 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
198 assert var_is_arr_regex.match(fn_arg[8:])
199 rust_obj = "LDKTwentyBytes"
201 elif fn_arg.startswith("LDKTwelveBytes"):
202 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
203 assert var_is_arr_regex.match(fn_arg[8:])
204 rust_obj = "LDKTwelveBytes"
206 elif fn_arg.startswith("LDKu8slice"):
207 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
208 assert var_is_arr_regex.match(fn_arg[8:])
209 rust_obj = "LDKu8slice"
211 elif fn_arg.startswith("LDKCVec_u8Z"):
212 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
213 rust_obj = "LDKCVec_u8Z"
214 assert var_is_arr_regex.match(fn_arg[8:])
216 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
217 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
218 rust_obj = "LDKTransaction"
219 assert var_is_arr_regex.match(fn_arg[8:])
221 elif fn_arg.startswith("LDKWitness ") or fn_arg == "LDKWitness":
222 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
223 rust_obj = "LDKWitness"
224 assert var_is_arr_regex.match(fn_arg[8:])
226 elif fn_arg.startswith("LDKCVec_"):
229 fn_arg = fn_arg.replace("*", "")
232 tyn = fn_arg[8:].split(" ")
233 assert tyn[0].endswith("Z")
237 new_arg = "LDK" + tyn[0][:-1]
239 new_arg = new_arg + " " + a
240 res = java_c_types(new_arg, ret_arr_len)
242 assert java_c_types_none_allowed
245 res.pass_by_ref = True
246 java_ty = consts.java_arr_ty_str(res.java_ty)
247 if res.is_native_primitive or res.passed_as_ptr:
248 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
249 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
250 nonnull_ptr=nonnull_ptr, is_const=is_const,
251 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
253 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
254 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
255 nonnull_ptr=nonnull_ptr, is_const=is_const,
256 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
259 contains_trait = False
262 java_type_plural = None
264 if fn_arg.startswith("void"):
268 fn_arg = fn_arg[4:].strip()
270 elif fn_arg.startswith("bool"):
271 java_ty = consts.c_type_map['bool'][0]
275 fn_arg = fn_arg[4:].strip()
277 elif fn_arg.startswith("uint8_t"):
278 mapped_type = consts.c_type_map['uint8_t']
279 java_ty = mapped_type[0]
283 fn_arg = fn_arg[7:].strip()
285 elif fn_arg.startswith("LDKU5") or fn_arg.startswith("LDKWitnessVersion"):
286 java_ty = consts.c_type_map['uint8_t'][0]
287 if fn_arg.startswith("LDKU5"):
290 fn_arg = fn_arg[6:].strip()
292 java_hu_ty = "WitnessVersion"
293 rust_obj = "LDKWitnessVersion"
294 fn_arg = fn_arg[18:].strip()
298 elif fn_arg.startswith("uint16_t"):
299 mapped_type = consts.c_type_map['uint16_t']
300 java_ty = mapped_type[0]
304 fn_arg = fn_arg[8:].strip()
306 elif fn_arg.startswith("uint32_t"):
307 mapped_type = consts.c_type_map['uint32_t']
308 java_ty = mapped_type[0]
312 fn_arg = fn_arg[8:].strip()
314 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
315 # TODO: uintptr_t is arch-dependent :(
316 mapped_type = consts.c_type_map['uint64_t']
317 java_ty = mapped_type[0]
319 if fn_arg.startswith("uint64_t"):
322 fn_arg = fn_arg[8:].strip()
324 java_ty = consts.usize_native_ty
325 c_ty = consts.usize_c_ty
327 rust_obj = "uintptr_t"
328 fn_arg = fn_arg[9:].strip()
330 elif is_const and fn_arg.startswith("char *"):
331 java_ty = consts.java_type_map["String"]
332 java_hu_ty = consts.java_hu_type_map["String"]
335 fn_ty_arg = "Ljava/lang/String;"
336 fn_arg = fn_arg[6:].strip()
337 elif fn_arg.startswith("LDKStr"):
340 java_ty = consts.java_type_map["String"]
341 java_hu_ty = consts.java_hu_type_map["String"]
343 fn_ty_arg = "Ljava/lang/String;"
344 fn_arg = fn_arg[6:].strip()
347 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
348 java_ty = consts.c_type_map['uint32_t'][0]
349 java_hu_ty = "UnqualifiedError"
350 rust_obj = "LDKError"
354 fn_arg = fn_arg[8:].strip()
356 ma = var_ty_regex.match(fn_arg)
357 arr_ty = ma.group(1).strip()
358 if ma.group(1).strip() in unitary_enums:
359 assert ma.group(1).strip().startswith("LDK")
360 java_ty = ma.group(1).strip()[3:]
362 c_ty = consts.result_c_ty
363 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
364 fn_arg = ma.group(2).strip()
365 rust_obj = ma.group(1).strip()
367 c_ty = consts.ptr_c_ty
368 java_ty = consts.ptr_native_ty
369 java_hu_ty = ma.group(1).strip()
370 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
371 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
372 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
373 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
374 java_hu_ty = java_hu_ty.replace("LDK", "")
376 fn_arg = ma.group(2).strip()
377 rust_obj = ma.group(1).strip()
378 if rust_obj in trait_structs:
379 contains_trait = True
380 elif rust_obj in complex_enums:
381 contains_trait = complex_enums[rust_obj]
384 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
385 fn_arg = fn_arg.replace("*", "").strip()
387 c_ty = consts.ptr_c_ty
388 java_ty = consts.ptr_native_ty
391 var_is_arr = var_is_arr_regex.match(fn_arg)
393 if var_is_arr is not None or ret_arr_len is not None:
394 assert(not take_by_ptr)
396 # is there a special case for plurals?
397 if len(mapped_type) == 3:
398 java_ty = mapped_type[1]
399 java_hu_ty = mapped_type[2]
401 java_ty = java_ty + "[]"
403 if rust_obj == "LDKU128":
404 java_hu_ty = consts.u128_native_ty
405 c_ty = c_ty + "Array"
407 subty = java_c_types(arr_ty, None)
409 assert java_c_types_none_allowed
412 subty.pass_by_ref = True
414 if var_is_arr is not None:
415 if var_is_arr.group(1) == "":
416 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,
417 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
418 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
419 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,
420 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
421 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
423 if java_hu_ty is None:
425 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,
426 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,
427 contains_trait=contains_trait, subty=subty)
429 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
430 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
431 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
435 from gen_type_mapping import TypeMappingGenerator
436 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
438 with open(sys.argv[1]) as in_h:
440 reg_fn = reg_fn_regex.match(line)
441 if reg_fn is not None:
442 if reg_fn.group(2).endswith("_clone"):
443 clone_fns.add(reg_fn.group(2))
445 rty = java_c_types(reg_fn.group(1), None)
446 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
447 constructor_fns[rty.rust_obj] = reg_fn.group(3)
449 arr_fn = fn_ret_arr_regex.match(line)
450 if arr_fn is not None:
451 if arr_fn.group(2).endswith("_clone"):
452 clone_fns.add(arr_fn.group(2))
453 # No object constructors return arrays, as then they wouldn't be an object constructor
456 # Define some manual clones...
457 clone_fns.add("ThirtyTwoBytes_clone")
458 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")
461 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
462 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
463 write_c("\tif (sizeof(void*) == 4) {\n")
464 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
465 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
466 write_c("\t} else {\n")
467 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
468 write_c("\t\t// use bit 9 ^ bit 10.\n")
469 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
470 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
471 write_c("#ifdef LDK_DEBUG_BUILD\n")
472 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
473 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
474 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
475 write_c("\t\tp ^= 1ULL << 53;\n")
477 write_c("\t\treturn (void*)p;\n")
481 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
482 write_c("\tif(ptr < 4096) return true;\n")
483 write_c("\tif (sizeof(void*) == 4) {\n")
484 write_c("\t\treturn ptr & (1ULL << 32);\n")
485 write_c("\t} else {\n")
486 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
487 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
488 write_c("#ifdef LDK_DEBUG_BUILD\n")
489 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
490 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
491 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
493 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
497 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
498 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
499 write_c("\tif (sizeof(void*) == 4) {\n")
500 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
501 write_c("\t} else {\n")
502 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
503 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
504 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
505 write_c("#ifdef LDK_DEBUG_BUILD\n")
506 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
507 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
508 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
509 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
510 write_c("\t\tt ^= 1ULL << 53;\n")
512 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
513 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
514 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
515 write_c("\t\treturn t;\n")
519 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
521 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
522 util.write(consts.util_fn_pfx)
524 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
525 # Map a top-level function
526 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
527 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
528 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
529 method_return_type = re_match.group(1)
530 method_name = re_match.group(2)
531 method_comma_separated_arguments = re_match.group(3)
532 method_arguments = method_comma_separated_arguments.split(',')
534 if method_name.startswith("__"):
537 is_free = method_name.endswith("_free")
538 if method_name.startswith("COption") or method_name.startswith("CResult"):
539 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
540 expected_struct = "LDKC" + struct_meth
541 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
542 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
543 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
544 if method_name.startswith("C2Tuple"):
545 struct_meth = "Two" + tuple_name
546 expected_struct = "LDKC2" + tuple_name
548 struct_meth = "Three" + tuple_name
549 expected_struct = "LDKC3" + tuple_name
550 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
552 struct_meth = method_name.split("_")[0]
553 expected_struct = "LDK" + struct_meth
554 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
556 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
558 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
560 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
562 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
563 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
564 write_c("static inline " + meth_line + " {\n")
565 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
566 write_c(method_name + "(arg)")
567 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
568 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
569 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
572 default_constructor_args = {}
574 takes_self_ptr = False
576 for argument_index, argument in enumerate(method_arguments):
577 arg_ty = type_mapping_generator.java_c_types(argument, None)
578 argument_conversion_info = None
579 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
580 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
582 if argument_conversion_info.ty_info.is_ptr:
583 takes_self_ptr = True
584 elif arg_ty.var_name in params_nullable:
585 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
586 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
587 arg_ty_info = java_c_types(argument, None)
588 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
589 print(" The argument appears to require a move, or not clonable, and is nullable.")
590 print(" Normally for arguments that require a move and are not clonable, we split")
591 print(" the argument into the type's constructor's arguments and just use those to")
592 print(" construct a new object on the fly.")
593 print(" However, because the object is nullable, doing so would mean we can no")
594 print(" longer allow the user to pass null, as we now have an argument list instead.")
595 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
596 print(" It may or may not actually be a reference, but its the simplest mapping option")
597 print(" and also the only use of this code today.")
598 arg_ty_info.requires_clone = False
599 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
600 assert argument_conversion_info.nullable
601 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
603 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
605 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
606 if argument_conversion_info.rust_obj in constructor_fns:
608 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
609 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
610 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
611 continue # (void) is C lingo for "no arguments)
612 if explode_arg_conv.c_ty == "void":
614 if not argument_conversion_info.arg_name in default_constructor_args:
615 default_constructor_args[argument_conversion_info.arg_name] = []
616 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
617 argument_types.append(argument_conversion_info)
619 if not takes_self and return_type_info.java_hu_ty != struct_meth:
620 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
621 struct_meth_name = method_name
625 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
626 expected_struct in complex_enums or expected_struct in complex_enums or
627 expected_struct in result_types or expected_struct in tuple_types) and not is_free
628 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
629 not method_name.startswith("TxOut") and not method_name.startswith("BigEndianScalar") and
630 not method_name.startswith("_") and
631 method_name != "check_platform" and method_name != "Result_read" and
632 not expected_struct in unitary_enums and
633 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
634 or method_name.endswith("_read")))
636 # If we're adding a static method, and it returns a primitive or an array of primitives,
637 # and a variable conversion adds a reference on the return type (via `this`), skip the
638 # variable's conversion reference-add (as we obviously cannot need a reference).
639 if impl_on_utils and (return_type_info.is_native_primitive or
640 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
641 for arg in argument_types:
642 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
643 if "this" in arg.from_hu_conv[1]:
644 arg.from_hu_conv = (arg.from_hu_conv[0], "")
646 out_java.write("\t// " + line)
647 args_known = True # We no longer ever set this to false
648 (out_java_delta, out_c_delta, out_java_struct_delta) = \
649 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)
650 out_java.write(out_java_delta)
653 assert len(argument_types) == 1
654 assert return_type_info.c_ty == "void"
655 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")
656 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
657 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
659 for info in argument_types:
660 if info.arg_conv is not None:
661 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
662 assert c_call_string is None
663 write_c("\t" + method_name + "(")
664 if argument_types[0].arg_conv_name is not None:
665 write_c(argument_types[0].arg_conv_name)
667 for info in argument_types:
668 if info.arg_conv_cleanup is not None:
669 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
674 out_java_struct = None
676 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
677 out_java_struct.write(out_java_struct_delta)
679 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
680 for line in out_java_struct_delta.splitlines():
681 out_java_struct.write(line + "\n")
683 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
684 assert struct_name.startswith("LDK")
685 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
686 unitary_enums.add(struct_name)
687 for idx, (struct_line, _) in enumerate(field_lines):
689 assert(struct_line == "typedef enum %s {" % struct_name)
690 elif idx == len(field_lines) - 3:
691 assert(struct_line.endswith("_Sentinel,"))
692 elif idx == len(field_lines) - 2:
693 assert(struct_line == "} %s;" % struct_name)
694 elif idx == len(field_lines) - 1:
695 assert(struct_line == "")
696 assert struct_name.startswith("LDK")
697 (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)
699 out_java_enum.write(native_file_out)
700 out_java.write(native_out)
702 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
703 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
706 tag_field_lines = union_enum_items["field_lines"]
707 contains_trait = False
708 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
710 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
711 elif idx == len(tag_field_lines) - 3:
712 assert(struct_line.endswith("_Sentinel,"))
713 elif idx == len(tag_field_lines) - 2:
714 assert(struct_line == "} %s_Tag;" % struct_name)
715 elif idx == len(tag_field_lines) - 1:
716 assert(struct_line == "")
718 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
720 if "LDK" + variant_name in union_enum_items:
721 enum_var_lines = union_enum_items["LDK" + variant_name]
722 for idx, (field, field_docs) in enumerate(enum_var_lines):
723 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
724 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
725 contains_trait |= field_ty.contains_trait
726 if field_docs is not None and doc_to_field_nullable(field_docs):
727 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
729 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
730 fields.append((field_conv, field_docs))
731 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
732 elif camel_to_snake(variant_name) in inline_enum_variants:
733 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
734 # docs through to there, and then potentially mark the field nullable.
735 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
736 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
737 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
738 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
739 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
741 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
742 contains_trait |= mapped.ty_info.contains_trait
743 fields.append((mapped, None))
744 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
746 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
747 complex_enums[struct_name] = contains_trait
749 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
750 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
752 out_java_enum.write(out_java_enum_addendum)
753 out_java.write(out_java_addendum)
754 write_c(out_c_addendum)
756 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
757 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
759 flattened_field_var_convs = []
760 for var_line in field_var_lines:
761 if var_line.group(1) in trait_structs:
762 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
763 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
764 flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
766 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
767 field_var_convs.append(mapped)
768 flattened_field_var_convs.append(mapped)
769 trait_structs[struct_name] = field_var_convs
772 for fn_docs, fn_line in trait_fn_lines:
773 if fn_line == "cloned":
774 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
775 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
777 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
779 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
780 ret_ty_info.nullable = True
782 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
783 is_const = fn_line.group(4) is not None
786 for idx, arg in enumerate(fn_line.group(5).split(',')):
789 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
790 if arg_ty_info.var_name in nullable_params:
791 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
792 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
794 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
795 arg_tys.append(arg_conv_info)
796 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
798 (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)
799 write_c(out_c_addendum)
800 out_java_trait.write(out_java_trait_addendum)
801 out_java.write(out_java_addendum)
803 for fn_docs, fn_line in trait_fn_lines:
804 if fn_line == "cloned":
806 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
807 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
808 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
809 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"
810 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)
811 for idx, var_line in enumerate(field_var_lines):
812 if var_line.group(1) not in trait_structs:
813 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
814 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
815 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
816 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
818 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"
819 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)
821 def map_result(struct_name, res_ty, err_ty):
822 result_types.add(struct_name)
823 human_ty = struct_name.replace("LDKCResult", "Result")
824 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
825 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
826 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
827 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
828 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
829 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
830 out_java_struct.write(java_hu_struct)
832 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
833 field_ty = java_c_types(field_decl + " " + field_name, None)
834 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
835 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
838 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
839 fn_defn = owned_fn_defn
840 write_c("static inline " + fn_defn + "{\n")
841 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
842 write_c("\tret.is_owned = false;\n")
843 write_c("\treturn ret;\n")
844 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
845 fn_defn = owned_fn_defn
846 write_c("static inline " + fn_defn + "{\n")
847 if check_sfx is not None:
848 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
849 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
850 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
851 fn_defn = owned_fn_defn
852 write_c("static inline " + fn_defn + "{\n")
853 if check_sfx is not None:
854 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
855 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
858 fn_defn = ptr_fn_defn
859 write_c("static inline " + fn_defn + "{\n")
860 if check_sfx is not None:
861 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
862 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
865 dummy_line = fn_defn + ";\n"
866 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
868 def map_tuple(struct_name, field_lines):
869 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
870 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
871 out_java_struct.write(consts.map_tuple(struct_name))
873 for idx, (line, _) in enumerate(field_lines):
874 if idx != 0 and idx < len(field_lines) - 2:
875 ty_list.append(java_c_types(line.strip(';'), None))
876 tuple_types[struct_name] = (ty_list, struct_name)
878 # Map virtual getter functions
879 for idx, (line, _) in enumerate(field_lines):
880 if idx != 0 and idx < len(field_lines) - 2:
881 field_name = chr(ord('a') + idx - 1)
882 assert line.endswith(" " + field_name + ";")
883 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
885 out_java.write(consts.bindings_header)
886 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
887 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
889 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
890 out_java_struct.write(consts.common_base)
893 last_block_comment = None
896 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
898 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
899 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
900 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
901 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
902 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
903 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
904 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
905 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
906 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
907 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
908 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
909 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
910 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
911 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
912 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
914 union_enum_items = {}
915 result_ptr_struct_items = {}
917 if block_comment is not None:
918 if line.endswith("*/\n"):
919 last_block_comment = block_comment.strip("\n")
922 block_comment = block_comment + line.strip(" /*")
923 elif cur_block_obj is not None:
924 cur_block_obj = cur_block_obj + line
925 if line.startswith("} "):
929 obj_lines = cur_block_obj.split("\n")
931 result_contents = None
932 is_unitary_enum = False
933 is_union_enum = False
938 last_struct_block_comment = None
940 for idx, struct_line in enumerate(obj_lines):
941 if struct_line.strip().startswith("/*"):
942 block_comment = struct_line.strip(" /*")
943 if block_comment is not None:
944 if struct_line.endswith("*/"):
945 last_struct_block_comment = block_comment.strip("\n")
948 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
950 struct_name_match = struct_name_regex.match(struct_line)
951 if struct_name_match is not None:
952 struct_name = struct_name_match.group(3)
953 if struct_name_match.group(1) == "enum":
954 if not struct_name.endswith("_Tag"):
955 is_unitary_enum = True
958 elif struct_name_match.group(1) == "union":
960 if line_indicates_opaque_regex.match(struct_line):
962 result_match = line_indicates_result_regex.match(struct_line)
963 if result_match is not None:
964 result_contents = result_match.group(1)
965 vec_ty_match = line_indicates_vec_regex.match(struct_line)
966 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
967 vec_ty = vec_ty_match.group(2)
968 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
970 trait_fn_match = line_indicates_trait_regex.match(struct_line)
971 if trait_fn_match is not None:
972 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
973 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
974 if trait_clone_fn_match is not None:
975 trait_fn_lines.append((last_struct_block_comment, "cloned"))
976 field_var_match = line_field_var_regex.match(struct_line)
977 if field_var_match is not None:
978 field_var_lines.append(field_var_match)
979 field_lines.append((struct_line, last_struct_block_comment))
980 last_struct_block_comment = None
982 assert(struct_name is not None)
983 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))
984 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))
985 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))
986 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))
987 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))
988 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))
989 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))
992 opaque_structs.add(struct_name)
993 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
994 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
995 last_block_comment = None
996 out_java_struct.write(out_opaque_struct_human)
997 elif result_contents is not None:
998 assert result_contents in result_ptr_struct_items
999 res_ty, err_ty = result_ptr_struct_items[result_contents]
1000 map_result(struct_name, res_ty, err_ty)
1001 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1002 for line, _ in field_lines:
1003 if line.endswith("*result;"):
1004 res_ty = line[:-8].strip()
1005 elif line.endswith("*err;"):
1006 err_ty = line[:-5].strip()
1007 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1008 result_types.add(struct_name[:-3])
1010 map_tuple(struct_name, field_lines)
1011 elif vec_ty is not None:
1012 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1013 if ty_info.is_native_primitive:
1014 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1015 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1016 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1017 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1018 write_c("\treturn ret;\n}\n")
1019 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1020 ty_name = struct_name.replace("LDK", "")
1021 clone_fns.add(ty_name + "_clone")
1022 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1023 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1024 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1025 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1026 write_c("\t}\n\treturn ret;\n}\n")
1028 assert(struct_name.endswith("_Tag"))
1029 struct_name = struct_name[:-4]
1030 union_enum_items[struct_name] = {"field_lines": field_lines}
1031 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1032 enum_var_name = struct_name.split("_")
1033 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1034 elif struct_name in union_enum_items:
1037 for line, field_block_comment in field_lines:
1038 if line == " struct {":
1042 elif elem_items > -1:
1044 if line.startswith("struct "):
1046 elif line.startswith("enum "):
1048 split = line.split(" ")
1049 assert len(split) == 2
1050 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1053 # We don't currently support tuple variant with more than one element
1055 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1056 last_block_comment = None
1057 elif is_unitary_enum:
1058 map_unitary_enum(struct_name, field_lines, last_block_comment)
1059 last_block_comment = None
1060 elif len(trait_fn_lines) > 0:
1061 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1062 elif struct_name == "LDKTxOut":
1063 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1064 out_java_struct.write(consts.hu_struct_file_prefix)
1065 out_java_struct.write(consts.txout_defn)
1066 out_java_struct.write(consts.hu_struct_file_suffix)
1067 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1068 write_c(fn_line + " {")
1069 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1071 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1072 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1073 write_c(fn_line + " {")
1074 write_c("\treturn thing->value;")
1076 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1077 elif struct_name == "LDKBigEndianScalar":
1078 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1079 out_java_struct.write(consts.hu_struct_file_prefix)
1080 out_java_struct.write(consts.scalar_defn)
1081 out_java_struct.write(consts.hu_struct_file_suffix)
1082 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1083 write_c(fn_line + " {\n")
1084 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1085 write_c("\treturn ret;\n")
1087 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1089 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1090 # there's nothing heap-allocated inside it the C bindings don't bother
1091 # exposing a `_free` method. Instead, we have to manually write one here,
1092 # though it doesn't need to do anything, the autogenerated wrapper will do
1093 # the required FREE.
1094 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1095 write_c(fn_line + " {}\n")
1096 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1098 pass # Everything remaining is a byte[] of some form
1099 cur_block_obj = None
1101 fn_ptr = fn_ptr_regex.match(line)
1102 fn_ret_arr = fn_ret_arr_regex.match(line)
1103 reg_fn = reg_fn_regex.match(line)
1104 const_val = const_val_regex.match(line)
1106 if line.startswith("#include <"):
1108 elif line.startswith("/*"):
1109 if not line.endswith("*/\n"):
1110 block_comment = line.strip(" /*")
1111 elif line.startswith("typedef enum "):
1112 cur_block_obj = line
1113 elif line.startswith("typedef struct "):
1114 cur_block_obj = line
1115 elif line.startswith("typedef union "):
1116 cur_block_obj = line
1117 elif fn_ptr is not None:
1118 map_fn(line, fn_ptr, None, None, last_block_comment)
1119 last_block_comment = None
1120 elif fn_ret_arr is not None:
1121 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1122 last_block_comment = None
1123 elif reg_fn is not None:
1124 map_fn(line, reg_fn, None, None, last_block_comment)
1125 last_block_comment = None
1126 elif const_val_regex is not None:
1127 # TODO Map const variables
1130 assert(line == "\n")
1132 out_java.write(consts.bindings_footer())
1133 for struct_name in opaque_structs:
1134 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1135 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1136 for struct_name in trait_structs:
1137 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1138 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1139 for struct_name in complex_enums:
1140 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1141 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1142 for struct_name in result_types:
1143 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1144 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1145 for struct_name in tuple_types:
1146 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1147 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1148 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1150 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1151 out_c.write(consts.c_file_pfx)
1152 out_c.write(consts.init_str())
1154 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1155 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1156 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1157 util.write(consts.util_fn_sfx)