Check if types are understood before we map an impl block for them
[ldk-c-bindings] / c-bindings-gen / src / main.rs
index 8e3962d5da2f133fcb4068721e88d3f29fff27b1..b88f37ffe9e306cc0ac83b5abfaa16d7118e0af1 100644 (file)
@@ -559,7 +559,9 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
        // Finally, implement the original Rust trait for the newly created mapped trait.
        writeln!(w, "\nuse {}::{} as rust{};", types.module_path, t.ident, trait_name).unwrap();
        if implementable {
-               write!(w, "impl rust{}", t.ident).unwrap();
+               write!(w, "impl").unwrap();
+               maybe_write_lifetime_generics(w, &t.generics, types);
+               write!(w, " rust{}", t.ident).unwrap();
                maybe_write_generics(w, &t.generics, types, false);
                writeln!(w, " for {} {{", trait_name).unwrap();
                impl_trait_for_c!(t, "", types);
@@ -590,7 +592,7 @@ fn writeln_opaque<W: std::io::Write>(w: &mut W, ident: &syn::Ident, struct_name:
        // If we directly read the original type by its original name, cbindgen hits
        // https://github.com/eqrion/cbindgen/issues/286 Thus, instead, we import it as a temporary
        // name and then reference it by that name, which works around the issue.
-       write!(w, "\nuse {}::{} as native{}Import;\ntype native{} = native{}Import", types.module_path, ident, ident, ident, ident).unwrap();
+       write!(w, "\nuse {}::{} as native{}Import;\npub(crate) type native{} = native{}Import", types.module_path, ident, ident, ident, ident).unwrap();
        maybe_write_generics(w, &generics, &types, true);
        writeln!(w, ";\n").unwrap();
        writeln!(extra_headers, "struct native{}Opaque;\ntypedef struct native{}Opaque LDKnative{};", ident, ident, ident).unwrap();
@@ -612,7 +614,7 @@ fn writeln_opaque<W: std::io::Write>(w: &mut W, ident: &syn::Ident, struct_name:
        writeln!(w, "#[no_mangle]\npub extern \"C\" fn {}_free(this_obj: {}) {{ }}", struct_name, struct_name).unwrap();
        writeln!(w, "#[allow(unused)]").unwrap();
        writeln!(w, "/// Used only if an object of this type is returned as a trait impl by a method").unwrap();
-       writeln!(w, "extern \"C\" fn {}_free_void(this_ptr: *mut c_void) {{", struct_name).unwrap();
+       writeln!(w, "pub(crate) extern \"C\" fn {}_free_void(this_ptr: *mut c_void) {{", struct_name).unwrap();
        writeln!(w, "\tunsafe {{ let _ = Box::from_raw(this_ptr as *mut native{}); }}\n}}", struct_name).unwrap();
        writeln!(w, "#[allow(unused)]").unwrap();
        writeln!(w, "impl {} {{", struct_name).unwrap();
@@ -646,7 +648,7 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
                let mut self_path_segs = syn::punctuated::Punctuated::new();
                self_path_segs.push(s.ident.clone().into());
                let self_path = syn::Path { leading_colon: None, segments: self_path_segs};
-               let mut gen_types = GenericTypes::new(Some((types.resolve_path(&self_path, None), &self_path)));
+               let mut gen_types = GenericTypes::new(Some(types.resolve_path(&self_path, None)));
                assert!(gen_types.learn_generics(&s.generics, types));
 
                let mut all_fields_settable = true;
@@ -769,7 +771,12 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                if p.qself.is_some() { unimplemented!(); }
                if let Some(ident) = single_ident_generic_path_to_ident(&p.path) {
                        if let Some(resolved_path) = types.maybe_resolve_non_ignored_ident(&ident) {
-                               let mut gen_types = GenericTypes::new(Some((resolved_path.clone(), &p.path)));
+                               if !types.understood_c_path(&p.path) {
+                                       eprintln!("Not implementing anything for impl {} as the type is not understood (probably C-not exported)", ident);
+                                       return;
+                               }
+
+                               let mut gen_types = GenericTypes::new(Some(resolved_path.clone()));
                                if !gen_types.learn_generics(&i.generics, types) {
                                        eprintln!("Not implementing anything for impl {} due to not understood generics", ident);
                                        return;
@@ -827,7 +834,13 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                                                // properly. This way we can call this method from deep in the
                                                // type-conversion logic without actually knowing the concrete native type.
                                                if !resolved_path.starts_with(types.module_path) {
-                                                       writeln!(w, "use {} as native{};", resolved_path, ident).unwrap();
+                                                       if !first_seg_is_stdlib(resolved_path.split("::").next().unwrap()) {
+                                                               writeln!(w, "use crate::{}::native{} as native{};", resolved_path.rsplitn(2, "::").skip(1).next().unwrap(), ident, ident).unwrap();
+                                                               writeln!(w, "use crate::{};", resolved_path).unwrap();
+                                                               writeln!(w, "use crate::{}_free_void;", resolved_path).unwrap();
+                                                       } else {
+                                                               writeln!(w, "use {} as native{};", resolved_path, ident).unwrap();
+                                                       }
                                                }
                                                writeln!(w, "impl From<native{}> for crate::{} {{", ident, full_trait_path).unwrap();
                                                writeln!(w, "\tfn from(obj: native{}) -> Self {{", ident).unwrap();
@@ -1853,7 +1866,8 @@ fn walk_ast<'a>(ast_storage: &'a FullLibraryAST, crate_types: &mut CrateTypes<'a
                                syn::Item::Impl(i) => {
                                        if let &syn::Type::Path(ref p) = &*i.self_ty {
                                                if let Some(trait_path) = i.trait_.as_ref() {
-                                                       if path_matches_nongeneric(&trait_path.1, &["core", "clone", "Clone"]) {
+                                                       if path_matches_nongeneric(&trait_path.1, &["core", "clone", "Clone"]) ||
+                                                          path_matches_nongeneric(&trait_path.1, &["Clone"]) {
                                                                if let Some(full_path) = import_resolver.maybe_resolve_path(&p.path, None) {
                                                                        crate_types.set_clonable("crate::".to_owned() + &full_path);
                                                                }
@@ -1904,6 +1918,9 @@ fn main() {
        writeln!(header_file, "#endif").unwrap();
        writeln!(cpp_header_file, "#include <string.h>\nnamespace LDK {{").unwrap();
 
+       // Write a few manually-defined types into the C++ header file
+       write_cpp_wrapper(&mut cpp_header_file, "Str", true, None);
+
        // First parse the full crate's ASTs, caching them so that we can hold references to the AST
        // objects in other datastructures:
        let mut lib_src = String::new();