X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=genbindings.py;h=1ade1705010d1f9055fe236b0be157cb9c091146;hb=2eb87ba813b7b6c1669a8a0d900a2baa67bfea3e;hp=a3ea7d40c57052da323b53301ba1aac1c11fe8c5;hpb=54be51eba6c3395c3c8c815df6d344db0dc965aa;p=ldk-java diff --git a/genbindings.py b/genbindings.py index a3ea7d40..1ade1705 100755 --- a/genbindings.py +++ b/genbindings.py @@ -263,14 +263,19 @@ def java_c_types(fn_arg, ret_arr_len): arr_ty = "uint8_t" fn_arg = fn_arg[7:].strip() is_primitive = True - elif fn_arg.startswith("LDKu5"): + elif fn_arg.startswith("LDKu5") or fn_arg.startswith("LDKWitnessVersion"): java_ty = consts.c_type_map['uint8_t'][0] - java_hu_ty = "UInt5" - rust_obj = "LDKu5" + if fn_arg.startswith("LDKu5"): + java_hu_ty = "UInt5" + rust_obj = "LDKu5" + fn_arg = fn_arg[6:].strip() + else: + java_hu_ty = "WitnessVersion" + rust_obj = "LDKWitnessVersion" + fn_arg = fn_arg[18:].strip() c_ty = "int8_t" arr_ty = "uint8_t" fn_ty_arg = "B" - fn_arg = fn_arg[6:].strip() elif fn_arg.startswith("uint16_t"): mapped_type = consts.c_type_map['uint16_t'] java_ty = mapped_type[0] @@ -297,8 +302,8 @@ def java_c_types(fn_arg, ret_arr_len): arr_ty = "uint64_t" fn_arg = fn_arg[8:].strip() else: - java_ty = consts.ptr_native_ty - c_ty = consts.ptr_c_ty + java_ty = consts.usize_native_ty + c_ty = consts.usize_c_ty arr_ty = "uintptr_t" rust_obj = "uintptr_t" fn_arg = fn_arg[9:].strip() @@ -320,6 +325,14 @@ def java_c_types(fn_arg, ret_arr_len): fn_arg = fn_arg[6:].strip() arr_access = "chars" arr_len = "len" + elif fn_arg.startswith("LDKError ") or fn_arg == "LDKError": + java_ty = consts.c_type_map['uint32_t'][0] + java_hu_ty = "UnqualifiedError" + rust_obj = "LDKError" + c_ty = "int32_t" + arr_ty = "uint32_t" + fn_ty_arg = "I" + fn_arg = fn_arg[8:].strip() else: ma = var_ty_regex.match(fn_arg) arr_ty = ma.group(1).strip() @@ -421,7 +434,66 @@ with open(sys.argv[1]) as in_h: # Define some manual clones... clone_fns.add("ThirtyTwoBytes_clone") -write_c("static inline struct LDKThirtyTwoBytes ThirtyTwoBytes_clone(const struct LDKThirtyTwoBytes *orig) { struct LDKThirtyTwoBytes ret; memcpy(ret.data, orig->data, 32); return ret; }\n") +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") + + +write_c("static inline void* untag_ptr(uint64_t ptr) {\n") +write_c("\tif (ptr < 4096) return (void*)ptr;\n") +write_c("\tif (sizeof(void*) == 4) {\n") +write_c("\t\t// For 32-bit systems, store pointers as 64-bit ints and use the 31st bit\n") +write_c("\t\treturn (void*)(uintptr_t)ptr;\n") +write_c("\t} else {\n") +write_c("\t\t// For 64-bit systems, assume the top byte is used for tagging, then\n") +write_c("\t\t// use bit 9 ^ bit 10.\n") +write_c("\t\tuint64_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n") +write_c("\t\tuintptr_t p = (ptr & ~(1ULL << 55)) | (tenth_bit << 55);\n") +write_c("#ifdef LDK_DEBUG_BUILD\n") +write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n") +write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n") +write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n") +write_c("\t\tp ^= 1ULL << 53;\n") +write_c("#endif\n") +write_c("\t\treturn (void*)p;\n") +write_c("\t}\n") +write_c("}\n") + +write_c("static inline bool ptr_is_owned(uint64_t ptr) {\n") +write_c("\tif(ptr < 4096) return true;\n") +write_c("\tif (sizeof(void*) == 4) {\n") +write_c("\t\treturn ptr & (1ULL << 32);\n") +write_c("\t} else {\n") +write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n") +write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n") +write_c("#ifdef LDK_DEBUG_BUILD\n") +write_c("\t\t// On debug builds we also use the 11th bit as a debug flag\n") +write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n") +write_c("\t\tCHECK(tenth_bit != eleventh_bit);\n") +write_c("#endif\n") +write_c("\t\treturn (ninth_bit ^ tenth_bit) ? true : false;\n") +write_c("\t}\n") +write_c("}\n") + +write_c("static inline uint64_t tag_ptr(const void* ptr, bool is_owned) {\n") +write_c("\tif ((uintptr_t)ptr < 4096) return (uint64_t)ptr;\n") +write_c("\tif (sizeof(void*) == 4) {\n") +write_c("\t\treturn (((uint64_t)ptr) | ((is_owned ? 1ULL : 0) << 32));\n") +write_c("\t} else {\n") +write_c("\t\tCHECK(sizeof(uintptr_t) == 8);\n") +write_c("\t\tuintptr_t tenth_bit = (((uintptr_t)ptr) & (1ULL << 54)) >> 54;\n") +write_c("\t\tuintptr_t t = (((uintptr_t)ptr) | (((is_owned ? 1ULL : 0ULL) ^ tenth_bit) << 55));\n") +write_c("#ifdef LDK_DEBUG_BUILD\n") +write_c("\t\tuintptr_t ninth_bit = (((uintptr_t)ptr) & (1ULL << 55)) >> 55;\n") +write_c("\t\tuintptr_t eleventh_bit = (((uintptr_t)ptr) & (1ULL << 53)) >> 53;\n") +write_c("\t\tCHECK(ninth_bit == tenth_bit);\n") +write_c("\t\tCHECK(ninth_bit == eleventh_bit);\n") +write_c("\t\tt ^= 1ULL << 53;\n") +write_c("#endif\n") +write_c("\t\tCHECK(ptr_is_owned(t) == is_owned);\n") +write_c("\t\tCHECK(untag_ptr(t) == ptr);\n") +#write_c("\t\tCHECK(untag_ptr((uintptr_t)untag_ptr(t)) == ptr);\n") +write_c("\t\treturn t;\n") +write_c("\t}\n") +write_c("}\n\n") java_c_types_none_allowed = False # C structs created by cbindgen are declared in dependency order @@ -467,13 +539,13 @@ with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", return_type_info = type_mapping_generator.map_type(method_return_type.strip() + " ret", True, ret_arr_len, False, force_holds_ref) if method_name.endswith("_clone") and expected_struct not in unitary_enums: - meth_line = "uintptr_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)" + meth_line = "uint64_t " + expected_struct.replace("LDK", "") + "_clone_ptr(" + expected_struct + " *NONNULL_PTR arg)" write_c("static inline " + meth_line + " {\n") write_c("\t" + return_type_info.ret_conv[0].replace("\n", "\n\t")) write_c(method_name + "(arg)") - write_c(return_type_info.ret_conv[1]) + write_c(return_type_info.ret_conv[1].replace("\n", "\n\t")) write_c("\n\treturn " + return_type_info.ret_conv_name + ";\n}\n") - map_fn(meth_line + ";\n", re.compile("(uintptr_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None) + map_fn(meth_line + ";\n", re.compile("(uint64_t) ([A-Za-z_0-9]*)\((.*)\)").match(meth_line), None, None, None) argument_types = [] default_constructor_args = {} @@ -535,7 +607,7 @@ with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", expected_struct in complex_enums or expected_struct in complex_enums or expected_struct in result_types or expected_struct in tuple_types) and not is_free impl_on_utils = not impl_on_struct and (not is_free and not method_name.endswith("_clone") and - not method_name.startswith("TxOut") and + not method_name.startswith("TxOut") and not method_name.startswith("BigEndianScalar") and not method_name.startswith("_") and method_name != "check_platform" and method_name != "Result_read" and not expected_struct in unitary_enums and @@ -562,7 +634,7 @@ with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", assert return_type_info.c_ty == "void" 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") if argument_types[0].ty_info.passed_as_ptr and not argument_types[0].ty_info.rust_obj in opaque_structs: - write_c("\tif ((" + argument_types[0].ty_info.var_name + " & 1) != 0) return;\n") + write_c("\tif (!ptr_is_owned(" + argument_types[0].ty_info.var_name + ")) return;\n") for info in argument_types: if info.arg_conv is not None: @@ -640,7 +712,13 @@ with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", elif camel_to_snake(variant_name) in inline_enum_variants: # TODO: If we ever have a rust enum Variant(Option) 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) + (variant_info, variant_field_docs) = inline_enum_variants[camel_to_snake(variant_name)] + variant_ty_text = variant_info + " " + camel_to_snake(variant_name) + variant_ty_info = type_mapping_generator.java_c_types(variant_ty_text, None) + if variant_field_docs is not None and doc_to_field_nullable(variant_field_docs): + mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, True) + else: + mapped = type_mapping_generator.map_type_with_info(variant_ty_info, False, None, False, True, False) contains_trait |= mapped.ty_info.contains_trait fields.append((mapped, None)) enum_variants.append(ComplexEnumVariantInfo(variant_name, variant_docs, fields, True)) @@ -738,7 +816,13 @@ with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", owned_fn_defn = field_decl + " " + struct_name.replace("LDK", "") + "_get_" + field_name + "(" + struct_name + " *NONNULL_PTR owner)" holds_ref = False - if field_ty.rust_obj is not None and field_ty.rust_obj.replace("LDK", "") + "_clone" in clone_fns: + if field_ty.rust_obj is not None and field_ty.rust_obj in opaque_structs: + fn_defn = owned_fn_defn + write_c("static inline " + fn_defn + "{\n") + write_c("\t" + field_ty.rust_obj + " ret = " + accessor[0] + "owner" + accessor[1] + ";\n") + write_c("\tret.is_owned = false;\n") + write_c("\treturn ret;\n") + elif 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") if check_sfx is not None: @@ -931,7 +1015,7 @@ with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", elif struct_name in union_enum_items: tuple_variants = {} elem_items = -1 - for line, _ in field_lines: + for line, field_block_comment in field_lines: if line == " struct {": elem_items = 0 elif line == " };": @@ -944,7 +1028,7 @@ with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", line = line[5:] split = line.split(" ") assert len(split) == 2 - tuple_variants[split[1].strip(";")] = split[0] + tuple_variants[split[1].strip(";")] = (split[0], field_block_comment) elem_items += 1 if elem_items > 1: # We don't currently support tuple variant with more than one element @@ -970,8 +1054,27 @@ with open(sys.argv[1]) as in_h, open(f"{sys.argv[2]}/bindings{consts.file_ext}", write_c("\treturn thing->value;") write_c("}") map_fn(fn_line + "\n", re.compile("(.*) (TxOut_get_value) \((.*)\)").match(fn_line), None, None, None) + elif struct_name == "LDKBigEndianScalar": + with open(f"{sys.argv[3]}/structs/BigEndianScalar{consts.file_ext}", "w") as out_java_struct: + out_java_struct.write(consts.hu_struct_file_prefix) + out_java_struct.write(consts.scalar_defn) + fn_line = "struct LDKThirtyTwoBytes BigEndianScalar_get_bytes (struct LDKBigEndianScalar* thing)" + write_c(fn_line + " {\n") + write_c("\tLDKThirtyTwoBytes ret = { .data = *thing->big_endian_bytes };\n") + write_c("\treturn ret;\n") + write_c("}\n") + map_fn(fn_line + "\n", re.compile("(.*) (BigEndianScalar_get_bytes) \((.*)\)").match(fn_line), None, None, None) + + # We need to be able to FREE a heap-allocated BigEndianScalar, but because + # there's nothing heap-allocated inside it the C bindings don't bother + # exposing a `_free` method. Instead, we have to manually write one here, + # though it doesn't need to do anything, the autogenerated wrapper will do + # the required FREE. + fn_line = "static void BigEndianScalar_free (struct LDKBigEndianScalar thing)" + write_c(fn_line + " {}\n") + map_fn(fn_line + "\n", re.compile("static (.*) (BigEndianScalar_free) \((.*)\)").match(fn_line), None, None, None) else: - pass # Everything remaining is a byte[] or some form + pass # Everything remaining is a byte[] of some form cur_block_obj = None else: fn_ptr = fn_ptr_regex.match(line)