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
33 elif sys.argv[6] == "python":
35 from python_strings import Consts
36 target = python_strings.Target.PYTHON
38 print("Only java, typescript, python, or c_sharp can be set for lang")
42 consts = Consts(DEBUG, target=target, outdir=sys.argv[4])
44 local_git_version = os.getenv("LDK_GARBAGECOLLECTED_GIT_OVERRIDE")
45 if local_git_version is None:
46 local_git_version = subprocess.check_output(["git", "describe", '--tag', '--dirty']).decode("utf-8").strip()
48 from bindingstypes import *
55 def camel_to_snake(s):
56 # Convert camel case to snake case, in a way that appears to match cbindgen
62 if lastchar.isupper():
63 if not char.isupper() and not lastund:
68 ret = ret + lastchar.lower()
71 if char.isupper() and not lastund:
79 return (ret + lastchar.lower()).strip("_")
81 def doc_to_field_nullable(doc):
84 for line in doc.splitlines():
85 if "Note that this (or a relevant inner pointer) may be NULL or all-0s to represent None" in line:
89 def doc_to_params_ret_nullable(doc):
94 for line in doc.splitlines():
95 if "may be NULL or all-0s to represent None" not in line:
97 if "Note that the return value" in line:
99 elif "Note that " in line:
100 param = line.split("Note that ")[1].split(" ")[0]
102 return (params, ret_null)
104 unitary_enums = set()
105 # Map from enum name to "contains trait object"
107 opaque_structs = set()
112 var_is_arr_regex = re.compile("\(\* ?([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
113 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
114 java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
115 def java_c_types(fn_arg, ret_arr_len):
116 fn_arg = fn_arg.strip()
117 if fn_arg.startswith("MUST_USE_RES "):
120 if fn_arg.startswith("const "):
123 if fn_arg.startswith("struct "):
125 if fn_arg.startswith("enum "):
127 nonnull_ptr = "NONNULL_PTR" in fn_arg
128 fn_arg = fn_arg.replace("NONNULL_PTR", "")
135 if fn_arg.startswith("LDKPaymentPreimage") or fn_arg.startswith("LDKPaymentSecret") or fn_arg.startswith("LDKPaymentHash"):
136 if fn_arg.startswith("LDKPaymentPreimage"):
137 fn_arg = "uint8_t (*" + fn_arg[19:] + ")[32]"
138 elif fn_arg.startswith("LDKPaymentSecret"):
139 fn_arg = "uint8_t (*" + fn_arg[17:] + ")[32]"
140 elif fn_arg.startswith("LDKPaymentHash"):
141 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[32]"
142 assert var_is_arr_regex.match(fn_arg[8:])
143 rust_obj = "LDKThirtyTwoBytes"
145 elif fn_arg.startswith("LDKThirtyTwoBytes"):
146 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
147 assert var_is_arr_regex.match(fn_arg[8:])
148 rust_obj = "LDKThirtyTwoBytes"
150 elif fn_arg.startswith("LDKEightU16s"):
151 fn_arg = "uint16_t (*" + fn_arg[13:] + ")[8]"
152 assert var_is_arr_regex.match(fn_arg[9:])
153 rust_obj = "LDKEightU16s"
155 elif fn_arg.startswith("LDKU128"):
156 if fn_arg == "LDKU128":
157 fn_arg = "LDKU128 arg"
158 if fn_arg.startswith("LDKU128*") or fn_arg.startswith("LDKU128 *"):
159 fn_arg = "uint8_t (" + fn_arg[8:] + ")[16]"
161 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[16]"
162 assert var_is_arr_regex.match(fn_arg[8:])
164 arr_access = "le_bytes"
165 elif fn_arg.startswith("LDKTxid"):
166 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
167 assert var_is_arr_regex.match(fn_arg[8:])
168 rust_obj = "LDKThirtyTwoBytes"
170 elif fn_arg.startswith("LDKPublicKey"):
171 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
172 assert var_is_arr_regex.match(fn_arg[8:])
173 rust_obj = "LDKPublicKey"
174 arr_access = "compressed_form"
175 elif fn_arg.startswith("LDKSecretKey"):
176 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
177 assert var_is_arr_regex.match(fn_arg[8:])
178 rust_obj = "LDKSecretKey"
180 elif fn_arg.startswith("LDKSignature"):
181 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
182 assert var_is_arr_regex.match(fn_arg[8:])
183 rust_obj = "LDKSignature"
184 arr_access = "compact_form"
185 elif fn_arg.startswith("LDKRecoverableSignature"):
186 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
187 assert var_is_arr_regex.match(fn_arg[8:])
188 rust_obj = "LDKRecoverableSignature"
189 arr_access = "serialized_form"
190 elif fn_arg.startswith("LDKThreeBytes"):
191 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
192 assert var_is_arr_regex.match(fn_arg[8:])
193 rust_obj = "LDKThreeBytes"
195 elif fn_arg.startswith("LDKFourBytes"):
196 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
197 assert var_is_arr_regex.match(fn_arg[8:])
198 rust_obj = "LDKFourBytes"
200 elif fn_arg.startswith("LDKSixteenBytes"):
201 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
202 assert var_is_arr_regex.match(fn_arg[8:])
203 rust_obj = "LDKSixteenBytes"
205 elif fn_arg.startswith("LDKTwentyBytes"):
206 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
207 assert var_is_arr_regex.match(fn_arg[8:])
208 rust_obj = "LDKTwentyBytes"
210 elif fn_arg.startswith("LDKTwelveBytes"):
211 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
212 assert var_is_arr_regex.match(fn_arg[8:])
213 rust_obj = "LDKTwelveBytes"
215 elif fn_arg.startswith("LDKu8slice"):
216 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
217 assert var_is_arr_regex.match(fn_arg[8:])
218 rust_obj = "LDKu8slice"
220 elif fn_arg.startswith("LDKCVec_u8Z"):
221 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
222 rust_obj = "LDKCVec_u8Z"
223 assert var_is_arr_regex.match(fn_arg[8:])
225 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
226 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
227 rust_obj = "LDKTransaction"
228 assert var_is_arr_regex.match(fn_arg[8:])
230 elif fn_arg.startswith("LDKWitness ") or fn_arg == "LDKWitness":
231 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
232 rust_obj = "LDKWitness"
233 assert var_is_arr_regex.match(fn_arg[8:])
235 elif fn_arg.startswith("LDKCVec_"):
238 fn_arg = fn_arg.replace("*", "")
241 tyn = fn_arg[8:].split(" ")
242 assert tyn[0].endswith("Z")
246 new_arg = "LDK" + tyn[0][:-1]
248 new_arg = new_arg + " " + a
249 res = java_c_types(new_arg, ret_arr_len)
251 assert java_c_types_none_allowed
254 res.pass_by_ref = True
255 java_ty = consts.java_arr_ty_str(res.java_ty)
256 if res.is_native_primitive or res.passed_as_ptr:
257 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
258 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
259 nonnull_ptr=nonnull_ptr, is_const=is_const,
260 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
262 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
263 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
264 nonnull_ptr=nonnull_ptr, is_const=is_const,
265 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
268 contains_trait = False
271 java_type_plural = None
273 if fn_arg.startswith("void"):
277 fn_arg = fn_arg[4:].strip()
279 elif fn_arg.startswith("bool"):
280 java_ty = consts.c_type_map['bool'][0]
284 fn_arg = fn_arg[4:].strip()
286 elif fn_arg.startswith("uint8_t"):
287 mapped_type = consts.c_type_map['uint8_t']
288 java_ty = mapped_type[0]
292 fn_arg = fn_arg[7:].strip()
294 elif fn_arg.startswith("LDKU5") or fn_arg.startswith("LDKWitnessVersion"):
295 java_ty = consts.c_type_map['uint8_t'][0]
296 if fn_arg.startswith("LDKU5"):
299 fn_arg = fn_arg[6:].strip()
301 java_hu_ty = "WitnessVersion"
302 rust_obj = "LDKWitnessVersion"
303 fn_arg = fn_arg[18:].strip()
307 elif fn_arg.startswith("uint16_t"):
308 mapped_type = consts.c_type_map['uint16_t']
309 java_ty = mapped_type[0]
313 fn_arg = fn_arg[8:].strip()
315 elif fn_arg.startswith("uint32_t"):
316 mapped_type = consts.c_type_map['uint32_t']
317 java_ty = mapped_type[0]
321 fn_arg = fn_arg[8:].strip()
323 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
324 # TODO: uintptr_t is arch-dependent :(
325 mapped_type = consts.c_type_map['uint64_t']
326 java_ty = mapped_type[0]
328 if fn_arg.startswith("uint64_t"):
331 fn_arg = fn_arg[8:].strip()
333 java_ty = consts.usize_native_ty
334 c_ty = consts.usize_c_ty
336 rust_obj = "uintptr_t"
337 fn_arg = fn_arg[9:].strip()
339 elif is_const and fn_arg.startswith("char *"):
340 java_ty = consts.java_type_map["String"]
341 java_hu_ty = consts.java_hu_type_map["String"]
344 fn_ty_arg = "Ljava/lang/String;"
345 fn_arg = fn_arg[6:].strip()
346 elif fn_arg.startswith("LDKStr"):
349 java_ty = consts.java_type_map["String"]
350 java_hu_ty = consts.java_hu_type_map["String"]
352 fn_ty_arg = "Ljava/lang/String;"
353 fn_arg = fn_arg[6:].strip()
356 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
357 java_ty = consts.c_type_map['uint32_t'][0]
358 java_hu_ty = "UnqualifiedError"
359 rust_obj = "LDKError"
363 fn_arg = fn_arg[8:].strip()
365 ma = var_ty_regex.match(fn_arg)
366 arr_ty = ma.group(1).strip()
367 if ma.group(1).strip() in unitary_enums:
368 assert ma.group(1).strip().startswith("LDK")
369 java_ty = ma.group(1).strip()[3:]
371 c_ty = consts.result_c_ty
372 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
373 fn_arg = ma.group(2).strip()
374 rust_obj = ma.group(1).strip()
376 c_ty = consts.ptr_c_ty
377 java_ty = consts.ptr_native_ty
378 java_hu_ty = ma.group(1).strip()
379 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
380 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
381 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
382 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
383 java_hu_ty = java_hu_ty.replace("LDK", "")
385 fn_arg = ma.group(2).strip()
386 rust_obj = ma.group(1).strip()
387 if rust_obj in trait_structs:
388 contains_trait = True
389 elif rust_obj in complex_enums:
390 contains_trait = complex_enums[rust_obj]
393 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
394 fn_arg = fn_arg.replace("*", "").strip()
396 c_ty = consts.ptr_c_ty
397 java_ty = consts.ptr_native_ty
400 var_is_arr = var_is_arr_regex.match(fn_arg)
402 if var_is_arr is not None or ret_arr_len is not None:
403 assert(not take_by_ptr)
405 # is there a special case for plurals?
406 if len(mapped_type) == 3:
407 java_ty = mapped_type[1]
408 java_hu_ty = mapped_type[2]
410 java_ty = java_ty + "[]"
412 if rust_obj == "LDKU128":
413 java_hu_ty = consts.u128_native_ty
414 c_ty = c_ty + "Array"
416 subty = java_c_types(arr_ty, None)
418 assert java_c_types_none_allowed
421 subty.pass_by_ref = True
423 if var_is_arr is not None:
424 if var_is_arr.group(1) == "":
425 return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
426 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
427 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
428 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,
429 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
430 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
432 if java_hu_ty is None:
434 return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg=fn_ty_arg, c_ty=c_ty, passed_as_ptr=is_ptr or take_by_ptr,
435 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,
436 contains_trait=contains_trait, subty=subty)
438 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
439 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
440 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
444 from gen_type_mapping import TypeMappingGenerator
445 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
447 with open(sys.argv[1]) as in_h:
449 reg_fn = reg_fn_regex.match(line)
450 if reg_fn is not None:
451 if reg_fn.group(2).endswith("_clone"):
452 clone_fns.add(reg_fn.group(2))
454 rty = java_c_types(reg_fn.group(1), None)
455 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
456 constructor_fns[rty.rust_obj] = reg_fn.group(3)
458 arr_fn = fn_ret_arr_regex.match(line)
459 if arr_fn is not None:
460 if arr_fn.group(2).endswith("_clone"):
461 clone_fns.add(arr_fn.group(2))
462 # No object constructors return arrays, as then they wouldn't be an object constructor
465 # Define some manual clones...
466 clone_fns.add("ThirtyTwoBytes_clone")
467 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")
470 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
471 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
472 write_c("\tif (sizeof(void*) == 4) {\n")
473 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
474 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
475 write_c("\t} else {\n")
476 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
477 write_c("\t\t// use bit 9 ^ bit 10.\n")
478 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
479 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
480 write_c("#ifdef LDK_DEBUG_BUILD\n")
481 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
482 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
483 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
484 write_c("\t\tp ^= 1ULL << 53;\n")
486 write_c("\t\treturn (void*)p;\n")
490 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
491 write_c("\tif(ptr < 4096) return true;\n")
492 write_c("\tif (sizeof(void*) == 4) {\n")
493 write_c("\t\treturn ptr & (1ULL << 32);\n")
494 write_c("\t} else {\n")
495 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
496 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
497 write_c("#ifdef LDK_DEBUG_BUILD\n")
498 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
499 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
500 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
502 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
506 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
507 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
508 write_c("\tif (sizeof(void*) == 4) {\n")
509 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
510 write_c("\t} else {\n")
511 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
512 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
513 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
514 write_c("#ifdef LDK_DEBUG_BUILD\n")
515 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
516 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
517 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
518 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
519 write_c("\t\tt ^= 1ULL << 53;\n")
521 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
522 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
523 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
524 write_c("\t\treturn t;\n")
528 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
530 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
531 util.write(consts.util_fn_pfx)
533 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
534 # Map a top-level function
535 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
536 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
537 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
538 method_return_type = re_match.group(1)
539 method_name = re_match.group(2)
540 method_comma_separated_arguments = re_match.group(3)
541 method_arguments = method_comma_separated_arguments.split(',')
543 if method_name.startswith("__"):
546 is_free = method_name.endswith("_free")
547 if method_name.startswith("COption") or method_name.startswith("CResult"):
548 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
549 expected_struct = "LDKC" + struct_meth
550 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
551 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
552 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
553 if method_name.startswith("C2Tuple"):
554 struct_meth = "Two" + tuple_name
555 expected_struct = "LDKC2" + tuple_name
557 struct_meth = "Three" + tuple_name
558 expected_struct = "LDKC3" + tuple_name
559 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
561 struct_meth = method_name.split("_")[0]
562 expected_struct = "LDK" + struct_meth
563 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
565 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
567 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
569 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
571 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
572 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
573 write_c("static inline " + meth_line + " {\n")
574 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
575 write_c(method_name + "(arg)")
576 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
577 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
578 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
581 default_constructor_args = {}
583 takes_self_ptr = False
585 for argument_index, argument in enumerate(method_arguments):
586 arg_ty = type_mapping_generator.java_c_types(argument, None)
587 argument_conversion_info = None
588 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
589 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
591 if argument_conversion_info.ty_info.is_ptr:
592 takes_self_ptr = True
593 elif arg_ty.var_name in params_nullable:
594 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
595 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
596 arg_ty_info = java_c_types(argument, None)
597 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
598 print(" The argument appears to require a move, or not clonable, and is nullable.")
599 print(" Normally for arguments that require a move and are not clonable, we split")
600 print(" the argument into the type's constructor's arguments and just use those to")
601 print(" construct a new object on the fly.")
602 print(" However, because the object is nullable, doing so would mean we can no")
603 print(" longer allow the user to pass null, as we now have an argument list instead.")
604 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
605 print(" It may or may not actually be a reference, but its the simplest mapping option")
606 print(" and also the only use of this code today.")
607 arg_ty_info.requires_clone = False
608 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
609 assert argument_conversion_info.nullable
610 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
612 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
614 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
615 if argument_conversion_info.rust_obj in constructor_fns:
617 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
618 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
619 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
620 continue # (void) is C lingo for "no arguments)
621 if explode_arg_conv.c_ty == "void":
623 if not argument_conversion_info.arg_name in default_constructor_args:
624 default_constructor_args[argument_conversion_info.arg_name] = []
625 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
626 argument_types.append(argument_conversion_info)
628 if not takes_self and return_type_info.java_hu_ty != struct_meth:
629 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
630 struct_meth_name = method_name
634 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
635 expected_struct in complex_enums or expected_struct in complex_enums or
636 expected_struct in result_types or expected_struct in tuple_types) and not is_free
637 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
638 not method_name.startswith("TxOut") and not method_name.startswith("BigEndianScalar") and
639 not method_name.startswith("_") and
640 method_name != "check_platform" and method_name != "Result_read" and
641 not expected_struct in unitary_enums and
642 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
643 or method_name.endswith("_read")))
645 # If we're adding a static method, and it returns a primitive or an array of primitives,
646 # and a variable conversion adds a reference on the return type (via `this`), skip the
647 # variable's conversion reference-add (as we obviously cannot need a reference).
648 if impl_on_utils and (return_type_info.is_native_primitive or
649 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
650 for arg in argument_types:
651 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
652 if "this" in arg.from_hu_conv[1]:
653 arg.from_hu_conv = (arg.from_hu_conv[0], "")
655 out_java.write("\t// " + line)
656 args_known = True # We no longer ever set this to false
657 (out_java_delta, out_c_delta, out_java_struct_delta) = \
658 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)
659 out_java.write(out_java_delta)
662 assert len(argument_types) == 1
663 assert return_type_info.c_ty == "void"
664 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")
665 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
666 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
668 for info in argument_types:
669 if info.arg_conv is not None:
670 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
671 assert c_call_string is None
672 write_c("\t" + method_name + "(")
673 if argument_types[0].arg_conv_name is not None:
674 write_c(argument_types[0].arg_conv_name)
676 for info in argument_types:
677 if info.arg_conv_cleanup is not None:
678 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
683 out_java_struct = None
685 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
686 out_java_struct.write(out_java_struct_delta)
688 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
689 for line in out_java_struct_delta.splitlines():
690 out_java_struct.write(line + "\n")
692 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
693 assert struct_name.startswith("LDK")
694 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
695 unitary_enums.add(struct_name)
696 for idx, (struct_line, _) in enumerate(field_lines):
698 assert(struct_line == "typedef enum %s {" % struct_name)
699 elif idx == len(field_lines) - 3:
700 assert(struct_line.endswith("_Sentinel,"))
701 elif idx == len(field_lines) - 2:
702 assert(struct_line == "} %s;" % struct_name)
703 elif idx == len(field_lines) - 1:
704 assert(struct_line == "")
705 assert struct_name.startswith("LDK")
706 (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)
708 out_java_enum.write(native_file_out)
709 out_java.write(native_out)
711 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
712 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
715 tag_field_lines = union_enum_items["field_lines"]
716 contains_trait = False
717 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
719 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
720 elif idx == len(tag_field_lines) - 3:
721 assert(struct_line.endswith("_Sentinel,"))
722 elif idx == len(tag_field_lines) - 2:
723 assert(struct_line == "} %s_Tag;" % struct_name)
724 elif idx == len(tag_field_lines) - 1:
725 assert(struct_line == "")
727 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
729 if "LDK" + variant_name in union_enum_items:
730 enum_var_lines = union_enum_items["LDK" + variant_name]
731 for idx, (field, field_docs) in enumerate(enum_var_lines):
732 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
733 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
734 contains_trait |= field_ty.contains_trait
735 if field_docs is not None and doc_to_field_nullable(field_docs):
736 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
738 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
739 fields.append((field_conv, field_docs))
740 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
741 elif camel_to_snake(variant_name) in inline_enum_variants:
742 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
743 # docs through to there, and then potentially mark the field nullable.
744 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
745 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
746 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
747 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
748 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
750 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
751 contains_trait |= mapped.ty_info.contains_trait
752 fields.append((mapped, None))
753 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
755 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
756 complex_enums[struct_name] = contains_trait
758 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
759 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
761 out_java_enum.write(out_java_enum_addendum)
762 out_java.write(out_java_addendum)
763 write_c(out_c_addendum)
765 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
766 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
768 flattened_field_var_convs = []
769 for var_line in field_var_lines:
770 if var_line.group(1) in trait_structs:
771 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
772 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), var_line.group(2)))
773 for field_var in trait_structs[var_line.group(1)]:
774 if isinstance(field_var, ConvInfo):
775 flattened_field_var_convs.append(field_var)
777 path = var_line.group(2)
778 if len(field_var) > 2:
779 path = var_line.group(2) + "." + field_var[2]
780 flattened_field_var_convs.append((field_var[0], field_var[1], path))
782 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
783 field_var_convs.append(mapped)
784 flattened_field_var_convs.append(mapped)
785 trait_structs[struct_name] = flattened_field_var_convs
788 for fn_docs, fn_line in trait_fn_lines:
789 if fn_line == "cloned":
790 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
791 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
793 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
795 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
796 ret_ty_info.nullable = True
798 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
799 is_const = fn_line.group(4) is not None
802 for idx, arg in enumerate(fn_line.group(5).split(',')):
805 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
806 if arg_ty_info.var_name in nullable_params:
807 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
808 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
810 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
811 arg_tys.append(arg_conv_info)
812 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
814 (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)
815 write_c(out_c_addendum)
816 out_java_trait.write(out_java_trait_addendum)
817 out_java.write(out_java_addendum)
819 for fn_docs, fn_line in trait_fn_lines:
820 if fn_line == "cloned":
822 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
823 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
824 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
825 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"
826 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)
827 for idx, var_line in enumerate(field_var_lines):
828 if var_line.group(1) not in trait_structs:
829 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
830 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
831 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
832 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
834 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"
835 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)
837 def map_result(struct_name, res_ty, err_ty):
838 result_types.add(struct_name)
839 human_ty = struct_name.replace("LDKCResult", "Result")
840 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
841 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
842 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
843 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
844 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
845 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
846 out_java_struct.write(java_hu_struct)
848 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
849 field_ty = java_c_types(field_decl + " " + field_name, None)
850 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
851 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
854 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
855 fn_defn = owned_fn_defn
856 write_c("static inline " + fn_defn + "{\n")
857 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
858 write_c("\tret.is_owned = false;\n")
859 write_c("\treturn ret;\n")
860 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
861 fn_defn = owned_fn_defn
862 write_c("static inline " + fn_defn + "{\n")
863 if check_sfx is not None:
864 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
865 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
866 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
867 fn_defn = owned_fn_defn
868 write_c("static inline " + fn_defn + "{\n")
869 if check_sfx is not None:
870 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
871 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
874 fn_defn = ptr_fn_defn
875 write_c("static inline " + fn_defn + "{\n")
876 if check_sfx is not None:
877 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
878 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
881 dummy_line = fn_defn + ";\n"
882 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
884 def map_tuple(struct_name, field_lines):
885 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
886 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
887 out_java_struct.write(consts.map_tuple(struct_name))
889 for idx, (line, _) in enumerate(field_lines):
890 if idx != 0 and idx < len(field_lines) - 2:
891 ty_list.append(java_c_types(line.strip(';'), None))
892 tuple_types[struct_name] = (ty_list, struct_name)
894 # Map virtual getter functions
895 for idx, (line, _) in enumerate(field_lines):
896 if idx != 0 and idx < len(field_lines) - 2:
897 field_name = chr(ord('a') + idx - 1)
898 assert line.endswith(" " + field_name + ";")
899 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
901 out_java.write(consts.bindings_header)
902 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
903 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
905 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
906 out_java_struct.write(consts.common_base)
909 last_block_comment = None
912 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
914 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
915 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
916 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
917 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
918 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
919 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
920 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
921 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
922 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
923 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
924 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
925 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
926 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
927 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
928 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
930 union_enum_items = {}
931 result_ptr_struct_items = {}
933 if block_comment is not None:
934 if line.endswith("*/\n"):
935 last_block_comment = block_comment.strip("\n")
938 block_comment = block_comment + line.strip(" /*")
939 elif cur_block_obj is not None:
940 cur_block_obj = cur_block_obj + line
941 if line.startswith("} "):
945 obj_lines = cur_block_obj.split("\n")
947 result_contents = None
948 is_unitary_enum = False
949 is_union_enum = False
954 last_struct_block_comment = None
956 for idx, struct_line in enumerate(obj_lines):
957 if struct_line.strip().startswith("/*"):
958 block_comment = struct_line.strip(" /*")
959 if block_comment is not None:
960 if struct_line.endswith("*/"):
961 last_struct_block_comment = block_comment.strip("\n")
964 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
966 struct_name_match = struct_name_regex.match(struct_line)
967 if struct_name_match is not None:
968 struct_name = struct_name_match.group(3)
969 if struct_name_match.group(1) == "enum":
970 if not struct_name.endswith("_Tag"):
971 is_unitary_enum = True
974 elif struct_name_match.group(1) == "union":
976 if line_indicates_opaque_regex.match(struct_line):
978 result_match = line_indicates_result_regex.match(struct_line)
979 if result_match is not None:
980 result_contents = result_match.group(1)
981 vec_ty_match = line_indicates_vec_regex.match(struct_line)
982 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
983 vec_ty = vec_ty_match.group(2)
984 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
986 trait_fn_match = line_indicates_trait_regex.match(struct_line)
987 if trait_fn_match is not None:
988 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
989 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
990 if trait_clone_fn_match is not None:
991 trait_fn_lines.append((last_struct_block_comment, "cloned"))
992 field_var_match = line_field_var_regex.match(struct_line)
993 if field_var_match is not None:
994 field_var_lines.append(field_var_match)
995 field_lines.append((struct_line, last_struct_block_comment))
996 last_struct_block_comment = None
998 assert(struct_name is not None)
999 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))
1000 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))
1001 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))
1002 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))
1003 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))
1004 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))
1005 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))
1008 opaque_structs.add(struct_name)
1009 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
1010 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
1011 last_block_comment = None
1012 out_java_struct.write(out_opaque_struct_human)
1013 elif result_contents is not None:
1014 assert result_contents in result_ptr_struct_items
1015 res_ty, err_ty = result_ptr_struct_items[result_contents]
1016 map_result(struct_name, res_ty, err_ty)
1017 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1018 for line, _ in field_lines:
1019 if line.endswith("*result;"):
1020 res_ty = line[:-8].strip()
1021 elif line.endswith("*err;"):
1022 err_ty = line[:-5].strip()
1023 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1024 result_types.add(struct_name[:-3])
1026 map_tuple(struct_name, field_lines)
1027 elif vec_ty is not None:
1028 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1029 if ty_info.is_native_primitive:
1030 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1031 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1032 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1033 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1034 write_c("\treturn ret;\n}\n")
1035 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1036 ty_name = struct_name.replace("LDK", "")
1037 clone_fns.add(ty_name + "_clone")
1038 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1039 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1040 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1041 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1042 write_c("\t}\n\treturn ret;\n}\n")
1044 assert(struct_name.endswith("_Tag"))
1045 struct_name = struct_name[:-4]
1046 union_enum_items[struct_name] = {"field_lines": field_lines}
1047 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1048 enum_var_name = struct_name.split("_")
1049 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1050 elif struct_name in union_enum_items:
1053 for line, field_block_comment in field_lines:
1054 if line == " struct {":
1058 elif elem_items > -1:
1060 if line.startswith("struct "):
1062 elif line.startswith("enum "):
1064 split = line.split(" ")
1065 assert len(split) == 2
1066 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1069 # We don't currently support tuple variant with more than one element
1071 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1072 last_block_comment = None
1073 elif is_unitary_enum:
1074 map_unitary_enum(struct_name, field_lines, last_block_comment)
1075 last_block_comment = None
1076 elif len(trait_fn_lines) > 0:
1077 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1078 elif struct_name == "LDKTxOut":
1079 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1080 out_java_struct.write(consts.hu_struct_file_prefix)
1081 out_java_struct.write(consts.txout_defn)
1082 out_java_struct.write(consts.hu_struct_file_suffix)
1083 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1084 write_c(fn_line + " {")
1085 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1087 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1088 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1089 write_c(fn_line + " {")
1090 write_c("\treturn thing->value;")
1092 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1093 elif struct_name == "LDKBigEndianScalar":
1094 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1095 out_java_struct.write(consts.hu_struct_file_prefix)
1096 out_java_struct.write(consts.scalar_defn)
1097 out_java_struct.write(consts.hu_struct_file_suffix)
1098 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1099 write_c(fn_line + " {\n")
1100 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1101 write_c("\treturn ret;\n")
1103 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1105 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1106 # there's nothing heap-allocated inside it the C bindings don't bother
1107 # exposing a `_free` method. Instead, we have to manually write one here,
1108 # though it doesn't need to do anything, the autogenerated wrapper will do
1109 # the required FREE.
1110 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1111 write_c(fn_line + " {}\n")
1112 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1114 pass # Everything remaining is a byte[] of some form
1115 cur_block_obj = None
1117 fn_ptr = fn_ptr_regex.match(line)
1118 fn_ret_arr = fn_ret_arr_regex.match(line)
1119 reg_fn = reg_fn_regex.match(line)
1120 const_val = const_val_regex.match(line)
1122 if line.startswith("#include <"):
1124 elif line.startswith("/*"):
1125 if not line.endswith("*/\n"):
1126 block_comment = line.strip(" /*")
1127 elif line.startswith("typedef enum "):
1128 cur_block_obj = line
1129 elif line.startswith("typedef struct "):
1130 cur_block_obj = line
1131 elif line.startswith("typedef union "):
1132 cur_block_obj = line
1133 elif fn_ptr is not None:
1134 map_fn(line, fn_ptr, None, None, last_block_comment)
1135 last_block_comment = None
1136 elif fn_ret_arr is not None:
1137 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1138 last_block_comment = None
1139 elif reg_fn is not None:
1140 map_fn(line, reg_fn, None, None, last_block_comment)
1141 last_block_comment = None
1142 elif const_val_regex is not None:
1143 # TODO Map const variables
1146 assert(line == "\n")
1148 out_java.write(consts.bindings_footer())
1149 for struct_name in opaque_structs:
1150 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1151 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1152 for struct_name in trait_structs:
1153 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1154 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1155 for struct_name in complex_enums:
1156 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1157 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1158 for struct_name in result_types:
1159 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1160 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1161 for struct_name in tuple_types:
1162 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1163 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1164 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1166 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1167 out_c.write(consts.c_file_pfx)
1168 out_c.write(consts.init_str())
1170 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1171 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1172 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1173 util.write(consts.util_fn_sfx)