Support new cloned upstream API instead of clone
[ldk-java] / genbindings.py
index 3d5bac974c5b563cd50d1d84dfe3d6d2b5199f59..5e8071ec00b31e1c93a9d6a05ef69d9dbc043e37 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/env python3
-import sys, re
+import os, sys, re, subprocess
 
 if len(sys.argv) < 7:
     print("USAGE: /path/to/lightning.h /path/to/bindings/output /path/to/bindings/ /path/to/bindings/output.c debug lang")
@@ -33,6 +33,10 @@ else:
 
 consts = Consts(DEBUG, target=target)
 
+local_git_version = os.getenv("LDK_GARBAGECOLLECTED_GIT_OVERRIDE")
+if local_git_version is None:
+    local_git_version = subprocess.check_output(["git", "describe", '--tag', '--dirty']).decode("utf-8").strip()
+
 from bindingstypes import *
 
 c_file = ""
@@ -270,9 +274,11 @@ def java_c_types(fn_arg, ret_arr_len):
     else:
         ma = var_ty_regex.match(fn_arg)
         if ma.group(1).strip() in unitary_enums:
-            java_ty = ma.group(1).strip()
+            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/" + ma.group(1).strip() + ";"
+            fn_ty_arg = "Lorg/ldk/enums/" + java_ty + ";"
             fn_arg = ma.group(2).strip()
             rust_obj = ma.group(1).strip()
         elif ma.group(1).strip().startswith("LDKC2Tuple"):
@@ -400,6 +406,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
     def map_fn(line, re_match, ret_arr_len, c_call_string, doc_comment):
         method_return_type = re_match.group(1)
         method_name = re_match.group(2)
+        orig_method_name = str(method_name)
         method_comma_separated_arguments = re_match.group(3)
         method_arguments = method_comma_separated_arguments.split(',')
 
@@ -414,12 +421,15 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
         argument_types = []
         default_constructor_args = {}
         takes_self = False
+        takes_self_ptr = False
         args_known = True
 
         for argument_index, argument in enumerate(method_arguments):
             argument_conversion_info = type_mapping_generator.map_type(argument, False, None, is_free, True)
             if argument_index == 0 and argument_conversion_info.java_hu_ty == struct_meth:
                 takes_self = True
+                if argument_conversion_info.ty_info.is_ptr:
+                    takes_self_ptr = True
             if argument_conversion_info.arg_conv is not None and "Warning" in argument_conversion_info.arg_conv:
                 if argument_conversion_info.rust_obj in constructor_fns:
                     assert not is_free
@@ -434,10 +444,14 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
                             default_constructor_args[argument_conversion_info.arg_name] = []
                         default_constructor_args[argument_conversion_info.arg_name].append(explode_arg_conv)
             argument_types.append(argument_conversion_info)
+        if not takes_self and return_type_info.java_hu_ty != struct_meth:
+            if not return_type_info.java_hu_ty.startswith("Result_" + struct_meth):
+                method_name = orig_method_name
+                struct_meth = ""
 
         out_java.write("\t// " + line)
         (out_java_delta, out_c_delta, out_java_struct_delta) = \
-            consts.map_function(argument_types, c_call_string, method_name, return_type_info, struct_meth, default_constructor_args, takes_self, args_known, type_mapping_generator, doc_comment)
+            consts.map_function(argument_types, c_call_string, method_name, return_type_info, struct_meth, default_constructor_args, takes_self, takes_self_ptr, args_known, type_mapping_generator, doc_comment)
         out_java.write(out_java_delta)
 
         if is_free:
@@ -469,14 +483,23 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
                 or expected_struct in complex_enums or expected_cstruct in complex_enums
                 or expected_cstruct in result_types) and not is_free:
             out_java_struct = open(f"{sys.argv[3]}/structs/{struct_meth}{consts.file_ext}", "a")
-        elif (method_name.startswith("C2Tuple_") and method_name.endswith("_read")) or \
-                (return_type_info.rust_obj is not None and "Result" in return_type_info.rust_obj and "from" in method_name):
-            out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
-        if out_java_struct is not None:
             out_java_struct.write(out_java_struct_delta)
+        elif (not is_free and not method_name.endswith("_clone") and
+                not method_name.startswith("_") and
+                method_name != "check_platform" and method_name != "Result_read" and
+                not expected_struct in unitary_enums and
+                ((not method_name.startswith("C2Tuple_") and not method_name.startswith("C3Tuple_"))
+                  or method_name.endswith("_read"))):
+            out_java_struct = open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a")
+            for line in out_java_struct_delta.splitlines():
+                if not line.strip().startswith("this."):
+                    out_java_struct.write(line + "\n")
+                else:
+                    out_java_struct.write("\t\t// " + line.strip() + "\n")
 
     def map_unitary_enum(struct_name, field_lines, enum_doc_comment):
-        with open(f"{sys.argv[3]}/enums/{struct_name}{consts.file_ext}", "w") as out_java_enum:
+        assert struct_name.startswith("LDK")
+        with open(f"{sys.argv[3]}/enums/{struct_name[3:]}{consts.file_ext}", "w") as out_java_enum:
             unitary_enums.add(struct_name)
             for idx, struct_line in enumerate(field_lines):
                 if idx == 0:
