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 target-tuple")
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 if "apple" in sys.argv[8]:
24 target = java_strings.Target.MACOS
25 elif sys.argv[6] == "typescript":
26 import typescript_strings
27 from typescript_strings import Consts
28 target = typescript_strings.Target.NODEJS
29 if len(sys.argv) == 8 and sys.argv[7] == 'browser':
30 target = typescript_strings.Target.BROWSER
31 elif sys.argv[6] == "c_sharp":
33 from csharp_strings import Consts
34 target = csharp_strings.Target.CSHARP
35 elif sys.argv[6] == "python":
37 from python_strings import Consts
38 target = python_strings.Target.PYTHON
40 print("Only java, typescript, python, or c_sharp can be set for lang")
43 consts = Consts(DEBUG, target=target, outdir=sys.argv[4])
45 local_git_version = os.getenv("LDK_GARBAGECOLLECTED_GIT_OVERRIDE")
46 if local_git_version is None:
47 local_git_version = subprocess.check_output(["git", "describe", '--tag', '--dirty']).decode("utf-8").strip()
49 from bindingstypes import *
56 def camel_to_snake(s):
57 # Convert camel case to snake case, in a way that appears to match cbindgen
63 if lastchar.isupper():
64 if not char.isupper() and not lastund:
69 ret = ret + lastchar.lower()
72 if char.isupper() and not lastund:
80 return (ret + lastchar.lower()).strip("_")
82 def doc_to_field_nullable(doc):
85 for line in doc.splitlines():
86 if "Note that this (or a relevant inner pointer) may be NULL or all-0s to represent None" in line:
90 def doc_to_params_ret_nullable(doc):
95 for line in doc.splitlines():
96 if "may be NULL or all-0s to represent None" not in line:
98 if "Note that the return value" in line:
100 elif "Note that " in line:
101 param = line.split("Note that ")[1].split(" ")[0]
103 return (params, ret_null)
105 unitary_enums = set()
106 # Map from enum name to "contains trait object"
108 opaque_structs = set()
113 var_is_arr_regex = re.compile("\(\* ?([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
114 var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
115 java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
116 def java_c_types(fn_arg, ret_arr_len):
117 fn_arg = fn_arg.strip()
118 if fn_arg.startswith("MUST_USE_RES "):
121 if fn_arg.startswith("const "):
124 if fn_arg.startswith("struct "):
126 if fn_arg.startswith("enum "):
128 nonnull_ptr = "NONNULL_PTR" in fn_arg
129 fn_arg = fn_arg.replace("NONNULL_PTR", "")
136 if fn_arg.startswith("LDKPaymentPreimage") or fn_arg.startswith("LDKPaymentSecret") or fn_arg.startswith("LDKPaymentHash") or fn_arg.startswith("LDKChainHash"):
137 if fn_arg.startswith("LDKPaymentPreimage"):
138 fn_arg = "uint8_t (*" + fn_arg[19:] + ")[32]"
139 elif fn_arg.startswith("LDKPaymentSecret"):
140 fn_arg = "uint8_t (*" + fn_arg[17:] + ")[32]"
141 elif fn_arg.startswith("LDKPaymentHash"):
142 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[32]"
143 elif fn_arg.startswith("LDKChainHash"):
144 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
145 assert var_is_arr_regex.match(fn_arg[8:])
146 rust_obj = "LDKThirtyTwoBytes"
148 elif fn_arg.startswith("LDKThirtyTwoBytes"):
149 fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
150 assert var_is_arr_regex.match(fn_arg[8:])
151 rust_obj = "LDKThirtyTwoBytes"
153 elif fn_arg.startswith("LDKEightU16s"):
154 fn_arg = "uint16_t (*" + fn_arg[13:] + ")[8]"
155 assert var_is_arr_regex.match(fn_arg[9:])
156 rust_obj = "LDKEightU16s"
158 elif fn_arg.startswith("LDKU128"):
159 if fn_arg == "LDKU128":
160 fn_arg = "LDKU128 arg"
161 if fn_arg.startswith("LDKU128*") or fn_arg.startswith("LDKU128 *"):
162 fn_arg = "uint8_t (" + fn_arg[8:] + ")[16]"
164 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[16]"
165 assert var_is_arr_regex.match(fn_arg[8:])
167 arr_access = "le_bytes"
168 elif fn_arg.startswith("LDKTxid"):
169 fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
170 assert var_is_arr_regex.match(fn_arg[8:])
171 rust_obj = "LDKThirtyTwoBytes"
173 elif fn_arg.startswith("LDKPublicKey"):
174 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
175 assert var_is_arr_regex.match(fn_arg[8:])
176 rust_obj = "LDKPublicKey"
177 arr_access = "compressed_form"
178 elif fn_arg.startswith("LDKSecretKey"):
179 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
180 assert var_is_arr_regex.match(fn_arg[8:])
181 rust_obj = "LDKSecretKey"
183 elif fn_arg.startswith("LDKSignature"):
184 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
185 assert var_is_arr_regex.match(fn_arg[8:])
186 rust_obj = "LDKSignature"
187 arr_access = "compact_form"
188 elif fn_arg.startswith("LDKRecoverableSignature"):
189 fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
190 assert var_is_arr_regex.match(fn_arg[8:])
191 rust_obj = "LDKRecoverableSignature"
192 arr_access = "serialized_form"
193 elif fn_arg.startswith("LDKThreeBytes"):
194 fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
195 assert var_is_arr_regex.match(fn_arg[8:])
196 rust_obj = "LDKThreeBytes"
198 elif fn_arg.startswith("LDKFourBytes"):
199 fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
200 assert var_is_arr_regex.match(fn_arg[8:])
201 rust_obj = "LDKFourBytes"
203 elif fn_arg.startswith("LDKSixteenBytes"):
204 fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
205 assert var_is_arr_regex.match(fn_arg[8:])
206 rust_obj = "LDKSixteenBytes"
208 elif fn_arg.startswith("LDKTwentyBytes"):
209 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
210 assert var_is_arr_regex.match(fn_arg[8:])
211 rust_obj = "LDKTwentyBytes"
213 elif fn_arg.startswith("LDKTwelveBytes"):
214 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
215 assert var_is_arr_regex.match(fn_arg[8:])
216 rust_obj = "LDKTwelveBytes"
218 elif fn_arg.startswith("LDKu8slice"):
219 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
220 assert var_is_arr_regex.match(fn_arg[8:])
221 rust_obj = "LDKu8slice"
223 elif fn_arg.startswith("LDKCVec_u8Z"):
224 fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
225 rust_obj = "LDKCVec_u8Z"
226 assert var_is_arr_regex.match(fn_arg[8:])
228 elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
229 fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
230 rust_obj = "LDKTransaction"
231 assert var_is_arr_regex.match(fn_arg[8:])
233 elif fn_arg.startswith("LDKWitness ") or fn_arg == "LDKWitness":
234 fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
235 rust_obj = "LDKWitness"
236 assert var_is_arr_regex.match(fn_arg[8:])
238 elif fn_arg.startswith("LDKCVec_"):
241 fn_arg = fn_arg.replace("*", "")
244 tyn = fn_arg[8:].split(" ")
245 assert tyn[0].endswith("Z")
249 new_arg = "LDK" + tyn[0][:-1]
251 new_arg = new_arg + " " + a
252 res = java_c_types(new_arg, ret_arr_len)
254 assert java_c_types_none_allowed
257 res.pass_by_ref = True
258 java_ty = consts.java_arr_ty_str(res.java_ty)
259 if res.is_native_primitive or res.passed_as_ptr:
260 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
261 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
262 nonnull_ptr=nonnull_ptr, is_const=is_const,
263 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
265 return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
266 java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
267 nonnull_ptr=nonnull_ptr, is_const=is_const,
268 var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
271 contains_trait = False
274 java_type_plural = None
276 if fn_arg.startswith("void"):
280 fn_arg = fn_arg[4:].strip()
282 elif fn_arg.startswith("bool"):
283 java_ty = consts.c_type_map['bool'][0]
287 fn_arg = fn_arg[4:].strip()
289 elif fn_arg.startswith("uint8_t"):
290 mapped_type = consts.c_type_map['uint8_t']
291 java_ty = mapped_type[0]
295 fn_arg = fn_arg[7:].strip()
297 elif fn_arg.startswith("LDKU5") or fn_arg.startswith("LDKWitnessVersion"):
298 java_ty = consts.c_type_map['uint8_t'][0]
299 if fn_arg.startswith("LDKU5"):
302 fn_arg = fn_arg[6:].strip()
304 java_hu_ty = "WitnessVersion"
305 rust_obj = "LDKWitnessVersion"
306 fn_arg = fn_arg[18:].strip()
310 elif fn_arg.startswith("uint16_t"):
311 mapped_type = consts.c_type_map['uint16_t']
312 java_ty = mapped_type[0]
316 fn_arg = fn_arg[8:].strip()
318 elif fn_arg.startswith("uint32_t"):
319 mapped_type = consts.c_type_map['uint32_t']
320 java_ty = mapped_type[0]
324 fn_arg = fn_arg[8:].strip()
326 elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
327 # TODO: uintptr_t is arch-dependent :(
328 mapped_type = consts.c_type_map['uint64_t']
329 java_ty = mapped_type[0]
331 if fn_arg.startswith("uint64_t"):
334 fn_arg = fn_arg[8:].strip()
336 java_ty = consts.usize_native_ty
337 c_ty = consts.usize_c_ty
339 rust_obj = "uintptr_t"
340 fn_arg = fn_arg[9:].strip()
342 elif is_const and fn_arg.startswith("char *"):
343 java_ty = consts.java_type_map["String"]
344 java_hu_ty = consts.java_hu_type_map["String"]
347 fn_ty_arg = "Ljava/lang/String;"
348 fn_arg = fn_arg[6:].strip()
349 elif fn_arg.startswith("LDKStr") or fn_arg.startswith("LDKAddress"):
352 java_ty = consts.java_type_map["String"]
353 java_hu_ty = consts.java_hu_type_map["String"]
355 fn_ty_arg = "Ljava/lang/String;"
356 if fn_arg.startswith("LDKAddress"):
357 fn_arg = fn_arg[10:].strip()
359 fn_arg = fn_arg[6:].strip()
362 elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError":
363 java_ty = consts.c_type_map['uint32_t'][0]
364 java_hu_ty = "UnqualifiedError"
365 rust_obj = "LDKError"
369 fn_arg = fn_arg[8:].strip()
371 ma = var_ty_regex.match(fn_arg)
372 arr_ty = ma.group(1).strip()
373 if ma.group(1).strip() in unitary_enums:
374 assert ma.group(1).strip().startswith("LDK")
375 java_ty = ma.group(1).strip()[3:]
377 c_ty = consts.result_c_ty
378 fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
379 fn_arg = ma.group(2).strip()
380 rust_obj = ma.group(1).strip()
382 c_ty = consts.ptr_c_ty
383 java_ty = consts.ptr_native_ty
384 java_hu_ty = ma.group(1).strip()
385 java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
386 java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
387 java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
388 java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
389 java_hu_ty = java_hu_ty.replace("LDK", "")
391 fn_arg = ma.group(2).strip()
392 rust_obj = ma.group(1).strip()
393 if rust_obj in trait_structs:
394 contains_trait = True
395 elif rust_obj in complex_enums:
396 contains_trait = complex_enums[rust_obj]
399 if fn_arg.startswith(" *") or fn_arg.startswith("*"):
400 fn_arg = fn_arg.replace("*", "").strip()
402 c_ty = consts.ptr_c_ty
403 java_ty = consts.ptr_native_ty
406 var_is_arr = var_is_arr_regex.match(fn_arg)
408 if var_is_arr is not None or ret_arr_len is not None:
409 assert(not take_by_ptr)
411 # is there a special case for plurals?
412 if len(mapped_type) == 3:
413 java_ty = mapped_type[1]
414 java_hu_ty = mapped_type[2]
416 java_ty = java_ty + "[]"
418 if rust_obj == "LDKU128":
419 java_hu_ty = consts.u128_native_ty
420 c_ty = c_ty + "Array"
422 subty = java_c_types(arr_ty, None)
424 assert java_c_types_none_allowed
427 subty.pass_by_ref = True
429 if var_is_arr is not None:
430 if var_is_arr.group(1) == "":
431 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,
432 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
433 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
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, is_const=is_const,
435 passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
436 arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
438 if java_hu_ty is None:
440 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,
441 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,
442 contains_trait=contains_trait, subty=subty)
444 fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
445 fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
446 reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
450 from gen_type_mapping import TypeMappingGenerator
451 type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
453 with open(sys.argv[1]) as in_h:
455 reg_fn = reg_fn_regex.match(line)
456 if reg_fn is not None:
457 if reg_fn.group(2).endswith("_clone"):
458 clone_fns.add(reg_fn.group(2))
460 rty = java_c_types(reg_fn.group(1), None)
461 if rty is not None and not rty.is_native_primitive and reg_fn.group(2) == rty.java_hu_ty + "_new":
462 constructor_fns[rty.rust_obj] = reg_fn.group(3)
464 arr_fn = fn_ret_arr_regex.match(line)
465 if arr_fn is not None:
466 if arr_fn.group(2).endswith("_clone"):
467 clone_fns.add(arr_fn.group(2))
468 # No object constructors return arrays, as then they wouldn't be an object constructor
471 # Define some manual clones...
472 clone_fns.add("ThirtyTwoBytes_clone")
473 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")
476 write_c("static inline void* untag_ptr(uint64_t ptr) {\n")
477 write_c("\tif (ptr < 4096) return (void*)ptr;\n")
478 write_c("\tif (sizeof(void*) == 4) {\n")
479 write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n")
480 write_c("\t\treturn (void*)(uintptr_t)ptr;\n")
481 write_c("\t} else {\n")
482 write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n")
483 write_c("\t\t// use bit 9 ^ bit 10.\n")
484 write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
485 write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n")
486 write_c("#ifdef LDK_DEBUG_BUILD\n")
487 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
488 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
489 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
490 write_c("\t\tp ^= 1ULL << 53;\n")
492 write_c("\t\treturn (void*)p;\n")
496 write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n")
497 write_c("\tif(ptr < 4096) return true;\n")
498 write_c("\tif (sizeof(void*) == 4) {\n")
499 write_c("\t\treturn ptr & (1ULL << 32);\n")
500 write_c("\t} else {\n")
501 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
502 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
503 write_c("#ifdef LDK_DEBUG_BUILD\n")
504 write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n")
505 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
506 write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n")
508 write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n")
512 write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n")
513 write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n")
514 write_c("\tif (sizeof(void*) == 4) {\n")
515 write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n")
516 write_c("\t} else {\n")
517 write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n")
518 write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n")
519 write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n")
520 write_c("#ifdef LDK_DEBUG_BUILD\n")
521 write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n")
522 write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n")
523 write_c("\t\tCHECK(ninth_bit == tenth_bit);\n")
524 write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n")
525 write_c("\t\tt ^= 1ULL << 53;\n")
527 write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n")
528 write_c("\t\tCHECK(untag_ptr(t) == ptr);\n")
529 #write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n")
530 write_c("\t\treturn t;\n")
534 java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order
536 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
537 util.write(consts.util_fn_pfx)
539 with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", "w") as out_java:
540 # Map a top-level function
541 def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
542 map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, False)
543 def map_fn_with_ref_option(line, re_match, ret_arr_len, c_call_string, doc_comment, force_holds_ref):
544 method_return_type = re_match.group(1)
545 method_name = re_match.group(2)
546 method_comma_separated_arguments = re_match.group(3)
547 method_arguments = method_comma_separated_arguments.split(',')
549 if method_name.startswith("__"):
552 is_free = method_name.endswith("_free")
553 if method_name.startswith("COption") or method_name.startswith("CResult"):
554 struct_meth = method_name.rsplit("Z", 1)[0][1:] + "Z"
555 expected_struct = "LDKC" + struct_meth
556 struct_meth_name = method_name[len(struct_meth) + 1:].strip("_")
557 elif method_name.startswith("C2Tuple") or method_name.startswith("C3Tuple"):
558 tuple_name = method_name.rsplit("Z", 1)[0][2:] + "Z"
559 if method_name.startswith("C2Tuple"):
560 struct_meth = "Two" + tuple_name
561 expected_struct = "LDKC2" + tuple_name
563 struct_meth = "Three" + tuple_name
564 expected_struct = "LDKC3" + tuple_name
565 struct_meth_name = method_name[len(tuple_name) + 2:].strip("_")
567 struct_meth = method_name.split("_")[0]
568 expected_struct = "LDK" + struct_meth
569 struct_meth_name = method_name[len(struct_meth) + 1 if len(struct_meth) != 0 else 0:].strip("_")
571 (params_nullable, ret_nullable) = doc_to_params_ret_nullable(doc_comment)
573 return_type_info = type_mapping_generator.map_nullable_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
575 return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref)
577 if method_name.endswith("_clone") and expected_struct not in unitary_enums:
578 meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)"
579 write_c("static inline " + meth_line + " {\n")
580 write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t"))
581 write_c(method_name + "(arg)")
582 write_c(return_type_info.ret_conv[1].replace("\n", "\n\t"))
583 write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n")
584 map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None)
587 default_constructor_args = {}
589 takes_self_ptr = False
591 for argument_index, argument in enumerate(method_arguments):
592 arg_ty = type_mapping_generator.java_c_types(argument, None)
593 argument_conversion_info = None
594 if argument_index == 0 and arg_ty.java_hu_ty == struct_meth:
595 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
597 if argument_conversion_info.ty_info.is_ptr:
598 takes_self_ptr = True
599 elif arg_ty.var_name in params_nullable:
600 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, True)
601 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
602 arg_ty_info = java_c_types(argument, None)
603 print("WARNING: Remapping argument " + arg_ty_info.var_name + " of function " + method_name + " to a reference")
604 print(" The argument appears to require a move, or not clonable, and is nullable.")
605 print(" Normally for arguments that require a move and are not clonable, we split")
606 print(" the argument into the type's constructor's arguments and just use those to")
607 print(" construct a new object on the fly.")
608 print(" However, because the object is nullable, doing so would mean we can no")
609 print(" longer allow the user to pass null, as we now have an argument list instead.")
610 print(" Thus, we blindly assume its really an Option<&Type> instead of an Option<Type>.")
611 print(" It may or may not actually be a reference, but its the simplest mapping option")
612 print(" and also the only use of this code today.")
613 arg_ty_info.requires_clone = False
614 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty_info, False, None, is_free, True, True)
615 assert argument_conversion_info.nullable
616 assert argument_conversion_info.arg_conv is not None and "WARNING" not in argument_conversion_info.arg_conv
618 argument_conversion_info = type_mapping_generator.map_type_with_info(arg_ty, False, None, is_free, True, False)
620 if argument_conversion_info.arg_conv is not None and "WARNING" in argument_conversion_info.arg_conv:
621 if argument_conversion_info.rust_obj in constructor_fns:
623 for explode_idx, explode_arg in enumerate(constructor_fns[argument_conversion_info.rust_obj].split(',')):
624 explode_arg_conv = type_mapping_generator.map_type(explode_arg, False, None, False, True)
625 if explode_idx == 0 and explode_arg_conv.c_ty == "void":
626 continue # (void) is C lingo for "no arguments)
627 if explode_arg_conv.c_ty == "void":
629 if not argument_conversion_info.arg_name in default_constructor_args:
630 default_constructor_args[argument_conversion_info.arg_name] = []
631 default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
632 argument_types.append(argument_conversion_info)
634 if not takes_self and return_type_info.java_hu_ty != struct_meth:
635 if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
636 struct_meth_name = method_name
640 impl_on_struct = (expected_struct in opaque_structs or expected_struct in trait_structs or
641 expected_struct in complex_enums or expected_struct in complex_enums or
642 expected_struct in result_types or expected_struct in tuple_types) and not is_free
643 impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and
644 not method_name.startswith("TxOut") and not method_name.startswith("BigEndianScalar") and
645 not method_name.startswith("_") and
646 method_name != "check_platform" and method_name != "Result_read" and
647 not expected_struct in unitary_enums and
648 ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
649 or method_name.endswith("_read")))
651 # If we're adding a static method, and it returns a primitive or an array of primitives,
652 # and a variable conversion adds a reference on the return type (via `this`), skip the
653 # variable's conversion reference-add (as we obviously cannot need a reference).
654 if impl_on_utils and (return_type_info.is_native_primitive or
655 (return_type_info.ty_info.subty is not None and return_type_info.ty_info.subty.is_native_primitive)):
656 for arg in argument_types:
657 if arg.from_hu_conv is not None and arg.from_hu_conv[1] != "":
658 if "this" in arg.from_hu_conv[1]:
659 arg.from_hu_conv = (arg.from_hu_conv[0], "")
661 out_java.write("\t// " + line)
662 args_known = True # We no longer ever set this to false
663 (out_java_delta, out_c_delta, out_java_struct_delta) = \
664 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)
665 out_java.write(out_java_delta)
668 assert len(argument_types) == 1
669 assert return_type_info.c_ty == "void"
670 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")
671 if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs:
672 write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n")
674 for info in argument_types:
675 if info.arg_conv is not None:
676 write_c("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
677 assert c_call_string is None
678 write_c("\t" + method_name + "(")
679 if argument_types[0].arg_conv_name is not None:
680 write_c(argument_types[0].arg_conv_name)
682 for info in argument_types:
683 if info.arg_conv_cleanup is not None:
684 write_c("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
689 out_java_struct = None
691 out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
692 out_java_struct.write(out_java_struct_delta)
694 out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
695 for line in out_java_struct_delta.splitlines():
696 out_java_struct.write(line + "\n")
698 def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
699 assert struct_name.startswith("LDK")
700 with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
701 unitary_enums.add(struct_name)
702 for idx, (struct_line, _) in enumerate(field_lines):
704 assert(struct_line == "typedef enum %s {" % struct_name)
705 elif idx == len(field_lines) - 3:
706 assert(struct_line.endswith("_Sentinel,"))
707 elif idx == len(field_lines) - 2:
708 assert(struct_line == "} %s;" % struct_name)
709 elif idx == len(field_lines) - 1:
710 assert(struct_line == "")
711 assert struct_name.startswith("LDK")
712 (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)
714 out_java_enum.write(native_file_out)
715 out_java.write(native_out)
717 def map_complex_enum(struct_name, union_enum_items, inline_enum_variants, enum_doc_comment):
718 java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
721 tag_field_lines = union_enum_items["field_lines"]
722 contains_trait = False
723 for idx, (struct_line, variant_docs) in enumerate(tag_field_lines):
725 assert(struct_line == "typedef enum %s_Tag {" % struct_name)
726 elif idx == len(tag_field_lines) - 3:
727 assert(struct_line.endswith("_Sentinel,"))
728 elif idx == len(tag_field_lines) - 2:
729 assert(struct_line == "} %s_Tag;" % struct_name)
730 elif idx == len(tag_field_lines) - 1:
731 assert(struct_line == "")
733 variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
735 if "LDK" + variant_name in union_enum_items:
736 enum_var_lines = union_enum_items["LDK" + variant_name]
737 for idx, (field, field_docs) in enumerate(enum_var_lines):
738 if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
739 field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
740 contains_trait |= field_ty.contains_trait
741 if field_docs is not None and doc_to_field_nullable(field_docs):
742 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
744 field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
745 fields.append((field_conv, field_docs))
746 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
747 elif camel_to_snake(variant_name) in inline_enum_variants:
748 # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
749 # docs through to there, and then potentially mark the field nullable.
750 (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)]
751 variant_ty_text = variant_info + " " + camel_to_snake(variant_name)
752 variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None)
753 if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs):
754 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True)
756 mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False)
757 contains_trait |= mapped.ty_info.contains_trait
758 fields.append((mapped, None))
759 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
761 enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
762 complex_enums[struct_name] = contains_trait
764 with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
765 (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
767 out_java_enum.write(out_java_enum_addendum)
768 out_java.write(out_java_addendum)
769 write_c(out_c_addendum)
771 def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
772 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
774 flattened_field_var_convs = []
775 for var_line in field_var_lines:
776 if var_line.group(1) in trait_structs:
777 field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
778 flattened_field_var_convs.append((var_line.group(1), var_line.group(2), var_line.group(2)))
779 for field_var in trait_structs[var_line.group(1)]:
780 if isinstance(field_var, ConvInfo):
781 flattened_field_var_convs.append(field_var)
783 path = var_line.group(2)
784 if len(field_var) > 2:
785 path = var_line.group(2) + "." + field_var[2]
786 flattened_field_var_convs.append((field_var[0], field_var[1], path))
788 mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
789 field_var_convs.append(mapped)
790 flattened_field_var_convs.append(mapped)
791 trait_structs[struct_name] = flattened_field_var_convs
794 for fn_docs, fn_line in trait_fn_lines:
795 if fn_line == "cloned":
796 ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
797 field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
799 (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
801 ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
802 ret_ty_info.nullable = True
804 ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
805 is_const = fn_line.group(4) is not None
808 for idx, arg in enumerate(fn_line.group(5).split(',')):
811 arg_ty_info = type_mapping_generator.java_c_types(arg, None)
812 if arg_ty_info.var_name in nullable_params:
813 # Types that are actually null instead of all-0s aren't yet handled on the Java side:
814 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
816 arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
817 arg_tys.append(arg_conv_info)
818 field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
820 (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)
821 write_c(out_c_addendum)
822 out_java_trait.write(out_java_trait_addendum)
823 out_java.write(out_java_addendum)
825 for fn_docs, fn_line in trait_fn_lines:
826 if fn_line == "cloned":
828 # For now, just disable enabling the _call_log - we don't know how to inverse-map String
829 is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
830 if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
831 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"
832 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)
833 for idx, var_line in enumerate(field_var_lines):
834 if var_line.group(1) not in trait_structs:
835 write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
836 write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
837 write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
838 write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
840 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"
841 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)
843 def map_result(struct_name, res_ty, err_ty):
844 result_types.add(struct_name)
845 human_ty = struct_name.replace("LDKCResult", "Result")
846 res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
847 err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
848 java_hu_struct = consts.map_result(struct_name, res_map, err_map)
849 create_getter(struct_name, res_ty, "ok", ("*", "->contents.result"), ("", "->result_ok"))
850 create_getter(struct_name, err_ty, "err", ("*", "->contents.err"), ("!", "->result_ok"))
851 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
852 out_java_struct.write(java_hu_struct)
854 def create_getter(struct_name, field_decl, field_name, accessor, check_sfx):
855 field_ty = java_c_types(field_decl + " " + field_name, None)
856 ptr_fn_defn = field_decl + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
857 owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)"
860 if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs:
861 fn_defn = owned_fn_defn
862 write_c("static inline " + fn_defn + "{\n")
863 write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n")
864 write_c("\tret.is_owned = false;\n")
865 write_c("\treturn ret;\n")
866 elif field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
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 " + field_ty.rust_obj.replace("LDK", "") + "_clone(&" + accessor[0] + "owner" + accessor[1] + ");\n")
872 elif field_ty.arr_len is not None or field_ty.is_native_primitive or field_ty.rust_obj in unitary_enums:
873 fn_defn = owned_fn_defn
874 write_c("static inline " + fn_defn + "{\n")
875 if check_sfx is not None:
876 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
877 write_c("\treturn " + accessor[0] + "owner" + accessor[1] + ";\n")
880 fn_defn = ptr_fn_defn
881 write_c("static inline " + fn_defn + "{\n")
882 if check_sfx is not None:
883 write_c("CHECK(" + check_sfx[0] + "owner" + check_sfx[1] + ");\n")
884 write_c("\treturn &" + accessor[0] + "owner" + accessor[1] + ";\n")
887 dummy_line = fn_defn + ";\n"
888 map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
890 def map_tuple(struct_name, field_lines):
891 human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
892 with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
893 out_java_struct.write(consts.map_tuple(struct_name))
895 for idx, (line, _) in enumerate(field_lines):
896 if idx != 0 and idx < len(field_lines) - 2:
897 ty_list.append(java_c_types(line.strip(';'), None))
898 tuple_types[struct_name] = (ty_list, struct_name)
900 # Map virtual getter functions
901 for idx, (line, _) in enumerate(field_lines):
902 if idx != 0 and idx < len(field_lines) - 2:
903 field_name = chr(ord('a') + idx - 1)
904 assert line.endswith(" " + field_name + ";")
905 create_getter(struct_name, line[:-3].strip(), field_name, ("", "->" + field_name), None)
907 out_java.write(consts.bindings_header)
908 with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
909 out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
911 with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
912 out_java_struct.write(consts.common_base)
915 last_block_comment = None
918 const_val_regex = re.compile("^extern const ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
920 line_indicates_result_regex = re.compile("^ union (LDKCResult_[A-Za-z_0-9]*Ptr) contents;$")
921 line_indicates_vec_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]*) \*data;$")
922 line_indicates_opaque_regex = re.compile("^ bool is_owned;$")
923 line_indicates_trait_regex = re.compile("^ (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
924 assert(line_indicates_trait_regex.match(" uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
925 assert(line_indicates_trait_regex.match(" struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
926 assert(line_indicates_trait_regex.match(" struct LDKCVec_u8Z (*write)(const void *this_arg);"))
927 line_indicates_trait_clone_regex = re.compile("^ void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
928 assert(line_indicates_trait_clone_regex.match(" void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
929 line_field_var_regex = re.compile("^ struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
930 assert(line_field_var_regex.match(" struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
931 assert(line_field_var_regex.match(" struct LDKChannelPublicKeys pubkeys;"))
932 struct_name_regex = re.compile("^typedef (struct|enum|union) (MUST_USE_STRUCT )?(LDK[A-Za-z_0-9]*) {$")
933 assert(struct_name_regex.match("typedef struct LDKCVec_u8Z {"))
934 assert(struct_name_regex.match("typedef enum LDKNetwork {"))
936 union_enum_items = {}
937 result_ptr_struct_items = {}
939 if block_comment is not None:
940 if line.endswith("*/\n"):
941 last_block_comment = block_comment.strip("\n")
944 block_comment = block_comment + line.strip(" /*")
945 elif cur_block_obj is not None:
946 cur_block_obj = cur_block_obj + line
947 if line.startswith("} "):
951 obj_lines = cur_block_obj.split("\n")
953 result_contents = None
954 is_unitary_enum = False
955 is_union_enum = False
960 last_struct_block_comment = None
962 for idx, struct_line in enumerate(obj_lines):
963 if struct_line.strip().startswith("/*"):
964 block_comment = struct_line.strip(" /*")
965 if block_comment is not None:
966 if struct_line.endswith("*/"):
967 last_struct_block_comment = block_comment.strip("\n")
970 block_comment = block_comment + "\n" + struct_line.strip(" /*").replace("…", "...")
972 struct_name_match = struct_name_regex.match(struct_line)
973 if struct_name_match is not None:
974 struct_name = struct_name_match.group(3)
975 if struct_name_match.group(1) == "enum":
976 if not struct_name.endswith("_Tag"):
977 is_unitary_enum = True
980 elif struct_name_match.group(1) == "union":
982 if line_indicates_opaque_regex.match(struct_line):
984 result_match = line_indicates_result_regex.match(struct_line)
985 if result_match is not None:
986 result_contents = result_match.group(1)
987 vec_ty_match = line_indicates_vec_regex.match(struct_line)
988 if vec_ty_match is not None and struct_name.startswith("LDKCVec_"):
989 vec_ty = vec_ty_match.group(2)
990 elif struct_name.startswith("LDKC2Tuple_") or struct_name.startswith("LDKC3Tuple_"):
992 trait_fn_match = line_indicates_trait_regex.match(struct_line)
993 if trait_fn_match is not None:
994 trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
995 trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
996 if trait_clone_fn_match is not None:
997 trait_fn_lines.append((last_struct_block_comment, "cloned"))
998 field_var_match = line_field_var_regex.match(struct_line)
999 if field_var_match is not None:
1000 field_var_lines.append(field_var_match)
1001 field_lines.append((struct_line, last_struct_block_comment))
1002 last_struct_block_comment = None
1004 assert(struct_name is not None)
1005 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))
1006 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))
1007 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))
1008 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))
1009 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))
1010 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))
1011 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))
1014 opaque_structs.add(struct_name)
1015 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_struct:
1016 out_opaque_struct_human = consts.map_opaque_struct(struct_name, last_block_comment)
1017 last_block_comment = None
1018 out_java_struct.write(out_opaque_struct_human)
1019 elif result_contents is not None:
1020 assert result_contents in result_ptr_struct_items
1021 res_ty, err_ty = result_ptr_struct_items[result_contents]
1022 map_result(struct_name, res_ty, err_ty)
1023 elif struct_name.startswith("LDKCResult_") and struct_name.endswith("ZPtr"):
1024 for line, _ in field_lines:
1025 if line.endswith("*result;"):
1026 res_ty = line[:-8].strip()
1027 elif line.endswith("*err;"):
1028 err_ty = line[:-5].strip()
1029 result_ptr_struct_items[struct_name] = (res_ty, err_ty)
1030 result_types.add(struct_name[:-3])
1032 map_tuple(struct_name, field_lines)
1033 elif vec_ty is not None:
1034 ty_info = type_mapping_generator.map_type(vec_ty + " arr_elem", False, None, False, False)
1035 if ty_info.is_native_primitive:
1036 clone_fns.add(struct_name.replace("LDK", "") + "_clone")
1037 write_c("static inline " + struct_name + " " + struct_name.replace("LDK", "") + "_clone(const " + struct_name + " *orig) {\n")
1038 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.c_ty + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1039 write_c("\tmemcpy(ret.data, orig->data, sizeof(" + ty_info.c_ty + ") * ret.datalen);\n")
1040 write_c("\treturn ret;\n}\n")
1041 elif (ty_info.rust_obj.replace("LDK", "") + "_clone") in clone_fns:
1042 ty_name = struct_name.replace("LDK", "")
1043 clone_fns.add(ty_name + "_clone")
1044 write_c("static inline " + struct_name + " " + ty_name + "_clone(const " + struct_name + " *orig) {\n")
1045 write_c("\t" + struct_name + " ret = { .data = MALLOC(sizeof(" + ty_info.rust_obj + ") * orig->datalen, \"" + struct_name + " clone bytes\"), .datalen = orig->datalen };\n")
1046 write_c("\tfor (size_t i = 0; i < ret.datalen; i++) {\n")
1047 write_c("\t\tret.data[i] = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&orig->data[i]);\n")
1048 write_c("\t}\n\treturn ret;\n}\n")
1050 assert(struct_name.endswith("_Tag"))
1051 struct_name = struct_name[:-4]
1052 union_enum_items[struct_name] = {"field_lines": field_lines}
1053 elif struct_name.endswith("_Body") and struct_name.split("_")[0] in union_enum_items:
1054 enum_var_name = struct_name.split("_")
1055 union_enum_items[enum_var_name[0]][enum_var_name[1]] = field_lines
1056 elif struct_name in union_enum_items:
1059 for line, field_block_comment in field_lines:
1060 if line == " struct {":
1064 elif elem_items > -1:
1066 if line.startswith("struct "):
1068 elif line.startswith("enum "):
1070 split = line.split(" ")
1071 assert len(split) == 2
1072 tuple_variants[split[1].strip(";")] = (split[0], field_block_comment)
1075 # We don't currently support tuple variant with more than one element
1077 map_complex_enum(struct_name, union_enum_items[struct_name], tuple_variants, last_block_comment)
1078 last_block_comment = None
1079 elif is_unitary_enum:
1080 map_unitary_enum(struct_name, field_lines, last_block_comment)
1081 last_block_comment = None
1082 elif len(trait_fn_lines) > 0:
1083 map_trait(struct_name, field_var_lines, trait_fn_lines, last_block_comment)
1084 elif struct_name == "LDKTxOut":
1085 with open(f"{sys.argv[3]}/structs/TxOut{consts.file_ext}", "w") as out_java_struct:
1086 out_java_struct.write(consts.hu_struct_file_prefix)
1087 out_java_struct.write(consts.txout_defn)
1088 out_java_struct.write(consts.hu_struct_file_suffix)
1089 fn_line = "struct LDKCVec_u8Z TxOut_get_script_pubkey (struct LDKTxOut* thing)"
1090 write_c(fn_line + " {")
1091 write_c("\treturn CVec_u8Z_clone(&thing->script_pubkey);")
1093 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_script_pubkey) \((.*)\)").match(fn_line), None, None, None)
1094 fn_line = "uint64_t TxOut_get_value (struct LDKTxOut* thing)"
1095 write_c(fn_line + " {")
1096 write_c("\treturn thing->value;")
1098 map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None)
1099 elif struct_name == "LDKBigEndianScalar":
1100 with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct:
1101 out_java_struct.write(consts.hu_struct_file_prefix)
1102 out_java_struct.write(consts.scalar_defn)
1103 out_java_struct.write(consts.hu_struct_file_suffix)
1104 fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)"
1105 write_c(fn_line + " {\n")
1106 write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n")
1107 write_c("\treturn ret;\n")
1109 map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None)
1111 # We need to be able to FREE a heap-allocated BigEndianScalar, but because
1112 # there's nothing heap-allocated inside it the C bindings don't bother
1113 # exposing a `_free` method. Instead, we have to manually write one here,
1114 # though it doesn't need to do anything, the autogenerated wrapper will do
1115 # the required FREE.
1116 fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)"
1117 write_c(fn_line + " {}\n")
1118 map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None)
1120 pass # Everything remaining is a byte[] of some form
1121 cur_block_obj = None
1123 fn_ptr = fn_ptr_regex.match(line)
1124 fn_ret_arr = fn_ret_arr_regex.match(line)
1125 reg_fn = reg_fn_regex.match(line)
1126 const_val = const_val_regex.match(line)
1128 if line.startswith("#include <"):
1130 elif line.startswith("/*"):
1131 if not line.endswith("*/\n"):
1132 block_comment = line.strip(" /*")
1133 elif line.startswith("typedef enum "):
1134 cur_block_obj = line
1135 elif line.startswith("typedef struct "):
1136 cur_block_obj = line
1137 elif line.startswith("typedef union "):
1138 cur_block_obj = line
1139 elif fn_ptr is not None:
1140 map_fn(line, fn_ptr, None, None, last_block_comment)
1141 last_block_comment = None
1142 elif fn_ret_arr is not None:
1143 map_fn(line, fn_ret_arr, fn_ret_arr.group(4), None, last_block_comment)
1144 last_block_comment = None
1145 elif reg_fn is not None:
1146 map_fn(line, reg_fn, None, None, last_block_comment)
1147 last_block_comment = None
1148 elif const_val_regex is not None:
1149 # TODO Map const variables
1152 assert(line == "\n")
1154 out_java.write(consts.bindings_footer())
1155 for struct_name in opaque_structs:
1156 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1157 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1158 for struct_name in trait_structs:
1159 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "a") as out_java_struct:
1160 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1161 for struct_name in complex_enums:
1162 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '').replace('COption', 'Option')}{consts.file_ext}", "a") as out_java_struct:
1163 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1164 for struct_name in result_types:
1165 with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDKCResult', 'Result')}{consts.file_ext}", "a") as out_java_struct:
1166 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1167 for struct_name in tuple_types:
1168 struct_hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
1169 with open(f"{sys.argv[3]}/structs/{struct_hu_name}{consts.file_ext}", "a") as out_java_struct:
1170 out_java_struct.write("}\n" + consts.hu_struct_file_suffix)
1172 with open(f"{sys.argv[4]}/bindings.c.body", "w") as out_c:
1173 out_c.write(consts.c_file_pfx)
1174 out_c.write(consts.init_str())
1176 with open(f"{sys.argv[4]}/version.c", "w") as out_c:
1177 out_c.write(consts.c_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
1178 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util:
1179 util.write(consts.util_fn_sfx)