- return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
- arg_conv = None, arg_conv_name = None, ret_conv = None, ret_conv_name = None)
-
- def map_fn(re_match, ret_arr_len):
- out_java.write("\t/// " + line)
- out_java.write("\tpublic static native ")
- out_c.write("JNIEXPORT ")
-
- ret_info = map_type(re_match.group(1), True, ret_arr_len, False)
- ret_info.print_ty()
- if ret_info.ret_conv is not None:
- ret_conv_pfx, ret_conv_sfx = ret_info.ret_conv
-
- out_java.write(" " + re_match.group(2) + "(")
- out_c.write(" JNICALL Java_org_ldk_impl_bindings_" + re_match.group(2).replace('_', '_1') + "(JNIEnv * _env, jclass _b")
-
- arg_names = []
- for idx, arg in enumerate(re_match.group(3).split(',')):
- if idx != 0:
- out_java.write(", ")
- if arg != "void":
- out_c.write(", ")
- arg_conv_info = map_type(arg, False, None, re_match.group(2).endswith("_free"))
- if arg_conv_info.c_ty != "void":
- arg_conv_info.print_ty()
- arg_conv_info.print_name()
- arg_names.append(arg_conv_info)
-
- out_java.write(");\n")
- out_c.write(") {\n")
-
- for info in arg_names:
- if info.arg_conv is not None:
- out_c.write("\t" + info.arg_conv.replace('\n', "\n\t") + "\n");
-
- if ret_info.ret_conv is not None:
- out_c.write("\t" + ret_conv_pfx.replace('\n', '\n\t'));
- else:
- out_c.write("\treturn ");
-
- out_c.write(re_match.group(2) + "(")
- for idx, info in enumerate(arg_names):
- if info.arg_conv_name is not None:
- if idx != 0:
- out_c.write(", ")
- out_c.write(info.arg_conv_name)
- out_c.write(")")
- if ret_info.ret_conv is not None:
- out_c.write(ret_conv_sfx.replace('\n', '\n\t'))
- out_c.write("\n\treturn " + ret_info.ret_conv_name + ";")
- else:
- out_c.write(";")
- out_c.write("\n}\n\n")
-
- out_java.write("""package org.ldk.impl;
-
-public class bindings {
- static {
- System.loadLibrary(\"lightningjni\");
- }
-
-""")
- out_c.write("#include \"org_ldk_impl_bindings.h\"\n")
- out_c.write("#include <rust_types.h>\n")
- out_c.write("#include <lightning.h>\n")
- out_c.write("#include <assert.h>\n")
- out_c.write("#include <string.h>\n")
- out_c.write("#include <stdatomic.h>\n\n")
- if sys.argv[4] == "false":
- out_c.write("#define MALLOC(a, _) malloc(a)\n")
- out_c.write("#define FREE free\n\n")
- else:
- out_c.write("#include <threads.h>\n")
- out_c.write("static mtx_t allocation_mtx;\n\n")
- out_c.write("void __attribute__((constructor)) init_mtx() {\n")
- out_c.write("\tassert(mtx_init(&allocation_mtx, mtx_plain) == thrd_success);\n")
- out_c.write("}\n\n")
- out_c.write("typedef struct allocation {\n")
- out_c.write("\tstruct allocation* next;\n")
- out_c.write("\tvoid* ptr;\n")
- out_c.write("\tconst char* struct_name;\n")
- out_c.write("} allocation;\n")
- out_c.write("static allocation* allocation_ll = NULL;\n\n")
- out_c.write("void* MALLOC(size_t len, const char* struct_name) {\n")
- out_c.write("\tvoid* res = malloc(len);\n")
- out_c.write("\tallocation* new_alloc = malloc(sizeof(allocation));\n")
- out_c.write("\tnew_alloc->ptr = res;\n")
- out_c.write("\tnew_alloc->struct_name = struct_name;\n")
- out_c.write("\tassert(mtx_lock(&allocation_mtx) == thrd_success);\n")
- out_c.write("\tnew_alloc->next = allocation_ll;\n")
- out_c.write("\tallocation_ll = new_alloc;\n")
- out_c.write("\tassert(mtx_unlock(&allocation_mtx) == thrd_success);\n")
- out_c.write("\treturn res;\n")
- out_c.write("}\n\n")
- out_c.write("void FREE(void* ptr) {\n")
- out_c.write("\tallocation* p = NULL;\n")
- out_c.write("\tassert(mtx_lock(&allocation_mtx) == thrd_success);\n")
- out_c.write("\tallocation* it = allocation_ll;\n")
- out_c.write("\twhile (it->ptr != ptr) { p = it; it = it->next; }\n")
- out_c.write("\tif (p) { p->next = it->next; } else { allocation_ll = it->next; }\n")
- out_c.write("\tassert(mtx_unlock(&allocation_mtx) == thrd_success);\n")
- out_c.write("\tassert(it->ptr == ptr);\n")
- out_c.write("\tfree(it);\n")
- out_c.write("\tfree(ptr);\n")
- out_c.write("}\n\n")
- out_c.write("void __attribute__((destructor)) check_leaks() {\n")
- out_c.write("\tfor (allocation* a = allocation_ll; a != NULL; a = a->next) { fprintf(stderr, \"%s %p remains\\n\", a->struct_name, a->ptr); }\n")
- out_c.write("\tassert(allocation_ll == NULL);\n")
- out_c.write("}\n\n")
-
- # XXX: Temporarily write out a manual SecretKey_new() for testing, we should auto-gen this kind of thing
- out_java.write("\tpublic static native long LDKSecretKey_new();\n\n") # TODO: rm me
- out_c.write("JNIEXPORT jlong JNICALL Java_org_ldk_impl_bindings_LDKSecretKey_1new(JNIEnv * _env, jclass _b) {\n") # TODO: rm me
- out_c.write("\tLDKSecretKey* key = (LDKSecretKey*)MALLOC(sizeof(LDKSecretKey), \"LDKSecretKey\");\n") # TODO: rm me
- out_c.write("\treturn (long)key;\n") # TODO: rm me
- out_c.write("}\n") # TODO: rm me
-
- in_block_comment = False
- in_block_enum = False
- cur_block_struct = None
- in_block_union = False
-
- fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
- fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")
- reg_fn_regex = re.compile("([A-Za-z_0-9\* ]* \*?)([a-zA-Z_0-9]*)\((.*)\);$")
+ variant_name = struct_line.strip(' ,')[len(struct_name) + 1:]
+ fields = []
+ if "LDK" + variant_name in union_enum_items:
+ enum_var_lines = union_enum_items["LDK" + variant_name]
+ for idx, (field, field_docs) in enumerate(enum_var_lines):
+ if idx != 0 and idx < len(enum_var_lines) - 2 and field.strip() != "":
+ field_ty = type_mapping_generator.java_c_types(field.strip(' ;'), None)
+ contains_trait |= field_ty.contains_trait
+ if field_docs is not None and doc_to_field_nullable(field_docs):
+ field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, True)
+ else:
+ field_conv = type_mapping_generator.map_type_with_info(field_ty, False, None, False, True, False)
+ fields.append((field_conv, field_docs))
+ enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, False))
+ elif camel_to_snake(variant_name) in inline_enum_variants:
+ # TODO: If we ever have a rust enum Variant(Option<Struct>) we need to pipe
+ # docs through to there, and then potentially mark the field nullable.
+ mapped = type_mapping_generator.map_type(inline_enum_variants[camel_to_snake(variant_name)] + " " + camel_to_snake(variant_name), False, None, False, True)
+ contains_trait |= mapped.ty_info.contains_trait
+ fields.append((mapped, None))
+ enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
+ else:
+ enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True))
+ complex_enums[struct_name] = contains_trait
+
+ with open(f"{sys.argv[3]}/structs/{java_hu_type}{consts.file_ext}", "w") as out_java_enum:
+ (out_java_addendum, out_java_enum_addendum, out_c_addendum) = consts.map_complex_enum(struct_name, enum_variants, camel_to_snake, enum_doc_comment)
+
+ out_java_enum.write(out_java_enum_addendum)
+ out_java.write(out_java_addendum)
+ write_c(out_c_addendum)
+
+ def map_trait(struct_name, field_var_lines, trait_fn_lines, trait_doc_comment):
+ with open(f"{sys.argv[3]}/structs/{struct_name.replace('LDK', '')}{consts.file_ext}", "w") as out_java_trait:
+ field_var_convs = []
+ flattened_field_var_convs = []
+ for var_line in field_var_lines:
+ if var_line.group(1) in trait_structs:
+ field_var_convs.append((var_line.group(1), var_line.group(2), trait_structs[var_line.group(1)]))
+ flattened_field_var_convs.append((var_line.group(1), var_line.group(2), ))
+ flattened_field_var_convs.extend(trait_structs[var_line.group(1)])
+ else:
+ mapped = type_mapping_generator.map_type(var_line.group(1) + " " + var_line.group(2), False, None, False, False)
+ field_var_convs.append(mapped)
+ flattened_field_var_convs.append(mapped)
+ trait_structs[struct_name] = field_var_convs
+
+ field_fns = []
+ for fn_docs, fn_line in trait_fn_lines:
+ if fn_line == "cloned":
+ ret_ty_info = type_mapping_generator.map_type("void", True, None, False, False)
+ field_fns.append(TraitMethInfo("cloned", False, ret_ty_info, [], fn_docs))
+ else:
+ (nullable_params, ret_nullable) = doc_to_params_ret_nullable(fn_docs)
+ if ret_nullable:
+ assert False # This isn't yet handled on the Java side
+ ret_ty_info.nullable = True
+ ret_ty_info = type_mapping_generator.map_nullable_type(fn_line.group(2).strip() + " ret", True, None, False, False)
+ else:
+ ret_ty_info = type_mapping_generator.map_type(fn_line.group(2).strip() + " ret", True, None, False, False)
+ is_const = fn_line.group(4) is not None
+
+ arg_tys = []
+ for idx, arg in enumerate(fn_line.group(5).split(',')):
+ if arg == "":
+ continue
+ arg_ty_info = type_mapping_generator.java_c_types(arg, None)
+ if arg_ty_info.var_name in nullable_params:
+ # Types that are actually null instead of all-0s aren't yet handled on the Java side:
+ arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, True)
+ else:
+ arg_conv_info = type_mapping_generator.map_type_with_info(arg_ty_info, True, None, False, False, False)
+ arg_tys.append(arg_conv_info)
+ field_fns.append(TraitMethInfo(fn_line.group(3), is_const, ret_ty_info, arg_tys, fn_docs))
+
+ (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)
+ write_c(out_c_addendum)
+ out_java_trait.write(out_java_trait_addendum)
+ out_java.write(out_java_addendum)
+
+ for fn_docs, fn_line in trait_fn_lines:
+ if fn_line == "cloned":
+ continue
+ # For now, just disable enabling the _call_log - we don't know how to inverse-map String
+ is_log = fn_line.group(3) == "log" and struct_name == "LDKLogger"
+ if fn_line.group(3) != "free" and fn_line.group(3) != "eq" and not is_log:
+ 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"
+ 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)
+ for idx, var_line in enumerate(field_var_lines):
+ if var_line.group(1) not in trait_structs:
+ write_c(var_line.group(1) + " " + struct_name + "_set_get_" + var_line.group(2) + "(" + struct_name + "* this_arg) {\n")
+ write_c("\tif (this_arg->set_" + var_line.group(2) + " != NULL)\n")
+ write_c("\t\tthis_arg->set_" + var_line.group(2) + "(this_arg);\n")
+ write_c("\treturn this_arg->" + var_line.group(2) + ";\n")
+ write_c("}\n")
+ 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"
+ 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)
+
+ def map_result(struct_name, res_ty, err_ty):
+ result_types.add(struct_name)
+ human_ty = struct_name.replace("LDKCResult", "Result")
+ with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
+ out_java_struct.write(consts.hu_struct_file_prefix)
+ out_java_struct.write("public class " + human_ty + " extends CommonBase {\n")
+ out_java_struct.write("\tprivate " + human_ty + "(Object _dummy, long ptr) { super(ptr); }\n")
+ out_java_struct.write("\tprotected void finalize() throws Throwable {\n")
+ out_java_struct.write("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); } super.finalize();\n")
+ out_java_struct.write("\t}\n\n")
+ out_java_struct.write("\tstatic " + human_ty + " constr_from_ptr(long ptr) {\n")
+ out_java_struct.write("\t\tif (bindings." + struct_name.replace("LDK", "") + "_is_ok(ptr)) {\n")
+ out_java_struct.write("\t\t\treturn new " + human_ty + "_OK(null, ptr);\n")
+ out_java_struct.write("\t\t} else {\n")
+ out_java_struct.write("\t\t\treturn new " + human_ty + "_Err(null, ptr);\n")
+ out_java_struct.write("\t\t}\n")
+ out_java_struct.write("\t}\n")
+
+ res_map = type_mapping_generator.map_type(res_ty + " res", True, None, False, True)
+ err_map = type_mapping_generator.map_type(err_ty + " err", True, None, False, True)
+ can_clone = True
+ if not res_map.is_native_primitive and (res_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
+ can_clone = False
+ if not err_map.is_native_primitive and (err_map.rust_obj.replace("LDK", "") + "_clone" not in clone_fns):
+ can_clone = False
+
+ out_java.write("\tpublic static native " + res_map.java_ty + " " + struct_name + "_get_ok(long arg);\n")
+ write_c(consts.c_fn_ty_pfx + res_map.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_ok", True) + consts.ptr_c_ty + " arg) {\n")
+ write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
+ write_c("\tCHECK(val->result_ok);\n\t")
+ out_java_struct.write("\tpublic static final class " + human_ty + "_OK extends " + human_ty + " {\n")
+ if res_map.ret_conv is not None:
+ write_c(res_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.result)")
+ write_c(res_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + res_map.ret_conv_name)
+ else:
+ write_c("return *val->contents.result")
+ write_c(";\n}\n")
+
+ if res_map.java_hu_ty != "void":
+ out_java_struct.write("\t\tpublic final " + res_map.java_hu_ty + " res;\n")
+ out_java_struct.write("\t\tprivate " + human_ty + "_OK(Object _dummy, long ptr) {\n")
+ out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
+ if res_map.java_hu_ty == "void":
+ pass
+ elif res_map.to_hu_conv is not None:
+ out_java_struct.write("\t\t\t" + res_map.java_ty + " res = bindings." + struct_name + "_get_ok(ptr);\n")
+ out_java_struct.write("\t\t\t" + res_map.to_hu_conv.replace("\n", "\n\t\t\t"))
+ out_java_struct.write("\n\t\t\tthis.res = " + res_map.to_hu_conv_name + ";\n")
+ else:
+ out_java_struct.write("\t\t\tthis.res = bindings." + struct_name + "_get_ok(ptr);\n")
+ out_java_struct.write("\t\t}\n")
+ out_java_struct.write("\t}\n\n")
+
+ out_java.write("\tpublic static native " + err_map.java_ty + " " + struct_name + "_get_err(long arg);\n")
+ write_c(consts.c_fn_ty_pfx + err_map.c_ty + " " + consts.c_fn_name_define_pfx(struct_name + "_get_err", True) + consts.ptr_c_ty + " arg) {\n")
+ write_c("\t" + struct_name + " *val = (" + struct_name + "*)(arg & ~1);\n")
+ write_c("\tCHECK(!val->result_ok);\n\t")
+ out_java_struct.write("\tpublic static final class " + human_ty + "_Err extends " + human_ty + " {\n")
+ if err_map.ret_conv is not None:
+ write_c(err_map.ret_conv[0].replace("\n", "\n\t") + "(*val->contents.err)")
+ write_c(err_map.ret_conv[1].replace("\n", "\n\t") + "\n\treturn " + err_map.ret_conv_name)
+ else:
+ write_c("return *val->contents.err")
+ write_c(";\n}\n")
+
+ if err_map.java_hu_ty != "void":
+ out_java_struct.write("\t\tpublic final " + err_map.java_hu_ty + " err;\n")
+ out_java_struct.write("\t\tprivate " + human_ty + "_Err(Object _dummy, long ptr) {\n")
+ out_java_struct.write("\t\t\tsuper(_dummy, ptr);\n")
+ if err_map.java_hu_ty == "void":
+ pass
+ elif err_map.to_hu_conv is not None:
+ out_java_struct.write("\t\t\t" + err_map.java_ty + " err = bindings." + struct_name + "_get_err(ptr);\n")
+ out_java_struct.write("\t\t\t" + err_map.to_hu_conv.replace("\n", "\n\t\t\t"))
+ out_java_struct.write("\n\t\t\tthis.err = " + err_map.to_hu_conv_name + ";\n")
+ else:
+ out_java_struct.write("\t\t\tthis.err = bindings." + struct_name + "_get_err(ptr);\n")
+ out_java_struct.write("\t\t}\n")
+
+ out_java_struct.write("\t}\n\n")
+
+ def map_tuple(struct_name, field_lines):
+ human_ty = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple")
+ with open(f"{sys.argv[3]}/structs/{human_ty}{consts.file_ext}", "w") as out_java_struct:
+ out_java_struct.write(consts.map_tuple(struct_name))
+ ty_list = []
+ for idx, (line, _) in enumerate(field_lines):
+ if idx != 0 and idx < len(field_lines) - 2:
+ ty_list.append(java_c_types(line.strip(';'), None))
+ tuple_types[struct_name] = (ty_list, struct_name)
+
+ # Map virtual getter functions
+ for idx, (line, _) in enumerate(field_lines):
+ if idx != 0 and idx < len(field_lines) - 2:
+ field_name = chr(ord('a') + idx - 1)
+ assert line.endswith(" " + field_name + ";")
+ field_ty = java_c_types(line[:-1], None)
+ ptr_fn_defn = line[:-3].strip() + " *" + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR tuple)"
+ owned_fn_defn = line[:-3].strip() + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR tuple)"
+
+ holds_ref = False
+ if field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns:
+ fn_defn = owned_fn_defn
+ write_c("static inline " + fn_defn + "{\n")
+ write_c("\treturn " + field_ty.rust_obj.replace("LDK", "") + "_clone(&tuple->" + field_name + ");\n")
+ elif field_ty.arr_len is not None or field_ty.is_native_primitive:
+ fn_defn = owned_fn_defn
+ write_c("static inline " + fn_defn + "{\n")
+ write_c("\treturn tuple->" + field_name + ";\n")
+ else:
+ fn_defn = ptr_fn_defn
+ write_c("static inline " + fn_defn + "{\n")
+ write_c("\treturn &tuple->" + field_name + ";\n")
+ holds_ref = True
+ write_c("}\n")
+ dummy_line = fn_defn + ";\n"
+ map_fn_with_ref_option(dummy_line, reg_fn_regex.match(dummy_line), None, None, "", holds_ref)
+
+ out_java.write(consts.bindings_header)
+ with open(f"{sys.argv[2]}/version{consts.file_ext}", "w") as out_java_version:
+ out_java_version.write(consts.bindings_version_file.replace('<git_version_ldk_garbagecollected>', local_git_version))
+
+ with open(f"{sys.argv[3]}/structs/CommonBase{consts.file_ext}", "w") as out_java_struct:
+ out_java_struct.write(consts.common_base)
+
+ block_comment = None
+ last_block_comment = None
+ cur_block_obj = None
+