+ lastund = False
+ lastchar = char
+ if char.isnumeric():
+ lastund = True
+ return (ret + lastchar.lower()).strip("_")
+
+def doc_to_field_nullable(doc):
+ if doc is None:
+ return False
+ for line in doc.splitlines():
+ if "Note that this (or a relevant inner pointer) may be NULL or all-0s to represent None" in line:
+ return True
+ return False
+
+def doc_to_params_ret_nullable(doc):
+ if doc is None:
+ return (set(), False)
+ params = set()
+ ret_null = False
+ for line in doc.splitlines():
+ if "may be NULL or all-0s to represent None" not in line:
+ continue
+ if "Note that the return value" in line:
+ ret_null = True
+ elif "Note that " in line:
+ param = line.split("Note that ")[1].split(" ")[0]
+ params.add(param)
+ return (params, ret_null)
+
+unitary_enums = set()
+# Map from enum name to "contains trait object"
+complex_enums = {}
+opaque_structs = set()
+trait_structs = {}
+result_types = set()
+tuple_types = {}
+
+var_is_arr_regex = re.compile("\(\* ?([A-za-z0-9_]*)\)\[([a-z0-9]*)\]")
+var_ty_regex = re.compile("([A-za-z_0-9]*)(.*)")
+java_c_types_none_allowed = True # Unset when we do the real pass that populates the above sets
+def java_c_types(fn_arg, ret_arr_len):
+ fn_arg = fn_arg.strip()
+ if fn_arg.startswith("MUST_USE_RES "):
+ fn_arg = fn_arg[13:]
+ is_const = False
+ if fn_arg.startswith("const "):
+ fn_arg = fn_arg[6:]
+ is_const = True
+ if fn_arg.startswith("struct "):
+ fn_arg = fn_arg[7:]
+ if fn_arg.startswith("enum "):
+ fn_arg = fn_arg[5:]
+ nonnull_ptr = "NONNULL_PTR" in fn_arg
+ fn_arg = fn_arg.replace("NONNULL_PTR", "")
+
+ is_ptr = False
+ take_by_ptr = False
+ rust_obj = None
+ arr_access = None
+ java_hu_ty = None
+ if fn_arg.startswith("LDKPaymentPreimage") or fn_arg.startswith("LDKPaymentSecret") or fn_arg.startswith("LDKPaymentHash"):
+ if fn_arg.startswith("LDKPaymentPreimage"):
+ fn_arg = "uint8_t (*" + fn_arg[19:] + ")[32]"
+ elif fn_arg.startswith("LDKPaymentSecret"):
+ fn_arg = "uint8_t (*" + fn_arg[17:] + ")[32]"
+ elif fn_arg.startswith("LDKPaymentHash"):
+ fn_arg = "uint8_t (*" + fn_arg[15:] + ")[32]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKThirtyTwoBytes"
+ arr_access = "data"
+ elif fn_arg.startswith("LDKThirtyTwoBytes"):
+ fn_arg = "uint8_t (*" + fn_arg[18:] + ")[32]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKThirtyTwoBytes"
+ arr_access = "data"
+ elif fn_arg.startswith("LDKTxid"):
+ fn_arg = "uint8_t (*" + fn_arg[8:] + ")[32]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKThirtyTwoBytes"
+ arr_access = "data"
+ elif fn_arg.startswith("LDKPublicKey"):
+ fn_arg = "uint8_t (*" + fn_arg[13:] + ")[33]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKPublicKey"
+ arr_access = "compressed_form"
+ elif fn_arg.startswith("LDKSecretKey"):
+ fn_arg = "uint8_t (*" + fn_arg[13:] + ")[32]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKSecretKey"
+ arr_access = "bytes"
+ elif fn_arg.startswith("LDKSignature"):
+ fn_arg = "uint8_t (*" + fn_arg[13:] + ")[64]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKSignature"
+ arr_access = "compact_form"
+ elif fn_arg.startswith("LDKRecoverableSignature"):
+ fn_arg = "uint8_t (*" + fn_arg[24:] + ")[68]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKRecoverableSignature"
+ arr_access = "serialized_form"
+ elif fn_arg.startswith("LDKThreeBytes"):
+ fn_arg = "uint8_t (*" + fn_arg[14:] + ")[3]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKThreeBytes"
+ arr_access = "data"
+ elif fn_arg.startswith("LDKFourBytes"):
+ fn_arg = "uint8_t (*" + fn_arg[13:] + ")[4]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKFourBytes"
+ arr_access = "data"
+ elif fn_arg.startswith("LDKSixteenBytes"):
+ fn_arg = "uint8_t (*" + fn_arg[16:] + ")[16]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKSixteenBytes"
+ arr_access = "data"
+ elif fn_arg.startswith("LDKTwentyBytes"):
+ fn_arg = "uint8_t (*" + fn_arg[15:] + ")[20]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKTwentyBytes"
+ arr_access = "data"
+ elif fn_arg.startswith("LDKTwelveBytes"):
+ fn_arg = "uint8_t (*" + fn_arg[15:] + ")[12]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKTwelveBytes"
+ arr_access = "data"
+ elif fn_arg.startswith("LDKu8slice"):
+ fn_arg = "uint8_t (*" + fn_arg[11:] + ")[datalen]"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ rust_obj = "LDKu8slice"
+ arr_access = "data"
+ elif fn_arg.startswith("LDKCVec_u8Z"):
+ fn_arg = "uint8_t (*" + fn_arg[12:] + ")[datalen]"
+ rust_obj = "LDKCVec_u8Z"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ arr_access = "data"
+ elif fn_arg.startswith("LDKTransaction ") or fn_arg == "LDKTransaction":
+ fn_arg = "uint8_t (*" + fn_arg[15:] + ")[datalen]"
+ rust_obj = "LDKTransaction"
+ assert var_is_arr_regex.match(fn_arg[8:])
+ arr_access = "data"
+ elif fn_arg.startswith("LDKCVec_"):
+ is_ptr = False
+ if "*" in fn_arg:
+ fn_arg = fn_arg.replace("*", "")
+ is_ptr = True
+
+ tyn = fn_arg[8:].split(" ")
+ assert tyn[0].endswith("Z")
+ if tyn[0] == "u64Z":
+ new_arg = "uint64_t"
+ else:
+ new_arg = "LDK" + tyn[0][:-1]
+ for a in tyn[1:]:
+ new_arg = new_arg + " " + a
+ res = java_c_types(new_arg, ret_arr_len)
+ if res is None:
+ assert java_c_types_none_allowed
+ return None
+ if is_ptr:
+ res.pass_by_ref = True
+ java_ty = consts.java_arr_ty_str(res.java_ty)
+ if res.is_native_primitive or res.passed_as_ptr:
+ return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
+ java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
+ nonnull_ptr=nonnull_ptr, is_const=is_const,
+ var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
+ else:
+ return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
+ java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
+ nonnull_ptr=nonnull_ptr, is_const=is_const,
+ var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
+
+ is_primitive = False
+ contains_trait = False
+ arr_len = None
+ mapped_type = []
+ java_type_plural = None
+ arr_ty = None
+ if fn_arg.startswith("void"):
+ java_ty = "void"
+ c_ty = "void"
+ fn_ty_arg = "V"
+ fn_arg = fn_arg[4:].strip()
+ is_primitive = True
+ elif fn_arg.startswith("bool"):
+ java_ty = "boolean"
+ c_ty = "jboolean"
+ fn_ty_arg = "Z"
+ arr_ty = "bool"
+ fn_arg = fn_arg[4:].strip()
+ is_primitive = True
+ elif fn_arg.startswith("uint8_t"):
+ mapped_type = consts.c_type_map['uint8_t']
+ java_ty = mapped_type[0]
+ c_ty = "int8_t"
+ fn_ty_arg = "B"
+ arr_ty = "uint8_t"
+ fn_arg = fn_arg[7:].strip()
+ is_primitive = True
+ elif fn_arg.startswith("LDKu5"):
+ java_ty = consts.c_type_map['uint8_t'][0]
+ java_hu_ty = "UInt5"
+ rust_obj = "LDKu5"
+ 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]
+ c_ty = "int16_t"
+ arr_ty = "uint16_t"
+ fn_ty_arg = "S"
+ fn_arg = fn_arg[8:].strip()
+ is_primitive = True
+ elif fn_arg.startswith("uint32_t"):
+ mapped_type = consts.c_type_map['uint32_t']
+ java_ty = mapped_type[0]
+ c_ty = "int32_t"
+ arr_ty = "uint32_t"
+ fn_ty_arg = "I"
+ fn_arg = fn_arg[8:].strip()
+ is_primitive = True
+ elif fn_arg.startswith("uint64_t") or fn_arg.startswith("uintptr_t"):
+ # TODO: uintptr_t is arch-dependent :(
+ mapped_type = consts.c_type_map['uint64_t']
+ java_ty = mapped_type[0]
+ fn_ty_arg = "J"
+ if fn_arg.startswith("uint64_t"):
+ c_ty = "int64_t"
+ arr_ty = "uint64_t"
+ fn_arg = fn_arg[8:].strip()
+ else:
+ java_ty = consts.ptr_native_ty
+ c_ty = consts.ptr_c_ty
+ arr_ty = "uintptr_t"
+ rust_obj = "uintptr_t"
+ fn_arg = fn_arg[9:].strip()
+ is_primitive = True
+ elif is_const and fn_arg.startswith("char *"):
+ java_ty = consts.java_type_map["String"]
+ java_hu_ty = consts.java_hu_type_map["String"]
+ c_ty = "const char*"
+ arr_ty = "LDKStr"
+ fn_ty_arg = "Ljava/lang/String;"
+ fn_arg = fn_arg[6:].strip()
+ elif fn_arg.startswith("LDKStr"):
+ rust_obj = "LDKStr"
+ arr_ty = "LDKStr"
+ java_ty = consts.java_type_map["String"]
+ java_hu_ty = consts.java_hu_type_map["String"]
+ c_ty = "jstring"
+ fn_ty_arg = "Ljava/lang/String;"
+ fn_arg = fn_arg[6:].strip()
+ arr_access = "chars"
+ arr_len = "len"
+ else:
+ ma = var_ty_regex.match(fn_arg)
+ arr_ty = ma.group(1).strip()
+ if ma.group(1).strip() in unitary_enums:
+ assert ma.group(1).strip().startswith("LDK")
+ java_ty = ma.group(1).strip()[3:]
+ java_hu_ty = java_ty
+ c_ty = consts.result_c_ty
+ fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
+ fn_arg = ma.group(2).strip()
+ rust_obj = ma.group(1).strip()
+ else:
+ c_ty = consts.ptr_c_ty
+ java_ty = consts.ptr_native_ty
+ java_hu_ty = ma.group(1).strip()
+ java_hu_ty = java_hu_ty.replace("LDKCOption", "Option")
+ java_hu_ty = java_hu_ty.replace("LDKCResult", "Result")
+ java_hu_ty = java_hu_ty.replace("LDKC2Tuple", "TwoTuple")
+ java_hu_ty = java_hu_ty.replace("LDKC3Tuple", "ThreeTuple")
+ java_hu_ty = java_hu_ty.replace("LDK", "")
+ fn_ty_arg = "J"
+ fn_arg = ma.group(2).strip()
+ rust_obj = ma.group(1).strip()
+ if rust_obj in trait_structs:
+ contains_trait = True
+ elif rust_obj in complex_enums:
+ contains_trait = complex_enums[rust_obj]
+ take_by_ptr = True
+
+ if fn_arg.startswith(" *") or fn_arg.startswith("*"):
+ fn_arg = fn_arg.replace("*", "").strip()
+ is_ptr = True
+ c_ty = consts.ptr_c_ty
+ java_ty = consts.ptr_native_ty
+ fn_ty_arg = "J"
+
+ var_is_arr = var_is_arr_regex.match(fn_arg)
+ subty = None
+ if var_is_arr is not None or ret_arr_len is not None:
+ assert(not take_by_ptr)
+ assert(not is_ptr)
+ # is there a special case for plurals?
+ if len(mapped_type) == 3:
+ java_ty = mapped_type[1]
+ java_hu_ty = mapped_type[2]
+ else:
+ java_ty = java_ty + "[]"
+ java_hu_ty = java_ty
+ c_ty = c_ty + "Array"
+
+ subty = java_c_types(arr_ty, None)
+ if subty is None:
+ assert java_c_types_none_allowed
+ return None
+ if is_ptr:
+ subty.pass_by_ref = True
+
+ if var_is_arr is not None:
+ if var_is_arr.group(1) == "":
+ 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,
+ passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
+ arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
+ 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,
+ passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
+ arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
+
+ if java_hu_ty is None:
+ java_hu_ty = java_ty
+ 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,
+ 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,
+ contains_trait=contains_trait, subty=subty)
+
+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]*)\((.*)\);$")
+clone_fns = set()
+constructor_fns = {}
+
+from gen_type_mapping import TypeMappingGenerator
+type_mapping_generator = TypeMappingGenerator(java_c_types, consts, opaque_structs, clone_fns, unitary_enums, trait_structs, complex_enums, result_types, tuple_types)
+
+with open(sys.argv[1]) as in_h:
+ for line in in_h:
+ reg_fn = reg_fn_regex.match(line)
+ if reg_fn is not None:
+ if reg_fn.group(2).endswith("_clone"):
+ clone_fns.add(reg_fn.group(2))