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("LDKEightU16s"):
147 fn_arg = "uint16_t (*" + fn_arg[13:] + ")[8]"
148 assert var_is_arr_regex.match(fn_arg[9:])
149 rust_obj = "LDKEightU16s"
151 elif fn_arg.startswith("LDKU128"):
152 if fn_arg == "LDKU128":
153 fn_arg = "LDKU128 arg"
154 if fn_arg.startswith("LDKU128*") or fn_arg.startswith("LDKU128 *"):
155 fn_arg = "uint8_t (" + fn_arg[8:] + ")[16]"
157 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[16]"
158 assert var_is_arr_regex.match(fn_arg[8:])
160 arr_access = "le_bytes"
161 elif fn_arg.startswith("LDKTxid"):
162 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
163 assert var_is_arr_regex.match(fn_arg[8:])
164 rust_obj = "LDKThirtyTwoBytes"
166 elif fn_arg.startswith("LDKPublicKey"):
167 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
168 assert var_is_arr_regex.match(fn_arg[8:])
169 rust_obj = "LDKPublicKey"
170 arr_access = "compressed_form"
171 elif fn_arg.startswith("LDKSecretKey"):
172 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
173 assert var_is_arr_regex.match(fn_arg[8:])
174 rust_obj = "LDKSecretKey"
176 elif fn_arg.startswith("LDKSignature"):
177 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
178 assert var_is_arr_regex.match(fn_arg[8:])
179 rust_obj = "LDKSignature"
180 arr_access = "compact_form"
181 elif fn_arg.startswith("LDKRecoverableSignature"):
182 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
183 assert var_is_arr_regex.match(fn_arg[8:])
184 rust_obj = "LDKRecoverableSignature"
185 arr_access = "serialized_form"
186 elif fn_arg.startswith("LDKThreeBytes"):
187 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
188 assert var_is_arr_regex.match(fn_arg[8:])
189 rust_obj = "LDKThreeBytes"
191 elif fn_arg.startswith("LDKFourBytes"):
192 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
193 assert var_is_arr_regex.match(fn_arg[8:])
194 rust_obj = "LDKFourBytes"
196 elif fn_arg.startswith("LDKSixteenBytes"):
197 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
198 assert var_is_arr_regex.match(fn_arg[8:])
199 rust_obj = "LDKSixteenBytes"
201 elif fn_arg.startswith("LDKTwentyBytes"):
202 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
203 assert var_is_arr_regex.match(fn_arg[8:])
204 rust_obj = "LDKTwentyBytes"
206 elif fn_arg.startswith("LDKTwelveBytes"):
207 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
208 assert var_is_arr_regex.match(fn_arg[8:])
209 rust_obj = "LDKTwelveBytes"
211 elif fn_arg.startswith("LDKu8slice"):
212 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
213 assert var_is_arr_regex.match(fn_arg[8:])
214 rust_obj = "LDKu8slice"
216 elif fn_arg.startswith("LDKCVec_u8Z"):
217 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
218 rust_obj = "LDKCVec_u8Z"
219 assert var_is_arr_regex.match(fn_arg[8:])
221 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
222 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
223 rust_obj = "LDKTransaction"
224 assert var_is_arr_regex.match(fn_arg[8:])
226 elif fn_arg.startswith("LDKWitness ") or fn_arg == "LDKWitness":
227 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
228 rust_obj = "LDKWitness"
229 assert var_is_arr_regex.match(fn_arg[8:])
231 elif fn_arg.startswith("LDKCVec_"):
234 fn_arg = fn_arg.replace("*", "")
237 tyn = fn_arg[8:].split(" ")
238 assert tyn[0].endswith("Z")
242 new_arg = "LDK" + tyn[0][:-1]
244 new_arg = new_arg + " " + a
245 res = java_c_types(new_arg, ret_arr_len)
247 assert java_c_types_none_allowed
250 res.pass_by_ref = True
251 java_ty = consts.java_arr_ty_str(res.java_ty)
252 if res.is_native_primitive or res.passed_as_ptr:
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=res.c_ty + "Array", 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)
258 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
259 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
260 nonnull_ptr=nonnull_ptr, is_const=is_const,
261 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
264 contains_trait = False
267 java_type_plural = None
269 if fn_arg.startswith("void"):
273 fn_arg = fn_arg[4:].strip()
275 elif fn_arg.startswith("bool"):
276 java_ty = consts.c_type_map['bool'][0]
280 fn_arg = fn_arg[4:].strip()
282 elif fn_arg.startswith("uint8_t"):
283 mapped_type = consts.c_type_map['uint8_t']
284 java_ty = mapped_type[0]
288 fn_arg = fn_arg[7:].strip()
290 elif fn_arg.startswith("LDKU5") or fn_arg.startswith("LDKWitnessVersion"):
291 java_ty = consts.c_type_map['uint8_t'][0]
292 if fn_arg.startswith("LDKU5"):
295 fn_arg = fn_arg[6:].strip()
297 java_hu_ty = "WitnessVersion"
298 rust_obj = "LDKWitnessVersion"
299 fn_arg = fn_arg[18:].strip()
303 elif fn_arg.startswith("uint16_t"):
304 mapped_type = consts.c_type_map['uint16_t']
305 java_ty = mapped_type[0]
309 fn_arg = fn_arg[8:].strip()
311 elif fn_arg.startswith("uint32_t"):
312 mapped_type = consts.c_type_map['uint32_t']
313 java_ty = mapped_type[0]
317 fn_arg = fn_arg[8:].strip()
319 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
320 # TODO: uintptr_t is arch-dependent :(
321 mapped_type = consts.c_type_map['uint64_t']
322 java_ty = mapped_type[0]
324 if fn_arg.startswith("uint64_t"):
327 fn_arg = fn_arg[8:].strip()
329 java_ty = consts.usize_native_ty
330 c_ty = consts.usize_c_ty
332 rust_obj = "uintptr_t"
333 fn_arg = fn_arg[9:].strip()
335 elif is_const and fn_arg.startswith("char *"):
336 java_ty = consts.java_type_map["String"]
337 java_hu_ty = consts.java_hu_type_map["String"]
340 fn_ty_arg = "Ljava/lang/String;"
341 fn_arg = fn_arg[6:].strip()
342 elif fn_arg.startswith("LDKStr"):
345 java_ty = consts.java_type_map["String"]
346 java_hu_ty = consts.java_hu_type_map["String"]
348 fn_ty_arg = "Ljava/lang/String;"
349 fn_arg = fn_arg[6:].strip()
352 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
353 java_ty = consts.c_type_map['uint32_t'][0]
354 java_hu_ty = "UnqualifiedError"
355 rust_obj = "LDKError"
359 fn_arg = fn_arg[8:].strip()
361 ma = var_ty_regex.match(fn_arg)
362 arr_ty = ma.group(1).strip()
363 if ma.group(1).strip() in unitary_enums:
364 assert ma.group(1).strip().startswith("LDK")
365 java_ty = ma.group(1).strip()[3:]
367 c_ty = consts.result_c_ty
368 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
369 fn_arg = ma.group(2).strip()
370 rust_obj = ma.group(1).strip()
372 c_ty = consts.ptr_c_ty
373 java_ty = consts.ptr_native_ty
374 java_hu_ty = ma.group(1).strip()
375 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
376 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
377 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
378 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
379 java_hu_ty = java_hu_ty.replace("LDK", "")
381 fn_arg = ma.group(2).strip()
382 rust_obj = ma.group(1).strip()
383 if rust_obj in trait_structs:
384 contains_trait = True
385 elif rust_obj in complex_enums:
386 contains_trait = complex_enums[rust_obj]
389 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
390 fn_arg = fn_arg.replace("*", "").strip()
392 c_ty = consts.ptr_c_ty
393 java_ty = consts.ptr_native_ty
396 var_is_arr = var_is_arr_regex.match(fn_arg)
398 if var_is_arr is not None or ret_arr_len is not None:
399 assert(not take_by_ptr)
401 # is there a special case for plurals?
402 if len(mapped_type) == 3:
403 java_ty = mapped_type[1]
404 java_hu_ty = mapped_type[2]
406 java_ty = java_ty + "[]"
408 if rust_obj == "LDKU128":
409 java_hu_ty = consts.u128_native_ty
410 c_ty = c_ty + "Array"
412 subty = java_c_types(arr_ty, None)
414 assert java_c_types_none_allowed
417 subty.pass_by_ref = True
419 if var_is_arr is not None:
420 if var_is_arr.group(1) == "":
421 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,
422 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
423 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
424 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,
425 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
426 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
428 if java_hu_ty is None:
430 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,
431 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,
432 contains_trait=contains_trait, subty=subty)
434 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
435 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
436 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
440 from gen_type_mapping import TypeMappingGenerator
441 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
443 with open(sys.argv[1]) as in_h:
445 reg_fn = reg_fn_regex.match(line)
446 if reg_fn is not None:
447 if reg_fn.group(2).endswith("_clone"):
448 clone_fns.add(reg_fn.group(2))
450 rty = java_c_types(reg_fn.group(1), None)
451 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
452 constructor_fns[rty.rust_obj] = reg_fn.group(3)
454 arr_fn = fn_ret_arr_regex.match(line)
455 if arr_fn is not None:
456 if arr_fn.group(2).endswith("_clone"):
457 clone_fns.add(arr_fn.group(2))
458 # No object constructors return arrays, as then they wouldn't be an object constructor
461 # Define some manual clones...
462 clone_fns.add("ThirtyTwoBytes_clone")
463 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")
466 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
467 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
468 write_c("\tif (sizeof(void*) == 4) {\n")
469 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
470 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
471 write_c("\t} else {\n")
472 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
473 write_c("\t\t// use bit 9 ^ bit 10.\n")
474 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
475 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
476 write_c("#ifdef LDK_DEBUG_BUILD\n")
477 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
478 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
479 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
480 write_c("\t\tp ^= 1ULL << 53;\n")
482 write_c("\t\treturn (void*)p;\n")
486 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
487 write_c("\tif(ptr < 4096) return true;\n")
488 write_c("\tif (sizeof(void*) == 4) {\n")
489 write_c("\t\treturn ptr & (1ULL << 32);\n")
490 write_c("\t} else {\n")
491 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
492 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
493 write_c("#ifdef LDK_DEBUG_BUILD\n")
494 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
495 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
496 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
498 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
502 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
503 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
504 write_c("\tif (sizeof(void*) == 4) {\n")
505 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
506 write_c("\t} else {\n")
507 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
508 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
509 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
510 write_c("#ifdef LDK_DEBUG_BUILD\n")
511 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
512 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
513 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
514 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
515 write_c("\t\tt ^= 1ULL << 53;\n")
517 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
518 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
519 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
520 write_c("\t\treturn t;\n")
524 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
526 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
527 util.write(consts.util_fn_pfx)
529 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
530 # Map a top-level function
531 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
532 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
533 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
534 method_return_type = re_match.group(1)
535 method_name = re_match.group(2)
536 method_comma_separated_arguments = re_match.group(3)
537 method_arguments = method_comma_separated_arguments.split(',')
539 if method_name.startswith("__"):
542 is_free = method_name.endswith("_free")
543 if method_name.startswith("COption") or method_name.startswith("CResult"):
544 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
545 expected_struct = "LDKC" + struct_meth
546 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
547 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
548 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
549 if method_name.startswith("C2Tuple"):
550 struct_meth = "Two" + tuple_name
551 expected_struct = "LDKC2" + tuple_name
553 struct_meth = "Three" + tuple_name
554 expected_struct = "LDKC3" + tuple_name
555 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
557 struct_meth = method_name.split("_")[0]
558 expected_struct = "LDK" + struct_meth
559 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
561 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
563 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
565 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
567 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
568 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
569 write_c("static inline " + meth_line + " {\n")
570 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
571 write_c(method_name + "(arg)")
572 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
573 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
574 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
577 default_constructor_args = {}
579 takes_self_ptr = False
581 for argument_index, argument in enumerate(method_arguments):
582 arg_ty = type_mapping_generator.java_c_types(argument, None)
583 argument_conversion_info = None
584 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
585 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
587 if argument_conversion_info.ty_info.is_ptr:
588 takes_self_ptr = True
589 elif arg_ty.var_name in params_nullable:
590 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
591 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
592 arg_ty_info = java_c_types(argument, None)
593 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
594 print(" The argument appears to require a move, or not clonable, and is nullable.")
595 print(" Normally for arguments that require a move and are not clonable, we split")
596 print(" the argument into the type's constructor's arguments and just use those to")
597 print(" construct a new object on the fly.")
598 print(" However, because the object is nullable, doing so would mean we can no")
599 print(" longer allow the user to pass null, as we now have an argument list instead.")
600 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
601 print(" It may or may not actually be a reference, but its the simplest mapping option")
602 print(" and also the only use of this code today.")
603 arg_ty_info.requires_clone = False
604 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
605 assert argument_conversion_info.nullable
606 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
608 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
610 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
611 if argument_conversion_info.rust_obj in constructor_fns:
613 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
614 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
615 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
616 continue # (void) is C lingo for "no arguments)
617 if explode_arg_conv.c_ty == "void":
619 if not argument_conversion_info.arg_name in default_constructor_args:
620 default_constructor_args[argument_conversion_info.arg_name] = []
621 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
622 argument_types.append(argument_conversion_info)
624 if not takes_self and return_type_info.java_hu_ty != struct_meth:
625 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
626 struct_meth_name = method_name
630 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
631 expected_struct in complex_enums or expected_struct in complex_enums or
632 expected_struct in result_types or expected_struct in tuple_types) and not is_free
633 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
634 not method_name.startswith("TxOut") and not method_name.startswith("BigEndianScalar") and
635 not method_name.startswith("_") and
636 method_name != "check_platform" and method_name != "Result_read" and
637 not expected_struct in unitary_enums and
638 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
639 or method_name.endswith("_read")))
641 # If we're adding a static method, and it returns a primitive or an array of primitives,
642 # and a variable conversion adds a reference on the return type (via `this`), skip the
643 # variable's conversion reference-add (as we obviously cannot need a reference).
644 if impl_on_utils and (return_type_info.is_native_primitive or
645 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
646 for arg in argument_types:
647 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
648 if "this" in arg.from_hu_conv[1]:
649 arg.from_hu_conv = (arg.from_hu_conv[0], "")
651 out_java.write("\t// " + line)
652 args_known = True # We no longer ever set this to false
653 (out_java_delta, out_c_delta, out_java_struct_delta) = \
654 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)
655 out_java.write(out_java_delta)
658 assert len(argument_types) == 1
659 assert return_type_info.c_ty == "void"
660 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")
661 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
662 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
664 for info in argument_types:
665 if info.arg_conv is not None:
666 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
667 assert c_call_string is None
668 write_c("\t" + method_name + "(")
669 if argument_types[0].arg_conv_name is not None:
670 write_c(argument_types[0].arg_conv_name)
672 for info in argument_types:
673 if info.arg_conv_cleanup is not None:
674 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
679 out_java_struct = None
681 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
682 out_java_struct.write(out_java_struct_delta)
684 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
685 for line in out_java_struct_delta.splitlines():
686 out_java_struct.write(line + "\n")
688 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
689 assert struct_name.startswith("LDK")
690 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
691 unitary_enums.add(struct_name)
692 for idx, (struct_line, _) in enumerate(field_lines):
694 assert(struct_line == "typedef enum %s {" % struct_name)
695 elif idx == len(field_lines) - 3:
696 assert(struct_line.endswith("_Sentinel,"))
697 elif idx == len(field_lines) - 2:
698 assert(struct_line == "} %s;" % struct_name)
699 elif idx == len(field_lines) - 1:
700 assert(struct_line == "")
701 assert struct_name.startswith("LDK")
702 (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)
704 out_java_enum.write(native_file_out)
705 out_java.write(native_out)
707 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
708 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
711 tag_field_lines = union_enum_items["field_lines"]
712 contains_trait = False
713 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
715 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
716 elif idx == len(tag_field_lines) - 3:
717 assert(struct_line.endswith("_Sentinel,"))
718 elif idx == len(tag_field_lines) - 2:
719 assert(struct_line == "} %s_Tag;" % struct_name)
720 elif idx == len(tag_field_lines) - 1:
721 assert(struct_line == "")
723 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
725 if "LDK" + variant_name in union_enum_items:
726 enum_var_lines = union_enum_items["LDK" + variant_name]
727 for idx, (field, field_docs) in enumerate(enum_var_lines):
728 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
729 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
730 contains_trait |= field_ty.contains_trait
731 if field_docs is not None and doc_to_field_nullable(field_docs):
732 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
734 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
735 fields.append((field_conv, field_docs))
736 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
737 elif camel_to_snake(variant_name) in inline_enum_variants:
738 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
739 # docs through to there, and then potentially mark the field nullable.
740 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
741 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
742 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
743 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
744 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
746 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
747 contains_trait |= mapped.ty_info.contains_trait
748 fields.append((mapped, None))
749 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
751 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
752 complex_enums[struct_name] = contains_trait
754 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
755 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
757 out_java_enum.write(out_java_enum_addendum)
758 out_java.write(out_java_addendum)
759 write_c(out_c_addendum)
761 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
762 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
764 flattened_field_var_convs = []
765 for var_line in field_var_lines:
766 if var_line.group(1) in trait_structs:
767 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
768 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), var_line.group(2)))
769 for field_var in trait_structs[var_line.group(1)]:
770 if isinstance(field_var, ConvInfo):
771 flattened_field_var_convs.append(field_var)
773 path = var_line.group(2)
774 if len(field_var) > 2:
775 path = var_line.group(2) + "." + field_var[2]
776 flattened_field_var_convs.append((field_var[0], field_var[1], path))
778 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
779 field_var_convs.append(mapped)
780 flattened_field_var_convs.append(mapped)
781 trait_structs[struct_name] = flattened_field_var_convs
784 for fn_docs, fn_line in trait_fn_lines:
785 if fn_line == "cloned":
786 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
787 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
789 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
791 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
792 ret_ty_info.nullable = True
794 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
795 is_const = fn_line.group(4) is not None
798 for idx, arg in enumerate(fn_line.group(5).split(',')):
801 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
802 if arg_ty_info.var_name in nullable_params:
803 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
804 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
806 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
807 arg_tys.append(arg_conv_info)
808 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
810 (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)
811 write_c(out_c_addendum)
812 out_java_trait.write(out_java_trait_addendum)
813 out_java.write(out_java_addendum)
815 for fn_docs, fn_line in trait_fn_lines:
816 if fn_line == "cloned":
818 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
819 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
820 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
821 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"
822 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)
823 for idx, var_line in enumerate(field_var_lines):
824 if var_line.group(1) not in trait_structs:
825 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
826 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
827 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
828 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
830 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"
831 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)
833 def map_result(struct_name, res_ty, err_ty):
834 result_types.add(struct_name)
835 human_ty = struct_name.replace("LDKCResult", "Result")
836 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
837 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
838 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
839 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
840 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
841 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
842 out_java_struct.write(java_hu_struct)
844 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
845 field_ty = java_c_types(field_decl + " " + field_name, None)
846 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
847 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
850 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
851 fn_defn = owned_fn_defn
852 write_c("static inline " + fn_defn + "{\n")
853 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
854 write_c("\tret.is_owned = false;\n")
855 write_c("\treturn ret;\n")
856 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
857 fn_defn = owned_fn_defn
858 write_c("static inline " + fn_defn + "{\n")
859 if check_sfx is not None:
860 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
861 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
862 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
863 fn_defn = owned_fn_defn
864 write_c("static inline " + fn_defn + "{\n")
865 if check_sfx is not None:
866 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
867 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
870 fn_defn = ptr_fn_defn
871 write_c("static inline " + fn_defn + "{\n")
872 if check_sfx is not None:
873 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
874 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
877 dummy_line = fn_defn + ";\n"
878 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
880 def map_tuple(struct_name, field_lines):
881 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
882 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
883 out_java_struct.write(consts.map_tuple(struct_name))
885 for idx, (line, _) in enumerate(field_lines):
886 if idx != 0 and idx < len(field_lines) - 2:
887 ty_list.append(java_c_types(line.strip(';'), None))
888 tuple_types[struct_name] = (ty_list, struct_name)
890 # Map virtual getter functions
891 for idx, (line, _) in enumerate(field_lines):
892 if idx != 0 and idx < len(field_lines) - 2:
893 field_name = chr(ord('a') + idx - 1)
894 assert line.endswith(" " + field_name + ";")
895 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
897 out_java.write(consts.bindings_header)
898 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
899 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
901 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
902 out_java_struct.write(consts.common_base)
905 last_block_comment = None
908 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
910 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
911 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
912 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
913 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
914 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
915 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
916 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
917 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
918 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
919 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
920 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
921 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
922 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
923 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
924 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
926 union_enum_items = {}
927 result_ptr_struct_items = {}
929 if block_comment is not None:
930 if line.endswith("*/\n"):
931 last_block_comment = block_comment.strip("\n")
934 block_comment = block_comment + line.strip(" /*")
935 elif cur_block_obj is not None:
936 cur_block_obj = cur_block_obj + line
937 if line.startswith("} "):
941 obj_lines = cur_block_obj.split("\n")
943 result_contents = None
944 is_unitary_enum = False
945 is_union_enum = False
950 last_struct_block_comment = None
952 for idx, struct_line in enumerate(obj_lines):
953 if struct_line.strip().startswith("/*"):
954 block_comment = struct_line.strip(" /*")
955 if block_comment is not None:
956 if struct_line.endswith("*/"):
957 last_struct_block_comment = block_comment.strip("\n")
960 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
962 struct_name_match = struct_name_regex.match(struct_line)
963 if struct_name_match is not None:
964 struct_name = struct_name_match.group(3)
965 if struct_name_match.group(1) == "enum":
966 if not struct_name.endswith("_Tag"):
967 is_unitary_enum = True
970 elif struct_name_match.group(1) == "union":
972 if line_indicates_opaque_regex.match(struct_line):
974 result_match = line_indicates_result_regex.match(struct_line)
975 if result_match is not None:
976 result_contents = result_match.group(1)
977 vec_ty_match = line_indicates_vec_regex.match(struct_line)
978 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
979 vec_ty = vec_ty_match.group(2)
980 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
982 trait_fn_match = line_indicates_trait_regex.match(struct_line)
983 if trait_fn_match is not None:
984 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
985 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
986 if trait_clone_fn_match is not None:
987 trait_fn_lines.append((last_struct_block_comment, "cloned"))
988 field_var_match = line_field_var_regex.match(struct_line)
989 if field_var_match is not None:
990 field_var_lines.append(field_var_match)
991 field_lines.append((struct_line, last_struct_block_comment))
992 last_struct_block_comment = None
994 assert(struct_name is not None)
995 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))
996 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))
997 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))
998 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))
999 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))
1000 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))
1001 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))
1004 opaque_structs.add(struct_name)
1005 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
1006 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
1007 last_block_comment = None
1008 out_java_struct.write(out_opaque_struct_human)
1009 elif result_contents is not None:
1010 assert result_contents in result_ptr_struct_items
1011 res_ty, err_ty = result_ptr_struct_items[result_contents]
1012 map_result(struct_name, res_ty, err_ty)
1013 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1014 for line, _ in field_lines:
1015 if line.endswith("*result;"):
1016 res_ty = line[:-8].strip()
1017 elif line.endswith("*err;"):
1018 err_ty = line[:-5].strip()
1019 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1020 result_types.add(struct_name[:-3])
1022 map_tuple(struct_name, field_lines)
1023 elif vec_ty is not None:
1024 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1025 if ty_info.is_native_primitive:
1026 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1027 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1028 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1029 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1030 write_c("\treturn ret;\n}\n")
1031 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1032 ty_name = struct_name.replace("LDK", "")
1033 clone_fns.add(ty_name + "_clone")
1034 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1035 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1036 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1037 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1038 write_c("\t}\n\treturn ret;\n}\n")
1040 assert(struct_name.endswith("_Tag"))
1041 struct_name = struct_name[:-4]
1042 union_enum_items[struct_name] = {"field_lines": field_lines}
1043 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1044 enum_var_name = struct_name.split("_")
1045 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1046 elif struct_name in union_enum_items:
1049 for line, field_block_comment in field_lines:
1050 if line == " struct {":
1054 elif elem_items > -1:
1056 if line.startswith("struct "):
1058 elif line.startswith("enum "):
1060 split = line.split(" ")
1061 assert len(split) == 2
1062 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1065 # We don't currently support tuple variant with more than one element
1067 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1068 last_block_comment = None
1069 elif is_unitary_enum:
1070 map_unitary_enum(struct_name, field_lines, last_block_comment)
1071 last_block_comment = None
1072 elif len(trait_fn_lines) > 0:
1073 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1074 elif struct_name == "LDKTxOut":
1075 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1076 out_java_struct.write(consts.hu_struct_file_prefix)
1077 out_java_struct.write(consts.txout_defn)
1078 out_java_struct.write(consts.hu_struct_file_suffix)
1079 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1080 write_c(fn_line + " {")
1081 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1083 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1084 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1085 write_c(fn_line + " {")
1086 write_c("\treturn thing->value;")
1088 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1089 elif struct_name == "LDKBigEndianScalar":
1090 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1091 out_java_struct.write(consts.hu_struct_file_prefix)
1092 out_java_struct.write(consts.scalar_defn)
1093 out_java_struct.write(consts.hu_struct_file_suffix)
1094 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1095 write_c(fn_line + " {\n")
1096 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1097 write_c("\treturn ret;\n")
1099 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1101 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1102 # there's nothing heap-allocated inside it the C bindings don't bother
1103 # exposing a `_free` method. Instead, we have to manually write one here,
1104 # though it doesn't need to do anything, the autogenerated wrapper will do
1105 # the required FREE.
1106 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1107 write_c(fn_line + " {}\n")
1108 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1110 pass # Everything remaining is a byte[] of some form
1111 cur_block_obj = None
1113 fn_ptr = fn_ptr_regex.match(line)
1114 fn_ret_arr = fn_ret_arr_regex.match(line)
1115 reg_fn = reg_fn_regex.match(line)
1116 const_val = const_val_regex.match(line)
1118 if line.startswith("#include <"):
1120 elif line.startswith("/*"):
1121 if not line.endswith("*/\n"):
1122 block_comment = line.strip(" /*")
1123 elif line.startswith("typedef enum "):
1124 cur_block_obj = line
1125 elif line.startswith("typedef struct "):
1126 cur_block_obj = line
1127 elif line.startswith("typedef union "):
1128 cur_block_obj = line
1129 elif fn_ptr is not None:
1130 map_fn(line, fn_ptr, None, None, last_block_comment)
1131 last_block_comment = None
1132 elif fn_ret_arr is not None:
1133 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1134 last_block_comment = None
1135 elif reg_fn is not None:
1136 map_fn(line, reg_fn, None, None, last_block_comment)
1137 last_block_comment = None
1138 elif const_val_regex is not None:
1139 # TODO Map const variables
1142 assert(line == "\n")
1144 out_java.write(consts.bindings_footer())
1145 for struct_name in opaque_structs:
1146 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1147 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1148 for struct_name in trait_structs:
1149 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1150 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1151 for struct_name in complex_enums:
1152 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1153 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1154 for struct_name in result_types:
1155 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1156 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1157 for struct_name in tuple_types:
1158 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1159 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1160 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1162 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1163 out_c.write(consts.c_file_pfx)
1164 out_c.write(consts.init_str())
1166 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1167 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1168 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1169 util.write(consts.util_fn_sfx)