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
30 print("Only java or typescript can be set for lang")
34 consts = Consts(DEBUG, target=target, outdir=sys.argv[4])
36 local_git_version = os.getenv("LDK_GARBAGECOLLECTED_GIT_OVERRIDE")
37 if local_git_version is None:
38 local_git_version = subprocess.check_output(["git", "describe", '--tag', '--dirty']).decode("utf-8").strip()
40 from bindingstypes import *
47 def camel_to_snake(s):
48 # Convert camel case to snake case, in a way that appears to match cbindgen
54 if lastchar.isupper():
55 if not char.isupper() and not lastund:
60 ret = ret + lastchar.lower()
63 if char.isupper() and not lastund:
71 return (ret + lastchar.lower()).strip("_")
73 def doc_to_field_nullable(doc):
76 for line in doc.splitlines():
77 if "Note that this (or a relevant inner pointer) may be NULL or all-0s to represent None" in line:
81 def doc_to_params_ret_nullable(doc):
86 for line in doc.splitlines():
87 if "may be NULL or all-0s to represent None" not in line:
89 if "Note that the return value" in line:
91 elif "Note that " in line:
92 param = line.split("Note that ")[1].split(" ")[0]
94 return (params, ret_null)
97 # Map from enum name to "contains trait object"
99 opaque_structs = set()
104 var_is_arr_regex = re.compile("\(\* ?([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
105 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
106 java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
107 def java_c_types(fn_arg, ret_arr_len):
108 fn_arg = fn_arg.strip()
109 if fn_arg.startswith("MUST_USE_RES "):
112 if fn_arg.startswith("const "):
115 if fn_arg.startswith("struct "):
117 if fn_arg.startswith("enum "):
119 nonnull_ptr = "NONNULL_PTR" in fn_arg
120 fn_arg = fn_arg.replace("NONNULL_PTR", "")
127 if fn_arg.startswith("LDKPaymentPreimage") or fn_arg.startswith("LDKPaymentSecret") or fn_arg.startswith("LDKPaymentHash"):
128 if fn_arg.startswith("LDKPaymentPreimage"):
129 fn_arg = "uint8_t (*" + fn_arg[19:] + ")[32]"
130 elif fn_arg.startswith("LDKPaymentSecret"):
131 fn_arg = "uint8_t (*" + fn_arg[17:] + ")[32]"
132 elif fn_arg.startswith("LDKPaymentHash"):
133 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[32]"
134 assert var_is_arr_regex.match(fn_arg[8:])
135 rust_obj = "LDKThirtyTwoBytes"
137 elif fn_arg.startswith("LDKThirtyTwoBytes"):
138 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
139 assert var_is_arr_regex.match(fn_arg[8:])
140 rust_obj = "LDKThirtyTwoBytes"
142 elif fn_arg.startswith("LDKU128"):
143 if fn_arg == "LDKU128":
144 fn_arg = "LDKU128 arg"
145 if fn_arg.startswith("LDKU128*") or fn_arg.startswith("LDKU128 *"):
146 fn_arg = "uint8_t (" + fn_arg[8:] + ")[16]"
148 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[16]"
149 assert var_is_arr_regex.match(fn_arg[8:])
151 arr_access = "le_bytes"
152 elif fn_arg.startswith("LDKTxid"):
153 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
154 assert var_is_arr_regex.match(fn_arg[8:])
155 rust_obj = "LDKThirtyTwoBytes"
157 elif fn_arg.startswith("LDKPublicKey"):
158 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
159 assert var_is_arr_regex.match(fn_arg[8:])
160 rust_obj = "LDKPublicKey"
161 arr_access = "compressed_form"
162 elif fn_arg.startswith("LDKSecretKey"):
163 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
164 assert var_is_arr_regex.match(fn_arg[8:])
165 rust_obj = "LDKSecretKey"
167 elif fn_arg.startswith("LDKSignature"):
168 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
169 assert var_is_arr_regex.match(fn_arg[8:])
170 rust_obj = "LDKSignature"
171 arr_access = "compact_form"
172 elif fn_arg.startswith("LDKRecoverableSignature"):
173 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
174 assert var_is_arr_regex.match(fn_arg[8:])
175 rust_obj = "LDKRecoverableSignature"
176 arr_access = "serialized_form"
177 elif fn_arg.startswith("LDKThreeBytes"):
178 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
179 assert var_is_arr_regex.match(fn_arg[8:])
180 rust_obj = "LDKThreeBytes"
182 elif fn_arg.startswith("LDKFourBytes"):
183 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
184 assert var_is_arr_regex.match(fn_arg[8:])
185 rust_obj = "LDKFourBytes"
187 elif fn_arg.startswith("LDKSixteenBytes"):
188 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
189 assert var_is_arr_regex.match(fn_arg[8:])
190 rust_obj = "LDKSixteenBytes"
192 elif fn_arg.startswith("LDKTwentyBytes"):
193 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
194 assert var_is_arr_regex.match(fn_arg[8:])
195 rust_obj = "LDKTwentyBytes"
197 elif fn_arg.startswith("LDKTwelveBytes"):
198 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
199 assert var_is_arr_regex.match(fn_arg[8:])
200 rust_obj = "LDKTwelveBytes"
202 elif fn_arg.startswith("LDKu8slice"):
203 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
204 assert var_is_arr_regex.match(fn_arg[8:])
205 rust_obj = "LDKu8slice"
207 elif fn_arg.startswith("LDKCVec_u8Z"):
208 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
209 rust_obj = "LDKCVec_u8Z"
210 assert var_is_arr_regex.match(fn_arg[8:])
212 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
213 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
214 rust_obj = "LDKTransaction"
215 assert var_is_arr_regex.match(fn_arg[8:])
217 elif fn_arg.startswith("LDKWitness ") or fn_arg == "LDKWitness":
218 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
219 rust_obj = "LDKWitness"
220 assert var_is_arr_regex.match(fn_arg[8:])
222 elif fn_arg.startswith("LDKCVec_"):
225 fn_arg = fn_arg.replace("*", "")
228 tyn = fn_arg[8:].split(" ")
229 assert tyn[0].endswith("Z")
233 new_arg = "LDK" + tyn[0][:-1]
235 new_arg = new_arg + " " + a
236 res = java_c_types(new_arg, ret_arr_len)
238 assert java_c_types_none_allowed
241 res.pass_by_ref = True
242 java_ty = consts.java_arr_ty_str(res.java_ty)
243 if res.is_native_primitive or res.passed_as_ptr:
244 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
245 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
246 nonnull_ptr=nonnull_ptr, is_const=is_const,
247 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
249 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
250 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
251 nonnull_ptr=nonnull_ptr, is_const=is_const,
252 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
255 contains_trait = False
258 java_type_plural = None
260 if fn_arg.startswith("void"):
264 fn_arg = fn_arg[4:].strip()
266 elif fn_arg.startswith("bool"):
267 java_ty = consts.c_type_map['bool'][0]
271 fn_arg = fn_arg[4:].strip()
273 elif fn_arg.startswith("uint8_t"):
274 mapped_type = consts.c_type_map['uint8_t']
275 java_ty = mapped_type[0]
279 fn_arg = fn_arg[7:].strip()
281 elif fn_arg.startswith("LDKU5") or fn_arg.startswith("LDKWitnessVersion"):
282 java_ty = consts.c_type_map['uint8_t'][0]
283 if fn_arg.startswith("LDKU5"):
286 fn_arg = fn_arg[6:].strip()
288 java_hu_ty = "WitnessVersion"
289 rust_obj = "LDKWitnessVersion"
290 fn_arg = fn_arg[18:].strip()
294 elif fn_arg.startswith("uint16_t"):
295 mapped_type = consts.c_type_map['uint16_t']
296 java_ty = mapped_type[0]
300 fn_arg = fn_arg[8:].strip()
302 elif fn_arg.startswith("uint32_t"):
303 mapped_type = consts.c_type_map['uint32_t']
304 java_ty = mapped_type[0]
308 fn_arg = fn_arg[8:].strip()
310 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
311 # TODO: uintptr_t is arch-dependent :(
312 mapped_type = consts.c_type_map['uint64_t']
313 java_ty = mapped_type[0]
315 if fn_arg.startswith("uint64_t"):
318 fn_arg = fn_arg[8:].strip()
320 java_ty = consts.usize_native_ty
321 c_ty = consts.usize_c_ty
323 rust_obj = "uintptr_t"
324 fn_arg = fn_arg[9:].strip()
326 elif is_const and fn_arg.startswith("char *"):
327 java_ty = consts.java_type_map["String"]
328 java_hu_ty = consts.java_hu_type_map["String"]
331 fn_ty_arg = "Ljava/lang/String;"
332 fn_arg = fn_arg[6:].strip()
333 elif fn_arg.startswith("LDKStr"):
336 java_ty = consts.java_type_map["String"]
337 java_hu_ty = consts.java_hu_type_map["String"]
339 fn_ty_arg = "Ljava/lang/String;"
340 fn_arg = fn_arg[6:].strip()
343 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
344 java_ty = consts.c_type_map['uint32_t'][0]
345 java_hu_ty = "UnqualifiedError"
346 rust_obj = "LDKError"
350 fn_arg = fn_arg[8:].strip()
352 ma = var_ty_regex.match(fn_arg)
353 arr_ty = ma.group(1).strip()
354 if ma.group(1).strip() in unitary_enums:
355 assert ma.group(1).strip().startswith("LDK")
356 java_ty = ma.group(1).strip()[3:]
358 c_ty = consts.result_c_ty
359 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
360 fn_arg = ma.group(2).strip()
361 rust_obj = ma.group(1).strip()
363 c_ty = consts.ptr_c_ty
364 java_ty = consts.ptr_native_ty
365 java_hu_ty = ma.group(1).strip()
366 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
367 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
368 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
369 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
370 java_hu_ty = java_hu_ty.replace("LDK", "")
372 fn_arg = ma.group(2).strip()
373 rust_obj = ma.group(1).strip()
374 if rust_obj in trait_structs:
375 contains_trait = True
376 elif rust_obj in complex_enums:
377 contains_trait = complex_enums[rust_obj]
380 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
381 fn_arg = fn_arg.replace("*", "").strip()
383 c_ty = consts.ptr_c_ty
384 java_ty = consts.ptr_native_ty
387 var_is_arr = var_is_arr_regex.match(fn_arg)
389 if var_is_arr is not None or ret_arr_len is not None:
390 assert(not take_by_ptr)
392 # is there a special case for plurals?
393 if len(mapped_type) == 3:
394 java_ty = mapped_type[1]
395 java_hu_ty = mapped_type[2]
397 java_ty = java_ty + "[]"
399 if rust_obj == "LDKU128":
400 java_hu_ty = consts.u128_native_ty
401 c_ty = c_ty + "Array"
403 subty = java_c_types(arr_ty, None)
405 assert java_c_types_none_allowed
408 subty.pass_by_ref = True
410 if var_is_arr is not None:
411 if var_is_arr.group(1) == "":
412 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,
413 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
414 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
415 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,
416 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
417 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
419 if java_hu_ty is None:
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, passed_as_ptr=is_ptr or take_by_ptr,
422 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,
423 contains_trait=contains_trait, subty=subty)
425 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
426 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
427 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
431 from gen_type_mapping import TypeMappingGenerator
432 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
434 with open(sys.argv[1]) as in_h:
436 reg_fn = reg_fn_regex.match(line)
437 if reg_fn is not None:
438 if reg_fn.group(2).endswith("_clone"):
439 clone_fns.add(reg_fn.group(2))
441 rty = java_c_types(reg_fn.group(1), None)
442 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
443 constructor_fns[rty.rust_obj] = reg_fn.group(3)
445 arr_fn = fn_ret_arr_regex.match(line)
446 if arr_fn is not None:
447 if arr_fn.group(2).endswith("_clone"):
448 clone_fns.add(arr_fn.group(2))
449 # No object constructors return arrays, as then they wouldn't be an object constructor
452 # Define some manual clones...
453 clone_fns.add("ThirtyTwoBytes_clone")
454 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")
457 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
458 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
459 write_c("\tif (sizeof(void*) == 4) {\n")
460 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
461 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
462 write_c("\t} else {\n")
463 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
464 write_c("\t\t// use bit 9 ^ bit 10.\n")
465 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
466 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
467 write_c("#ifdef LDK_DEBUG_BUILD\n")
468 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
469 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
470 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
471 write_c("\t\tp ^= 1ULL << 53;\n")
473 write_c("\t\treturn (void*)p;\n")
477 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
478 write_c("\tif(ptr < 4096) return true;\n")
479 write_c("\tif (sizeof(void*) == 4) {\n")
480 write_c("\t\treturn ptr & (1ULL << 32);\n")
481 write_c("\t} else {\n")
482 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
483 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
484 write_c("#ifdef LDK_DEBUG_BUILD\n")
485 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
486 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
487 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
489 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
493 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
494 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
495 write_c("\tif (sizeof(void*) == 4) {\n")
496 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
497 write_c("\t} else {\n")
498 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
499 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
500 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
501 write_c("#ifdef LDK_DEBUG_BUILD\n")
502 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
503 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
504 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
505 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
506 write_c("\t\tt ^= 1ULL << 53;\n")
508 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
509 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
510 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
511 write_c("\t\treturn t;\n")
515 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
517 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
518 util.write(consts.util_fn_pfx)
520 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
521 # Map a top-level function
522 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
523 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
524 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
525 method_return_type = re_match.group(1)
526 method_name = re_match.group(2)
527 method_comma_separated_arguments = re_match.group(3)
528 method_arguments = method_comma_separated_arguments.split(',')
530 if method_name.startswith("__"):
533 is_free = method_name.endswith("_free")
534 if method_name.startswith("COption") or method_name.startswith("CResult"):
535 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
536 expected_struct = "LDKC" + struct_meth
537 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
538 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
539 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
540 if method_name.startswith("C2Tuple"):
541 struct_meth = "Two" + tuple_name
542 expected_struct = "LDKC2" + tuple_name
544 struct_meth = "Three" + tuple_name
545 expected_struct = "LDKC3" + tuple_name
546 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
548 struct_meth = method_name.split("_")[0]
549 expected_struct = "LDK" + struct_meth
550 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
552 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
554 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
556 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
558 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
559 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
560 write_c("static inline " + meth_line + " {\n")
561 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
562 write_c(method_name + "(arg)")
563 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
564 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
565 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
568 default_constructor_args = {}
570 takes_self_ptr = False
572 for argument_index, argument in enumerate(method_arguments):
573 arg_ty = type_mapping_generator.java_c_types(argument, None)
574 argument_conversion_info = None
575 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
576 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
578 if argument_conversion_info.ty_info.is_ptr:
579 takes_self_ptr = True
580 elif arg_ty.var_name in params_nullable:
581 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
582 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
583 arg_ty_info = java_c_types(argument, None)
584 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
585 print(" The argument appears to require a move, or not clonable, and is nullable.")
586 print(" Normally for arguments that require a move and are not clonable, we split")
587 print(" the argument into the type's constructor's arguments and just use those to")
588 print(" construct a new object on the fly.")
589 print(" However, because the object is nullable, doing so would mean we can no")
590 print(" longer allow the user to pass null, as we now have an argument list instead.")
591 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
592 print(" It may or may not actually be a reference, but its the simplest mapping option")
593 print(" and also the only use of this code today.")
594 arg_ty_info.requires_clone = False
595 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
596 assert argument_conversion_info.nullable
597 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
599 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
601 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
602 if argument_conversion_info.rust_obj in constructor_fns:
604 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
605 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
606 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
607 continue # (void) is C lingo for "no arguments)
608 if explode_arg_conv.c_ty == "void":
610 if not argument_conversion_info.arg_name in default_constructor_args:
611 default_constructor_args[argument_conversion_info.arg_name] = []
612 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
613 argument_types.append(argument_conversion_info)
615 if not takes_self and return_type_info.java_hu_ty != struct_meth:
616 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
617 struct_meth_name = method_name
621 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
622 expected_struct in complex_enums or expected_struct in complex_enums or
623 expected_struct in result_types or expected_struct in tuple_types) and not is_free
624 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
625 not method_name.startswith("TxOut") and not method_name.startswith("BigEndianScalar") and
626 not method_name.startswith("_") and
627 method_name != "check_platform" and method_name != "Result_read" and
628 not expected_struct in unitary_enums and
629 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
630 or method_name.endswith("_read")))
632 # If we're adding a static method, and it returns a primitive or an array of primitives,
633 # and a variable conversion adds a reference on the return type (via `this`), skip the
634 # variable's conversion reference-add (as we obviously cannot need a reference).
635 if impl_on_utils and (return_type_info.is_native_primitive or
636 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
637 for arg in argument_types:
638 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
639 if "this" in arg.from_hu_conv[1]:
640 arg.from_hu_conv = (arg.from_hu_conv[0], "")
642 out_java.write("\t// " + line)
643 args_known = True # We no longer ever set this to false
644 (out_java_delta, out_c_delta, out_java_struct_delta) = \
645 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)
646 out_java.write(out_java_delta)
649 assert len(argument_types) == 1
650 assert return_type_info.c_ty == "void"
651 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")
652 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
653 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
655 for info in argument_types:
656 if info.arg_conv is not None:
657 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
658 assert c_call_string is None
659 write_c("\t" + method_name + "(")
660 if argument_types[0].arg_conv_name is not None:
661 write_c(argument_types[0].arg_conv_name)
663 for info in argument_types:
664 if info.arg_conv_cleanup is not None:
665 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
670 out_java_struct = None
672 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
673 out_java_struct.write(out_java_struct_delta)
675 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
676 for line in out_java_struct_delta.splitlines():
677 out_java_struct.write(line + "\n")
679 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
680 assert struct_name.startswith("LDK")
681 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
682 unitary_enums.add(struct_name)
683 for idx, (struct_line, _) in enumerate(field_lines):
685 assert(struct_line == "typedef enum %s {" % struct_name)
686 elif idx == len(field_lines) - 3:
687 assert(struct_line.endswith("_Sentinel,"))
688 elif idx == len(field_lines) - 2:
689 assert(struct_line == "} %s;" % struct_name)
690 elif idx == len(field_lines) - 1:
691 assert(struct_line == "")
692 assert struct_name.startswith("LDK")
693 (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)
695 out_java_enum.write(native_file_out)
696 out_java.write(native_out)
698 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
699 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
702 tag_field_lines = union_enum_items["field_lines"]
703 contains_trait = False
704 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
706 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
707 elif idx == len(tag_field_lines) - 3:
708 assert(struct_line.endswith("_Sentinel,"))
709 elif idx == len(tag_field_lines) - 2:
710 assert(struct_line == "} %s_Tag;" % struct_name)
711 elif idx == len(tag_field_lines) - 1:
712 assert(struct_line == "")
714 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
716 if "LDK" + variant_name in union_enum_items:
717 enum_var_lines = union_enum_items["LDK" + variant_name]
718 for idx, (field, field_docs) in enumerate(enum_var_lines):
719 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
720 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
721 contains_trait |= field_ty.contains_trait
722 if field_docs is not None and doc_to_field_nullable(field_docs):
723 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
725 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
726 fields.append((field_conv, field_docs))
727 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
728 elif camel_to_snake(variant_name) in inline_enum_variants:
729 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
730 # docs through to there, and then potentially mark the field nullable.
731 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
732 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
733 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
734 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
735 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
737 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
738 contains_trait |= mapped.ty_info.contains_trait
739 fields.append((mapped, None))
740 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
742 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
743 complex_enums[struct_name] = contains_trait
745 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
746 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
748 out_java_enum.write(out_java_enum_addendum)
749 out_java.write(out_java_addendum)
750 write_c(out_c_addendum)
752 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
753 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
755 flattened_field_var_convs = []
756 for var_line in field_var_lines:
757 if var_line.group(1) in trait_structs:
758 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
759 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
760 flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
762 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
763 field_var_convs.append(mapped)
764 flattened_field_var_convs.append(mapped)
765 trait_structs[struct_name] = field_var_convs
768 for fn_docs, fn_line in trait_fn_lines:
769 if fn_line == "cloned":
770 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
771 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
773 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
775 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
776 ret_ty_info.nullable = True
778 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
779 is_const = fn_line.group(4) is not None
782 for idx, arg in enumerate(fn_line.group(5).split(',')):
785 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
786 if arg_ty_info.var_name in nullable_params:
787 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
788 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
790 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
791 arg_tys.append(arg_conv_info)
792 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
794 (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)
795 write_c(out_c_addendum)
796 out_java_trait.write(out_java_trait_addendum)
797 out_java.write(out_java_addendum)
799 for fn_docs, fn_line in trait_fn_lines:
800 if fn_line == "cloned":
802 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
803 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
804 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
805 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"
806 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)
807 for idx, var_line in enumerate(field_var_lines):
808 if var_line.group(1) not in trait_structs:
809 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
810 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
811 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
812 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
814 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"
815 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)
817 def map_result(struct_name, res_ty, err_ty):
818 result_types.add(struct_name)
819 human_ty = struct_name.replace("LDKCResult", "Result")
820 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
821 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
822 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
823 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
824 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
825 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
826 out_java_struct.write(java_hu_struct)
828 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
829 field_ty = java_c_types(field_decl + " " + field_name, None)
830 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
831 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
834 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
835 fn_defn = owned_fn_defn
836 write_c("static inline " + fn_defn + "{\n")
837 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
838 write_c("\tret.is_owned = false;\n")
839 write_c("\treturn ret;\n")
840 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
841 fn_defn = owned_fn_defn
842 write_c("static inline " + fn_defn + "{\n")
843 if check_sfx is not None:
844 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
845 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
846 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
847 fn_defn = owned_fn_defn
848 write_c("static inline " + fn_defn + "{\n")
849 if check_sfx is not None:
850 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
851 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
854 fn_defn = ptr_fn_defn
855 write_c("static inline " + fn_defn + "{\n")
856 if check_sfx is not None:
857 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
858 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
861 dummy_line = fn_defn + ";\n"
862 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
864 def map_tuple(struct_name, field_lines):
865 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
866 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
867 out_java_struct.write(consts.map_tuple(struct_name))
869 for idx, (line, _) in enumerate(field_lines):
870 if idx != 0 and idx < len(field_lines) - 2:
871 ty_list.append(java_c_types(line.strip(';'), None))
872 tuple_types[struct_name] = (ty_list, struct_name)
874 # Map virtual getter functions
875 for idx, (line, _) in enumerate(field_lines):
876 if idx != 0 and idx < len(field_lines) - 2:
877 field_name = chr(ord('a') + idx - 1)
878 assert line.endswith(" " + field_name + ";")
879 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
881 out_java.write(consts.bindings_header)
882 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
883 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
885 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
886 out_java_struct.write(consts.common_base)
889 last_block_comment = None
892 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
894 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
895 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
896 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
897 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
898 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
899 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
900 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
901 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
902 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
903 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
904 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
905 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
906 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
907 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
908 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
910 union_enum_items = {}
911 result_ptr_struct_items = {}
913 if block_comment is not None:
914 if line.endswith("*/\n"):
915 last_block_comment = block_comment.strip("\n")
918 block_comment = block_comment + line.strip(" /*")
919 elif cur_block_obj is not None:
920 cur_block_obj = cur_block_obj + line
921 if line.startswith("} "):
925 obj_lines = cur_block_obj.split("\n")
927 result_contents = None
928 is_unitary_enum = False
929 is_union_enum = False
934 last_struct_block_comment = None
936 for idx, struct_line in enumerate(obj_lines):
937 if struct_line.strip().startswith("/*"):
938 block_comment = struct_line.strip(" /*")
939 if block_comment is not None:
940 if struct_line.endswith("*/"):
941 last_struct_block_comment = block_comment.strip("\n")
944 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
946 struct_name_match = struct_name_regex.match(struct_line)
947 if struct_name_match is not None:
948 struct_name = struct_name_match.group(3)
949 if struct_name_match.group(1) == "enum":
950 if not struct_name.endswith("_Tag"):
951 is_unitary_enum = True
954 elif struct_name_match.group(1) == "union":
956 if line_indicates_opaque_regex.match(struct_line):
958 result_match = line_indicates_result_regex.match(struct_line)
959 if result_match is not None:
960 result_contents = result_match.group(1)
961 vec_ty_match = line_indicates_vec_regex.match(struct_line)
962 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
963 vec_ty = vec_ty_match.group(2)
964 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
966 trait_fn_match = line_indicates_trait_regex.match(struct_line)
967 if trait_fn_match is not None:
968 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
969 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
970 if trait_clone_fn_match is not None:
971 trait_fn_lines.append((last_struct_block_comment, "cloned"))
972 field_var_match = line_field_var_regex.match(struct_line)
973 if field_var_match is not None:
974 field_var_lines.append(field_var_match)
975 field_lines.append((struct_line, last_struct_block_comment))
976 last_struct_block_comment = None
978 assert(struct_name is not None)
979 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))
980 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))
981 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))
982 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))
983 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))
984 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))
985 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))
988 opaque_structs.add(struct_name)
989 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
990 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
991 last_block_comment = None
992 out_java_struct.write(out_opaque_struct_human)
993 elif result_contents is not None:
994 assert result_contents in result_ptr_struct_items
995 res_ty, err_ty = result_ptr_struct_items[result_contents]
996 map_result(struct_name, res_ty, err_ty)
997 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
998 for line, _ in field_lines:
999 if line.endswith("*result;"):
1000 res_ty = line[:-8].strip()
1001 elif line.endswith("*err;"):
1002 err_ty = line[:-5].strip()
1003 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1004 result_types.add(struct_name[:-3])
1006 map_tuple(struct_name, field_lines)
1007 elif vec_ty is not None:
1008 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1009 if ty_info.is_native_primitive:
1010 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1011 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1012 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1013 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1014 write_c("\treturn ret;\n}\n")
1015 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1016 ty_name = struct_name.replace("LDK", "")
1017 clone_fns.add(ty_name + "_clone")
1018 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1019 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1020 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1021 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1022 write_c("\t}\n\treturn ret;\n}\n")
1024 assert(struct_name.endswith("_Tag"))
1025 struct_name = struct_name[:-4]
1026 union_enum_items[struct_name] = {"field_lines": field_lines}
1027 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1028 enum_var_name = struct_name.split("_")
1029 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1030 elif struct_name in union_enum_items:
1033 for line, field_block_comment in field_lines:
1034 if line == " struct {":
1038 elif elem_items > -1:
1040 if line.startswith("struct "):
1042 elif line.startswith("enum "):
1044 split = line.split(" ")
1045 assert len(split) == 2
1046 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1049 # We don't currently support tuple variant with more than one element
1051 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1052 last_block_comment = None
1053 elif is_unitary_enum:
1054 map_unitary_enum(struct_name, field_lines, last_block_comment)
1055 last_block_comment = None
1056 elif len(trait_fn_lines) > 0:
1057 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1058 elif struct_name == "LDKTxOut":
1059 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1060 out_java_struct.write(consts.hu_struct_file_prefix)
1061 out_java_struct.write(consts.txout_defn)
1062 out_java_struct.write(consts.hu_struct_file_suffix)
1063 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1064 write_c(fn_line + " {")
1065 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1067 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1068 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1069 write_c(fn_line + " {")
1070 write_c("\treturn thing->value;")
1072 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1073 elif struct_name == "LDKBigEndianScalar":
1074 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1075 out_java_struct.write(consts.hu_struct_file_prefix)
1076 out_java_struct.write(consts.scalar_defn)
1077 out_java_struct.write(consts.hu_struct_file_suffix)
1078 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1079 write_c(fn_line + " {\n")
1080 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1081 write_c("\treturn ret;\n")
1083 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1085 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1086 # there's nothing heap-allocated inside it the C bindings don't bother
1087 # exposing a `_free` method. Instead, we have to manually write one here,
1088 # though it doesn't need to do anything, the autogenerated wrapper will do
1089 # the required FREE.
1090 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1091 write_c(fn_line + " {}\n")
1092 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1094 pass # Everything remaining is a byte[] of some form
1095 cur_block_obj = None
1097 fn_ptr = fn_ptr_regex.match(line)
1098 fn_ret_arr = fn_ret_arr_regex.match(line)
1099 reg_fn = reg_fn_regex.match(line)
1100 const_val = const_val_regex.match(line)
1102 if line.startswith("#include <"):
1104 elif line.startswith("/*"):
1105 if not line.endswith("*/\n"):
1106 block_comment = line.strip(" /*")
1107 elif line.startswith("typedef enum "):
1108 cur_block_obj = line
1109 elif line.startswith("typedef struct "):
1110 cur_block_obj = line
1111 elif line.startswith("typedef union "):
1112 cur_block_obj = line
1113 elif fn_ptr is not None:
1114 map_fn(line, fn_ptr, None, None, last_block_comment)
1115 last_block_comment = None
1116 elif fn_ret_arr is not None:
1117 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1118 last_block_comment = None
1119 elif reg_fn is not None:
1120 map_fn(line, reg_fn, None, None, last_block_comment)
1121 last_block_comment = None
1122 elif const_val_regex is not None:
1123 # TODO Map const variables
1126 assert(line == "\n")
1128 out_java.write(consts.bindings_footer())
1129 for struct_name in opaque_structs:
1130 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1131 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1132 for struct_name in trait_structs:
1133 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1134 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1135 for struct_name in complex_enums:
1136 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1137 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1138 for struct_name in result_types:
1139 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1140 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1141 for struct_name in tuple_types:
1142 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1143 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1144 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1146 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1147 out_c.write(consts.c_file_pfx)
1148 out_c.write(consts.init_str())
1150 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1151 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1152 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1153 util.write(consts.util_fn_sfx)