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") or fn_arg.startswith("LDKChainHash"):
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 elif fn_arg.startswith("LDKChainHash"):
143 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
144 assert var_is_arr_regex.match(fn_arg[8:])
145 rust_obj = "LDKThirtyTwoBytes"
147 elif fn_arg.startswith("LDKThirtyTwoBytes"):
148 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
149 assert var_is_arr_regex.match(fn_arg[8:])
150 rust_obj = "LDKThirtyTwoBytes"
152 elif fn_arg.startswith("LDKEightU16s"):
153 fn_arg = "uint16_t (*" + fn_arg[13:] + ")[8]"
154 assert var_is_arr_regex.match(fn_arg[9:])
155 rust_obj = "LDKEightU16s"
157 elif fn_arg.startswith("LDKU128"):
158 if fn_arg == "LDKU128":
159 fn_arg = "LDKU128 arg"
160 if fn_arg.startswith("LDKU128*") or fn_arg.startswith("LDKU128 *"):
161 fn_arg = "uint8_t (" + fn_arg[8:] + ")[16]"
163 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[16]"
164 assert var_is_arr_regex.match(fn_arg[8:])
166 arr_access = "le_bytes"
167 elif fn_arg.startswith("LDKTxid"):
168 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
169 assert var_is_arr_regex.match(fn_arg[8:])
170 rust_obj = "LDKThirtyTwoBytes"
172 elif fn_arg.startswith("LDKPublicKey"):
173 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
174 assert var_is_arr_regex.match(fn_arg[8:])
175 rust_obj = "LDKPublicKey"
176 arr_access = "compressed_form"
177 elif fn_arg.startswith("LDKSecretKey"):
178 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
179 assert var_is_arr_regex.match(fn_arg[8:])
180 rust_obj = "LDKSecretKey"
182 elif fn_arg.startswith("LDKSignature"):
183 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
184 assert var_is_arr_regex.match(fn_arg[8:])
185 rust_obj = "LDKSignature"
186 arr_access = "compact_form"
187 elif fn_arg.startswith("LDKRecoverableSignature"):
188 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
189 assert var_is_arr_regex.match(fn_arg[8:])
190 rust_obj = "LDKRecoverableSignature"
191 arr_access = "serialized_form"
192 elif fn_arg.startswith("LDKThreeBytes"):
193 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
194 assert var_is_arr_regex.match(fn_arg[8:])
195 rust_obj = "LDKThreeBytes"
197 elif fn_arg.startswith("LDKFourBytes"):
198 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
199 assert var_is_arr_regex.match(fn_arg[8:])
200 rust_obj = "LDKFourBytes"
202 elif fn_arg.startswith("LDKSixteenBytes"):
203 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
204 assert var_is_arr_regex.match(fn_arg[8:])
205 rust_obj = "LDKSixteenBytes"
207 elif fn_arg.startswith("LDKTwentyBytes"):
208 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
209 assert var_is_arr_regex.match(fn_arg[8:])
210 rust_obj = "LDKTwentyBytes"
212 elif fn_arg.startswith("LDKTwelveBytes"):
213 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
214 assert var_is_arr_regex.match(fn_arg[8:])
215 rust_obj = "LDKTwelveBytes"
217 elif fn_arg.startswith("LDKu8slice"):
218 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
219 assert var_is_arr_regex.match(fn_arg[8:])
220 rust_obj = "LDKu8slice"
222 elif fn_arg.startswith("LDKCVec_u8Z"):
223 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
224 rust_obj = "LDKCVec_u8Z"
225 assert var_is_arr_regex.match(fn_arg[8:])
227 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
228 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
229 rust_obj = "LDKTransaction"
230 assert var_is_arr_regex.match(fn_arg[8:])
232 elif fn_arg.startswith("LDKWitness ") or fn_arg == "LDKWitness":
233 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
234 rust_obj = "LDKWitness"
235 assert var_is_arr_regex.match(fn_arg[8:])
237 elif fn_arg.startswith("LDKCVec_"):
240 fn_arg = fn_arg.replace("*", "")
243 tyn = fn_arg[8:].split(" ")
244 assert tyn[0].endswith("Z")
248 new_arg = "LDK" + tyn[0][:-1]
250 new_arg = new_arg + " " + a
251 res = java_c_types(new_arg, ret_arr_len)
253 assert java_c_types_none_allowed
256 res.pass_by_ref = True
257 java_ty = consts.java_arr_ty_str(res.java_ty)
258 if res.is_native_primitive or res.passed_as_ptr:
259 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
260 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
261 nonnull_ptr=nonnull_ptr, is_const=is_const,
262 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
264 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
265 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
266 nonnull_ptr=nonnull_ptr, is_const=is_const,
267 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
270 contains_trait = False
273 java_type_plural = None
275 if fn_arg.startswith("void"):
279 fn_arg = fn_arg[4:].strip()
281 elif fn_arg.startswith("bool"):
282 java_ty = consts.c_type_map['bool'][0]
286 fn_arg = fn_arg[4:].strip()
288 elif fn_arg.startswith("uint8_t"):
289 mapped_type = consts.c_type_map['uint8_t']
290 java_ty = mapped_type[0]
294 fn_arg = fn_arg[7:].strip()
296 elif fn_arg.startswith("LDKU5") or fn_arg.startswith("LDKWitnessVersion"):
297 java_ty = consts.c_type_map['uint8_t'][0]
298 if fn_arg.startswith("LDKU5"):
301 fn_arg = fn_arg[6:].strip()
303 java_hu_ty = "WitnessVersion"
304 rust_obj = "LDKWitnessVersion"
305 fn_arg = fn_arg[18:].strip()
309 elif fn_arg.startswith("uint16_t"):
310 mapped_type = consts.c_type_map['uint16_t']
311 java_ty = mapped_type[0]
315 fn_arg = fn_arg[8:].strip()
317 elif fn_arg.startswith("uint32_t"):
318 mapped_type = consts.c_type_map['uint32_t']
319 java_ty = mapped_type[0]
323 fn_arg = fn_arg[8:].strip()
325 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
326 # TODO: uintptr_t is arch-dependent :(
327 mapped_type = consts.c_type_map['uint64_t']
328 java_ty = mapped_type[0]
330 if fn_arg.startswith("uint64_t"):
333 fn_arg = fn_arg[8:].strip()
335 java_ty = consts.usize_native_ty
336 c_ty = consts.usize_c_ty
338 rust_obj = "uintptr_t"
339 fn_arg = fn_arg[9:].strip()
341 elif is_const and fn_arg.startswith("char *"):
342 java_ty = consts.java_type_map["String"]
343 java_hu_ty = consts.java_hu_type_map["String"]
346 fn_ty_arg = "Ljava/lang/String;"
347 fn_arg = fn_arg[6:].strip()
348 elif fn_arg.startswith("LDKStr") or fn_arg.startswith("LDKAddress"):
351 java_ty = consts.java_type_map["String"]
352 java_hu_ty = consts.java_hu_type_map["String"]
354 fn_ty_arg = "Ljava/lang/String;"
355 if fn_arg.startswith("LDKAddress"):
356 fn_arg = fn_arg[10:].strip()
358 fn_arg = fn_arg[6:].strip()
361 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
362 java_ty = consts.c_type_map['uint32_t'][0]
363 java_hu_ty = "UnqualifiedError"
364 rust_obj = "LDKError"
368 fn_arg = fn_arg[8:].strip()
370 ma = var_ty_regex.match(fn_arg)
371 arr_ty = ma.group(1).strip()
372 if ma.group(1).strip() in unitary_enums:
373 assert ma.group(1).strip().startswith("LDK")
374 java_ty = ma.group(1).strip()[3:]
376 c_ty = consts.result_c_ty
377 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
378 fn_arg = ma.group(2).strip()
379 rust_obj = ma.group(1).strip()
381 c_ty = consts.ptr_c_ty
382 java_ty = consts.ptr_native_ty
383 java_hu_ty = ma.group(1).strip()
384 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
385 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
386 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
387 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
388 java_hu_ty = java_hu_ty.replace("LDK", "")
390 fn_arg = ma.group(2).strip()
391 rust_obj = ma.group(1).strip()
392 if rust_obj in trait_structs:
393 contains_trait = True
394 elif rust_obj in complex_enums:
395 contains_trait = complex_enums[rust_obj]
398 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
399 fn_arg = fn_arg.replace("*", "").strip()
401 c_ty = consts.ptr_c_ty
402 java_ty = consts.ptr_native_ty
405 var_is_arr = var_is_arr_regex.match(fn_arg)
407 if var_is_arr is not None or ret_arr_len is not None:
408 assert(not take_by_ptr)
410 # is there a special case for plurals?
411 if len(mapped_type) == 3:
412 java_ty = mapped_type[1]
413 java_hu_ty = mapped_type[2]
415 java_ty = java_ty + "[]"
417 if rust_obj == "LDKU128":
418 java_hu_ty = consts.u128_native_ty
419 c_ty = c_ty + "Array"
421 subty = java_c_types(arr_ty, None)
423 assert java_c_types_none_allowed
426 subty.pass_by_ref = True
428 if var_is_arr is not None:
429 if var_is_arr.group(1) == "":
430 return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
431 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
432 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
433 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,
434 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
435 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
437 if java_hu_ty is None:
439 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,
440 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,
441 contains_trait=contains_trait, subty=subty)
443 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
444 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
445 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
449 from gen_type_mapping import TypeMappingGenerator
450 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
452 with open(sys.argv[1]) as in_h:
454 reg_fn = reg_fn_regex.match(line)
455 if reg_fn is not None:
456 if reg_fn.group(2).endswith("_clone"):
457 clone_fns.add(reg_fn.group(2))
459 rty = java_c_types(reg_fn.group(1), None)
460 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
461 constructor_fns[rty.rust_obj] = reg_fn.group(3)
463 arr_fn = fn_ret_arr_regex.match(line)
464 if arr_fn is not None:
465 if arr_fn.group(2).endswith("_clone"):
466 clone_fns.add(arr_fn.group(2))
467 # No object constructors return arrays, as then they wouldn't be an object constructor
470 # Define some manual clones...
471 clone_fns.add("ThirtyTwoBytes_clone")
472 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")
475 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
476 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
477 write_c("\tif (sizeof(void*) == 4) {\n")
478 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
479 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
480 write_c("\t} else {\n")
481 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
482 write_c("\t\t// use bit 9 ^ bit 10.\n")
483 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
484 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
485 write_c("#ifdef LDK_DEBUG_BUILD\n")
486 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
487 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
488 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
489 write_c("\t\tp ^= 1ULL << 53;\n")
491 write_c("\t\treturn (void*)p;\n")
495 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
496 write_c("\tif(ptr < 4096) return true;\n")
497 write_c("\tif (sizeof(void*) == 4) {\n")
498 write_c("\t\treturn ptr & (1ULL << 32);\n")
499 write_c("\t} else {\n")
500 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
501 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
502 write_c("#ifdef LDK_DEBUG_BUILD\n")
503 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
504 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
505 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
507 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
511 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
512 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
513 write_c("\tif (sizeof(void*) == 4) {\n")
514 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
515 write_c("\t} else {\n")
516 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
517 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
518 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
519 write_c("#ifdef LDK_DEBUG_BUILD\n")
520 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
521 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
522 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
523 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
524 write_c("\t\tt ^= 1ULL << 53;\n")
526 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
527 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
528 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
529 write_c("\t\treturn t;\n")
533 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
535 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
536 util.write(consts.util_fn_pfx)
538 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
539 # Map a top-level function
540 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
541 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
542 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
543 method_return_type = re_match.group(1)
544 method_name = re_match.group(2)
545 method_comma_separated_arguments = re_match.group(3)
546 method_arguments = method_comma_separated_arguments.split(',')
548 if method_name.startswith("__"):
551 is_free = method_name.endswith("_free")
552 if method_name.startswith("COption") or method_name.startswith("CResult"):
553 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
554 expected_struct = "LDKC" + struct_meth
555 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
556 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
557 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
558 if method_name.startswith("C2Tuple"):
559 struct_meth = "Two" + tuple_name
560 expected_struct = "LDKC2" + tuple_name
562 struct_meth = "Three" + tuple_name
563 expected_struct = "LDKC3" + tuple_name
564 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
566 struct_meth = method_name.split("_")[0]
567 expected_struct = "LDK" + struct_meth
568 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
570 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
572 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
574 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
576 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
577 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
578 write_c("static inline " + meth_line + " {\n")
579 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
580 write_c(method_name + "(arg)")
581 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
582 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
583 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
586 default_constructor_args = {}
588 takes_self_ptr = False
590 for argument_index, argument in enumerate(method_arguments):
591 arg_ty = type_mapping_generator.java_c_types(argument, None)
592 argument_conversion_info = None
593 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
594 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
596 if argument_conversion_info.ty_info.is_ptr:
597 takes_self_ptr = True
598 elif arg_ty.var_name in params_nullable:
599 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
600 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
601 arg_ty_info = java_c_types(argument, None)
602 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
603 print(" The argument appears to require a move, or not clonable, and is nullable.")
604 print(" Normally for arguments that require a move and are not clonable, we split")
605 print(" the argument into the type's constructor's arguments and just use those to")
606 print(" construct a new object on the fly.")
607 print(" However, because the object is nullable, doing so would mean we can no")
608 print(" longer allow the user to pass null, as we now have an argument list instead.")
609 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
610 print(" It may or may not actually be a reference, but its the simplest mapping option")
611 print(" and also the only use of this code today.")
612 arg_ty_info.requires_clone = False
613 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
614 assert argument_conversion_info.nullable
615 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
617 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
619 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
620 if argument_conversion_info.rust_obj in constructor_fns:
622 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
623 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
624 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
625 continue # (void) is C lingo for "no arguments)
626 if explode_arg_conv.c_ty == "void":
628 if not argument_conversion_info.arg_name in default_constructor_args:
629 default_constructor_args[argument_conversion_info.arg_name] = []
630 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
631 argument_types.append(argument_conversion_info)
633 if not takes_self and return_type_info.java_hu_ty != struct_meth:
634 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
635 struct_meth_name = method_name
639 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
640 expected_struct in complex_enums or expected_struct in complex_enums or
641 expected_struct in result_types or expected_struct in tuple_types) and not is_free
642 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
643 not method_name.startswith("TxOut") and not method_name.startswith("BigEndianScalar") and
644 not method_name.startswith("_") and
645 method_name != "check_platform" and method_name != "Result_read" and
646 not expected_struct in unitary_enums and
647 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
648 or method_name.endswith("_read")))
650 # If we're adding a static method, and it returns a primitive or an array of primitives,
651 # and a variable conversion adds a reference on the return type (via `this`), skip the
652 # variable's conversion reference-add (as we obviously cannot need a reference).
653 if impl_on_utils and (return_type_info.is_native_primitive or
654 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
655 for arg in argument_types:
656 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
657 if "this" in arg.from_hu_conv[1]:
658 arg.from_hu_conv = (arg.from_hu_conv[0], "")
660 out_java.write("\t// " + line)
661 args_known = True # We no longer ever set this to false
662 (out_java_delta, out_c_delta, out_java_struct_delta) = \
663 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)
664 out_java.write(out_java_delta)
667 assert len(argument_types) == 1
668 assert return_type_info.c_ty == "void"
669 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")
670 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
671 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
673 for info in argument_types:
674 if info.arg_conv is not None:
675 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
676 assert c_call_string is None
677 write_c("\t" + method_name + "(")
678 if argument_types[0].arg_conv_name is not None:
679 write_c(argument_types[0].arg_conv_name)
681 for info in argument_types:
682 if info.arg_conv_cleanup is not None:
683 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
688 out_java_struct = None
690 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
691 out_java_struct.write(out_java_struct_delta)
693 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
694 for line in out_java_struct_delta.splitlines():
695 out_java_struct.write(line + "\n")
697 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
698 assert struct_name.startswith("LDK")
699 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
700 unitary_enums.add(struct_name)
701 for idx, (struct_line, _) in enumerate(field_lines):
703 assert(struct_line == "typedef enum %s {" % struct_name)
704 elif idx == len(field_lines) - 3:
705 assert(struct_line.endswith("_Sentinel,"))
706 elif idx == len(field_lines) - 2:
707 assert(struct_line == "} %s;" % struct_name)
708 elif idx == len(field_lines) - 1:
709 assert(struct_line == "")
710 assert struct_name.startswith("LDK")
711 (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)
713 out_java_enum.write(native_file_out)
714 out_java.write(native_out)
716 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
717 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
720 tag_field_lines = union_enum_items["field_lines"]
721 contains_trait = False
722 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
724 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
725 elif idx == len(tag_field_lines) - 3:
726 assert(struct_line.endswith("_Sentinel,"))
727 elif idx == len(tag_field_lines) - 2:
728 assert(struct_line == "} %s_Tag;" % struct_name)
729 elif idx == len(tag_field_lines) - 1:
730 assert(struct_line == "")
732 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
734 if "LDK" + variant_name in union_enum_items:
735 enum_var_lines = union_enum_items["LDK" + variant_name]
736 for idx, (field, field_docs) in enumerate(enum_var_lines):
737 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
738 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
739 contains_trait |= field_ty.contains_trait
740 if field_docs is not None and doc_to_field_nullable(field_docs):
741 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
743 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
744 fields.append((field_conv, field_docs))
745 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
746 elif camel_to_snake(variant_name) in inline_enum_variants:
747 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
748 # docs through to there, and then potentially mark the field nullable.
749 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
750 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
751 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
752 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
753 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
755 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
756 contains_trait |= mapped.ty_info.contains_trait
757 fields.append((mapped, None))
758 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
760 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
761 complex_enums[struct_name] = contains_trait
763 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
764 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
766 out_java_enum.write(out_java_enum_addendum)
767 out_java.write(out_java_addendum)
768 write_c(out_c_addendum)
770 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
771 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
773 flattened_field_var_convs = []
774 for var_line in field_var_lines:
775 if var_line.group(1) in trait_structs:
776 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
777 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), var_line.group(2)))
778 for field_var in trait_structs[var_line.group(1)]:
779 if isinstance(field_var, ConvInfo):
780 flattened_field_var_convs.append(field_var)
782 path = var_line.group(2)
783 if len(field_var) > 2:
784 path = var_line.group(2) + "." + field_var[2]
785 flattened_field_var_convs.append((field_var[0], field_var[1], path))
787 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
788 field_var_convs.append(mapped)
789 flattened_field_var_convs.append(mapped)
790 trait_structs[struct_name] = flattened_field_var_convs
793 for fn_docs, fn_line in trait_fn_lines:
794 if fn_line == "cloned":
795 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
796 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
798 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
800 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
801 ret_ty_info.nullable = True
803 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
804 is_const = fn_line.group(4) is not None
807 for idx, arg in enumerate(fn_line.group(5).split(',')):
810 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
811 if arg_ty_info.var_name in nullable_params:
812 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
813 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
815 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
816 arg_tys.append(arg_conv_info)
817 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
819 (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)
820 write_c(out_c_addendum)
821 out_java_trait.write(out_java_trait_addendum)
822 out_java.write(out_java_addendum)
824 for fn_docs, fn_line in trait_fn_lines:
825 if fn_line == "cloned":
827 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
828 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
829 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
830 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"
831 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)
832 for idx, var_line in enumerate(field_var_lines):
833 if var_line.group(1) not in trait_structs:
834 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
835 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
836 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
837 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
839 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"
840 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)
842 def map_result(struct_name, res_ty, err_ty):
843 result_types.add(struct_name)
844 human_ty = struct_name.replace("LDKCResult", "Result")
845 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
846 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
847 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
848 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
849 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
850 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
851 out_java_struct.write(java_hu_struct)
853 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
854 field_ty = java_c_types(field_decl + " " + field_name, None)
855 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
856 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
859 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
860 fn_defn = owned_fn_defn
861 write_c("static inline " + fn_defn + "{\n")
862 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
863 write_c("\tret.is_owned = false;\n")
864 write_c("\treturn ret;\n")
865 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
866 fn_defn = owned_fn_defn
867 write_c("static inline " + fn_defn + "{\n")
868 if check_sfx is not None:
869 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
870 write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
871 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
872 fn_defn = owned_fn_defn
873 write_c("static inline " + fn_defn + "{\n")
874 if check_sfx is not None:
875 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
876 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
879 fn_defn = ptr_fn_defn
880 write_c("static inline " + fn_defn + "{\n")
881 if check_sfx is not None:
882 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
883 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
886 dummy_line = fn_defn + ";\n"
887 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
889 def map_tuple(struct_name, field_lines):
890 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
891 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
892 out_java_struct.write(consts.map_tuple(struct_name))
894 for idx, (line, _) in enumerate(field_lines):
895 if idx != 0 and idx < len(field_lines) - 2:
896 ty_list.append(java_c_types(line.strip(';'), None))
897 tuple_types[struct_name] = (ty_list, struct_name)
899 # Map virtual getter functions
900 for idx, (line, _) in enumerate(field_lines):
901 if idx != 0 and idx < len(field_lines) - 2:
902 field_name = chr(ord('a') + idx - 1)
903 assert line.endswith(" " + field_name + ";")
904 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
906 out_java.write(consts.bindings_header)
907 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
908 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
910 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
911 out_java_struct.write(consts.common_base)
914 last_block_comment = None
917 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
919 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
920 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
921 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
922 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
923 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
924 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
925 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
926 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
927 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
928 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
929 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
930 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
931 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
932 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
933 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
935 union_enum_items = {}
936 result_ptr_struct_items = {}
938 if block_comment is not None:
939 if line.endswith("*/\n"):
940 last_block_comment = block_comment.strip("\n")
943 block_comment = block_comment + line.strip(" /*")
944 elif cur_block_obj is not None:
945 cur_block_obj = cur_block_obj + line
946 if line.startswith("} "):
950 obj_lines = cur_block_obj.split("\n")
952 result_contents = None
953 is_unitary_enum = False
954 is_union_enum = False
959 last_struct_block_comment = None
961 for idx, struct_line in enumerate(obj_lines):
962 if struct_line.strip().startswith("/*"):
963 block_comment = struct_line.strip(" /*")
964 if block_comment is not None:
965 if struct_line.endswith("*/"):
966 last_struct_block_comment = block_comment.strip("\n")
969 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
971 struct_name_match = struct_name_regex.match(struct_line)
972 if struct_name_match is not None:
973 struct_name = struct_name_match.group(3)
974 if struct_name_match.group(1) == "enum":
975 if not struct_name.endswith("_Tag"):
976 is_unitary_enum = True
979 elif struct_name_match.group(1) == "union":
981 if line_indicates_opaque_regex.match(struct_line):
983 result_match = line_indicates_result_regex.match(struct_line)
984 if result_match is not None:
985 result_contents = result_match.group(1)
986 vec_ty_match = line_indicates_vec_regex.match(struct_line)
987 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
988 vec_ty = vec_ty_match.group(2)
989 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
991 trait_fn_match = line_indicates_trait_regex.match(struct_line)
992 if trait_fn_match is not None:
993 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
994 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
995 if trait_clone_fn_match is not None:
996 trait_fn_lines.append((last_struct_block_comment, "cloned"))
997 field_var_match = line_field_var_regex.match(struct_line)
998 if field_var_match is not None:
999 field_var_lines.append(field_var_match)
1000 field_lines.append((struct_line, last_struct_block_comment))
1001 last_struct_block_comment = None
1003 assert(struct_name is not None)
1004 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))
1005 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))
1006 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))
1007 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))
1008 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))
1009 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))
1010 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))
1013 opaque_structs.add(struct_name)
1014 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
1015 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
1016 last_block_comment = None
1017 out_java_struct.write(out_opaque_struct_human)
1018 elif result_contents is not None:
1019 assert result_contents in result_ptr_struct_items
1020 res_ty, err_ty = result_ptr_struct_items[result_contents]
1021 map_result(struct_name, res_ty, err_ty)
1022 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1023 for line, _ in field_lines:
1024 if line.endswith("*result;"):
1025 res_ty = line[:-8].strip()
1026 elif line.endswith("*err;"):
1027 err_ty = line[:-5].strip()
1028 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1029 result_types.add(struct_name[:-3])
1031 map_tuple(struct_name, field_lines)
1032 elif vec_ty is not None:
1033 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1034 if ty_info.is_native_primitive:
1035 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1036 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1037 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1038 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1039 write_c("\treturn ret;\n}\n")
1040 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1041 ty_name = struct_name.replace("LDK", "")
1042 clone_fns.add(ty_name + "_clone")
1043 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1044 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1045 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1046 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1047 write_c("\t}\n\treturn ret;\n}\n")
1049 assert(struct_name.endswith("_Tag"))
1050 struct_name = struct_name[:-4]
1051 union_enum_items[struct_name] = {"field_lines": field_lines}
1052 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1053 enum_var_name = struct_name.split("_")
1054 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1055 elif struct_name in union_enum_items:
1058 for line, field_block_comment in field_lines:
1059 if line == " struct {":
1063 elif elem_items > -1:
1065 if line.startswith("struct "):
1067 elif line.startswith("enum "):
1069 split = line.split(" ")
1070 assert len(split) == 2
1071 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1074 # We don't currently support tuple variant with more than one element
1076 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1077 last_block_comment = None
1078 elif is_unitary_enum:
1079 map_unitary_enum(struct_name, field_lines, last_block_comment)
1080 last_block_comment = None
1081 elif len(trait_fn_lines) > 0:
1082 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1083 elif struct_name == "LDKTxOut":
1084 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1085 out_java_struct.write(consts.hu_struct_file_prefix)
1086 out_java_struct.write(consts.txout_defn)
1087 out_java_struct.write(consts.hu_struct_file_suffix)
1088 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1089 write_c(fn_line + " {")
1090 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1092 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1093 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1094 write_c(fn_line + " {")
1095 write_c("\treturn thing->value;")
1097 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1098 elif struct_name == "LDKBigEndianScalar":
1099 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1100 out_java_struct.write(consts.hu_struct_file_prefix)
1101 out_java_struct.write(consts.scalar_defn)
1102 out_java_struct.write(consts.hu_struct_file_suffix)
1103 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1104 write_c(fn_line + " {\n")
1105 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1106 write_c("\treturn ret;\n")
1108 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1110 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1111 # there's nothing heap-allocated inside it the C bindings don't bother
1112 # exposing a `_free` method. Instead, we have to manually write one here,
1113 # though it doesn't need to do anything, the autogenerated wrapper will do
1114 # the required FREE.
1115 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1116 write_c(fn_line + " {}\n")
1117 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1119 pass # Everything remaining is a byte[] of some form
1120 cur_block_obj = None
1122 fn_ptr = fn_ptr_regex.match(line)
1123 fn_ret_arr = fn_ret_arr_regex.match(line)
1124 reg_fn = reg_fn_regex.match(line)
1125 const_val = const_val_regex.match(line)
1127 if line.startswith("#include <"):
1129 elif line.startswith("/*"):
1130 if not line.endswith("*/\n"):
1131 block_comment = line.strip(" /*")
1132 elif line.startswith("typedef enum "):
1133 cur_block_obj = line
1134 elif line.startswith("typedef struct "):
1135 cur_block_obj = line
1136 elif line.startswith("typedef union "):
1137 cur_block_obj = line
1138 elif fn_ptr is not None:
1139 map_fn(line, fn_ptr, None, None, last_block_comment)
1140 last_block_comment = None
1141 elif fn_ret_arr is not None:
1142 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1143 last_block_comment = None
1144 elif reg_fn is not None:
1145 map_fn(line, reg_fn, None, None, last_block_comment)
1146 last_block_comment = None
1147 elif const_val_regex is not None:
1148 # TODO Map const variables
1151 assert(line == "\n")
1153 out_java.write(consts.bindings_footer())
1154 for struct_name in opaque_structs:
1155 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1156 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1157 for struct_name in trait_structs:
1158 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1159 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1160 for struct_name in complex_enums:
1161 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1162 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1163 for struct_name in result_types:
1164 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1165 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1166 for struct_name in tuple_types:
1167 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1168 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1169 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1171 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1172 out_c.write(consts.c_file_pfx)
1173 out_c.write(consts.init_str())
1175 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1176 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1177 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1178 util.write(consts.util_fn_sfx)