@@ -487,7 +510,8 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
                     assert(struct_line == "} %s;" % struct_name)
                 elif idx == len(field_lines) - 1:
                     assert(struct_line == "")
-            (c_out, native_file_out, native_out) = consts.native_c_unitary_enum_map(struct_name, [x.strip().strip(",") for x in field_lines[1:-3]], enum_doc_comment)
+            assert struct_name.startswith("LDK")
+            (c_out, native_file_out, native_out) = consts.native_c_unitary_enum_map(struct_name[3:], [x.strip().strip(",") for x in field_lines[1:-3]], enum_doc_comment)
             write_c(c_out)
             out_java_enum.write(native_file_out)
             out_java.write(native_out)
@@ -546,16 +570,20 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
 
             field_fns = []
             for fn_docs, fn_line in trait_fn_lines:
-                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
+                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:
+                    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_conv_info = type_mapping_generator.map_type(arg, True, None, 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))
+                    arg_tys = []
+                    for idx, arg in enumerate(fn_line.group(5).split(',')):
+                        if arg == "":
+                            continue
+                        arg_conv_info = type_mapping_generator.map_type(arg, True, None, 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)
@@ -563,9 +591,11 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
             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) != "clone" and fn_line.group(3) != "eq" and not is_log:
+            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):
@@ -693,7 +723,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
                     write_c("\tret->" + e + " = " + e + ";\n")
                 if ty_info.arg_conv_cleanup is not None:
                     write_c("\t//TODO: Really need to call " + ty_info.arg_conv_cleanup + " here\n")
-        write_c("\treturn (long)ret;\n")
+        write_c("\treturn (uint64_t)ret;\n")
         write_c("}\n")
 
         for idx, ty_info in enumerate(ty_list):
@@ -709,7 +739,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
                 write_c("\treturn tuple->" + e + ";\n")
             write_c("}\n")
 
-    out_java.write(consts.bindings_header)
+    out_java.write(consts.bindings_header.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)
@@ -726,8 +756,9 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
     line_indicates_trait_regex = re.compile("^   (struct |enum |union )?([A-Za-z_0-9]* \*?)\(\*([A-Za-z_0-9]*)\)\((const )?void \*this_arg(.*)\);$")
     assert(line_indicates_trait_regex.match("   uintptr_t (*send_data)(void *this_arg, LDKu8slice data, bool resume_read);"))
     assert(line_indicates_trait_regex.match("   struct LDKCVec_MessageSendEventZ (*get_and_clear_pending_msg_events)(const void *this_arg);"))
-    assert(line_indicates_trait_regex.match("   void *(*clone)(const void *this_arg);"))
     assert(line_indicates_trait_regex.match("   struct LDKCVec_u8Z (*write)(const void *this_arg);"))
+    line_indicates_trait_clone_regex = re.compile("^   void \(\*cloned\)\(struct ([A-Za-z0-9])* \*NONNULL_PTR new_[A-Za-z0-9]*\);$")
+    assert(line_indicates_trait_clone_regex.match("   void (*cloned)(struct LDKSign *NONNULL_PTR new_Sign);"))
     line_field_var_regex = re.compile("^   struct ([A-Za-z_0-9]*) ([A-Za-z_0-9]*);$")
     assert(line_field_var_regex.match("   struct LDKMessageSendEventsProvider MessageSendEventsProvider;"))
     assert(line_field_var_regex.match("   struct LDKChannelPublicKeys pubkeys;"))
@@ -793,6 +824,9 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
                         trait_fn_match = line_indicates_trait_regex.match(struct_line)
                         if trait_fn_match is not None:
                             trait_fn_lines.append((last_struct_block_comment, trait_fn_match))
+                        trait_clone_fn_match = line_indicates_trait_clone_regex.match(struct_line)
+                        if trait_clone_fn_match is not None:
+                            trait_fn_lines.append((last_struct_block_comment, "cloned"))
                         field_var_match = line_field_var_regex.match(struct_line)
                         if field_var_match is not None:
                             field_var_lines.append(field_var_match)
@@ -853,7 +887,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
                         if cleanup is not None:
                             write_c("\t\t" + cleanup + ";\n")
                         write_c("\t}\n")
-                        write_c("\treturn (long)ret;\n")
+                        write_c("\treturn (uint64_t)ret;\n")
                         write_c("}\n")
 
                     if ty_info.is_native_primitive:
@@ -968,7 +1002,7 @@ with open(sys.argv[1]) as in_h, open(sys.argv[2], "w") as out_java:
             out_java_struct.write("}\n")
 
 with open(sys.argv[4], "w") as out_c:
-    out_c.write(consts.c_file_pfx)
+    out_c.write(consts.c_file_pfx.replace('<git_version_ldk_garbagecollected>', local_git_version))
     out_c.write(consts.init_str())
     out_c.write(c_file)
 with open(f"{sys.argv[3]}/structs/UtilMethods{consts.file_ext}", "a") as util: