Drop `#[no_mangle]` from `*_write_void` to make cbindgen not export
[ldk-c-bindings] / c-bindings-gen / src / main.rs
index 28cce19e9715067a150a194f496b7e27eb03e640..6853534624427a7b0a5fcb8295f8b4999254e672 100644 (file)
@@ -36,6 +36,7 @@ use blocks::*;
 
 const DEFAULT_IMPORTS: &'static str = "
 use alloc::str::FromStr;
+use alloc::string::String;
 use core::ffi::c_void;
 use core::convert::Infallible;
 use bitcoin::hashes::Hash;
@@ -73,7 +74,7 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
                        let mut for_obj_vec = Vec::new();
                        types.write_c_type(&mut for_obj_vec, for_ty, Some(generics), false);
                        full_obj_path = String::from_utf8(for_obj_vec).unwrap();
-                       assert!(full_obj_path.starts_with(TypeResolver::generated_container_path()));
+                       if !full_obj_path.starts_with(TypeResolver::generated_container_path()) { return; }
                        for_obj = full_obj_path[TypeResolver::generated_container_path().len() + 2..].into();
                }
 
@@ -94,7 +95,6 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
 
                                writeln!(w, "}}").unwrap();
                                if has_inner {
-                                       writeln!(w, "#[no_mangle]").unwrap();
                                        writeln!(w, "pub(crate) extern \"C\" fn {}_write_void(obj: *const c_void) -> crate::c_types::derived::CVec_u8Z {{", for_obj).unwrap();
                                        writeln!(w, "\tcrate::c_types::serialize_obj(unsafe {{ &*(obj as *const native{}) }})", for_obj).unwrap();
                                        writeln!(w, "}}").unwrap();
@@ -266,8 +266,8 @@ macro_rules! walk_supertraits { ($t: expr, $types: expr, ($( $($pat: pat)|* => $
 } } }
 
 macro_rules! get_module_type_resolver {
-       ($module: expr, $crate_libs: expr, $crate_types: expr) => { {
-               let module: &str = &$module;
+       ($type_in_module: expr, $crate_types: expr) => { {
+               let module: &str = &$type_in_module;
                let mut module_iter = module.rsplitn(2, "::");
                module_iter.next().unwrap();
                let module = module_iter.next().unwrap();
@@ -303,7 +303,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                (s, _i, _) => {
                        if let Some(supertrait) = types.crate_types.traits.get(s) {
                                supertrait_name = s.to_string();
-                               supertrait_resolver = get_module_type_resolver!(supertrait_name, types.crate_libs, types.crate_types);
+                               supertrait_resolver = get_module_type_resolver!(supertrait_name, types.crate_types);
                                gen_types.learn_associated_types(&supertrait, &supertrait_resolver);
                                break;
                        }
@@ -533,8 +533,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                                                                        writeln!(w, "\ttype {} = crate::{};", t.ident, $type_resolver.resolve_path(&tr.path, Some(&gen_types))).unwrap();
                                                                        for bound in bounds_iter {
                                                                                if let syn::TypeParamBound::Trait(t) = bound {
-                                                                                       // We only allow for `?Sized` here.
-                                                                                       if let syn::TraitBoundModifier::Maybe(_) = t.modifier {} else { panic!(); }
+                                                                                       // We only allow for `Sized` here.
                                                                                        assert_eq!(t.path.segments.len(), 1);
                                                                                        assert_eq!(format!("{}", t.path.segments[0].ident), "Sized");
                                                                                }
@@ -554,8 +553,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
        writeln!(w, "unsafe impl Send for {} {{}}", trait_name).unwrap();
        writeln!(w, "unsafe impl Sync for {} {{}}", trait_name).unwrap();
 
-       writeln!(w, "#[no_mangle]").unwrap();
-       writeln!(w, "pub(crate) extern \"C\" fn {}_clone_fields(orig: &{}) -> {} {{", trait_name, trait_name, trait_name).unwrap();
+       writeln!(w, "pub(crate) fn {}_clone_fields(orig: &{}) -> {} {{", trait_name, trait_name, trait_name).unwrap();
        writeln!(w, "\t{} {{", trait_name).unwrap();
        writeln!(w, "\t\tthis_arg: orig.this_arg,").unwrap();
        for (field, clone_fn, _) in generated_fields.iter() {
@@ -601,10 +599,10 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                },
                (s, i, generic_args) => {
                        if let Some(supertrait) = types.crate_types.traits.get(s) {
-                               let resolver = get_module_type_resolver!(s, types.crate_libs, types.crate_types);
+                               let resolver = get_module_type_resolver!(s, types.crate_types);
                                macro_rules! impl_supertrait {
                                        ($s: expr, $supertrait: expr, $i: expr, $generic_args: expr) => {
-                                               let resolver = get_module_type_resolver!($s, types.crate_libs, types.crate_types);
+                                               let resolver = get_module_type_resolver!($s, types.crate_types);
 
                                                // Blindly assume that the same imports where `supertrait` is defined are also
                                                // imported here. This will almost certainly break at some point, but it should be
@@ -647,6 +645,8 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                writeln!(w, "// directly as a Deref trait in higher-level structs:").unwrap();
                writeln!(w, "impl core::ops::Deref for {} {{\n\ttype Target = Self;", trait_name).unwrap();
                writeln!(w, "\tfn deref(&self) -> &Self {{\n\t\tself\n\t}}\n}}").unwrap();
+               writeln!(w, "impl core::ops::DerefMut for {} {{", trait_name).unwrap();
+               writeln!(w, "\tfn deref_mut(&mut self) -> &mut Self {{\n\t\tself\n\t}}\n}}").unwrap();
        }
 
        writeln!(w, "/// Calls the free function if one is set").unwrap();
@@ -805,12 +805,25 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
                                define_field!(('a' as u8 + idx as u8) as char, ('0' as u8 + idx as u8) as char, field);
                        }
                }
-               _ => unimplemented!()
+               syn::Fields::Unit => {},
        }
 
        if all_fields_settable {
                // Build a constructor!
                writeln!(w, "/// Constructs a new {} given each field", struct_name).unwrap();
+               match &s.fields {
+                       syn::Fields::Named(fields) => {
+                               writeln_arg_docs(w, &[], "", types, Some(&gen_types),
+                                       fields.named.iter().map(|field| (format!("{}_arg", field.ident.as_ref().unwrap()), &field.ty)),
+                                       None);
+                       },
+                       syn::Fields::Unnamed(fields) => {
+                               writeln_arg_docs(w, &[], "", types, Some(&gen_types),
+                                       fields.unnamed.iter().enumerate().map(|(idx, field)| (format!("{}_arg", ('a' as u8 + idx as u8)), &field.ty)),
+                                       None);
+                       },
+                       syn::Fields::Unit => {},
+               }
                write!(w, "#[must_use]\n#[no_mangle]\npub extern \"C\" fn {}_new(", struct_name).unwrap();
 
                match &s.fields {
@@ -828,7 +841,7 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
                                        types.write_c_type(w, &field.ty, Some(&gen_types), false);
                                }
                        }
-                       _ => unreachable!()
+                       syn::Fields::Unit => {},
                }
                write!(w, ") -> {} {{\n\t", struct_name).unwrap();
                match &s.fields {
@@ -848,7 +861,7 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
                                        }
                                }
                        },
-                       _ => unreachable!()
+                       syn::Fields::Unit => {},
                }
                write!(w, "{} {{ inner: ObjOps::heap_alloc(", struct_name).unwrap();
                match &s.fields {
@@ -876,7 +889,7 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
                                }
                                write!(w, "\t)").unwrap();
                        },
-                       _ => unreachable!()
+                       syn::Fields::Unit => write!(w, "{}::{} {{}}", types.module_path, struct_name).unwrap(),
                }
                writeln!(w, "), is_owned: true }}\n}}").unwrap();
        }
@@ -945,9 +958,11 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
                                if i.defaultness.is_some() || i.unsafety.is_some() { unimplemented!(); }
                                if let Some(trait_path) = i.trait_.as_ref() {
                                        if trait_path.0.is_some() { unimplemented!(); }
-                                       if types.understood_c_path(&trait_path.1) {
-                                               let full_trait_path = types.resolve_path(&trait_path.1, None);
-                                               let trait_obj = *types.crate_types.traits.get(&full_trait_path).unwrap();
+                                       let full_trait_path_opt = types.maybe_resolve_path(&trait_path.1, None);
+                                       let trait_obj_opt = full_trait_path_opt.as_ref().and_then(|path| types.crate_types.traits.get(path));
+                                       if types.understood_c_path(&trait_path.1) && trait_obj_opt.is_some() {
+                                               let full_trait_path = full_trait_path_opt.unwrap();
+                                               let trait_obj = *trait_obj_opt.unwrap();
 
                                                let supertrait_name;
                                                let supertrait_resolver;
@@ -955,7 +970,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
                                                        (s, _i, _) => {
                                                                if let Some(supertrait) = types.crate_types.traits.get(s) {
                                                                        supertrait_name = s.to_string();
-                                                                       supertrait_resolver = get_module_type_resolver!(supertrait_name, types.crate_libs, types.crate_types);
+                                                                       supertrait_resolver = get_module_type_resolver!(supertrait_name, types.crate_types);
                                                                        gen_types.learn_associated_types(&supertrait, &supertrait_resolver);
                                                                        break;
                                                                }
@@ -966,7 +981,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
                                                // mappings from a trai defined in a different file, we may mis-resolve or
                                                // fail to resolve the mapped types. Thus, we have to construct a new
                                                // resolver for the module that the trait was defined in here first.
-                                               let mut trait_resolver = get_module_type_resolver!(full_trait_path, types.crate_libs, types.crate_types);
+                                               let mut trait_resolver = get_module_type_resolver!(full_trait_path, types.crate_types);
                                                gen_types.learn_associated_types(trait_obj, &trait_resolver);
                                                let mut impl_associated_types = HashMap::new();
                                                for item in i.items.iter() {
@@ -1099,7 +1114,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
                                                                        }
                                                                        write_impl_fields!(s, supertrait_obj, t, "\t", types);
 
-                                                                       let resolver = get_module_type_resolver!(s, types.crate_libs, types.crate_types);
+                                                                       let resolver = get_module_type_resolver!(s, types.crate_types);
                                                                        walk_supertraits!(supertrait_obj, Some(&resolver), (
                                                                                (s, t, _) => {
                                                                                        if let Some(supertrait_obj) = types.crate_types.traits.get(s) {
@@ -1238,15 +1253,22 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
                                                        writeln!(w, "extern \"C\" fn {}_{}_cloned(new_obj: &mut crate::{}) {{", trait_obj.ident, ident, full_trait_path).unwrap();
                                                        writeln!(w, "\tnew_obj.this_arg = {}_clone_void(new_obj.this_arg);", ident).unwrap();
                                                        writeln!(w, "\tnew_obj.free = Some({}_free_void);", ident).unwrap();
-                                                       walk_supertraits!(trait_obj, Some(&types), (
-                                                               (s, t, _) => {
-                                                                       if types.crate_types.traits.get(s).is_some() {
-                                                                               assert!(!types.is_clonable(s)); // We don't currently support cloning with a clonable supertrait
-                                                                               writeln!(w, "\tnew_obj.{}.this_arg = new_obj.this_arg;", t).unwrap();
-                                                                               writeln!(w, "\tnew_obj.{}.free = None;", t).unwrap();
+
+                                                       fn seek_supertraits<W: std::io::Write>(w: &mut W, pfx: &str, tr: &syn::ItemTrait, types: &TypeResolver) {
+                                                               walk_supertraits!(tr, Some(types), (
+                                                                       (s, t, _) => {
+                                                                               if types.crate_types.traits.get(s).is_some() {
+                                                                                       assert!(!types.is_clonable(s)); // We don't currently support cloning with a clonable supertrait
+                                                                                       writeln!(w, "\tnew_obj.{}{}.this_arg = new_obj.this_arg;", pfx, t).unwrap();
+                                                                                       writeln!(w, "\tnew_obj.{}{}.free = None;", pfx, t).unwrap();
+                                                                                       let tr = types.crate_types.traits.get(s).unwrap();
+                                                                                       let resolver = get_module_type_resolver!(s, types.crate_types);
+                                                                                       seek_supertraits(w, &format!("{}.", t), tr, &resolver);
+                                                                               }
                                                                        }
-                                                               }
-                                                       ) );
+                                                               ) );
+                                                       }
+                                                       seek_supertraits(w, "", trait_obj, types);
                                                        writeln!(w, "}}").unwrap();
                                                }
                                                write!(w, "\n").unwrap();
@@ -2200,9 +2222,13 @@ fn walk_private_mod<'a>(ast_storage: &'a FullLibraryAST, orig_crate: &str, modul
                                        if let Some(trait_path) = i.trait_.as_ref() {
                                                if let Some(tp) = import_resolver.maybe_resolve_path(&trait_path.1, None) {
                                                        if let Some(sp) = import_resolver.maybe_resolve_path(&p.path, None) {
-                                                               match crate_types.trait_impls.entry(sp) {
-                                                                       hash_map::Entry::Occupied(mut e) => { e.get_mut().push(tp); },
-                                                                       hash_map::Entry::Vacant(e) => { e.insert(vec![tp]); },
+                                                               match crate_types.trait_impls.entry(sp.clone()) {
+                                                                       hash_map::Entry::Occupied(mut e) => { e.get_mut().push(tp.clone()); },
+                                                                       hash_map::Entry::Vacant(e) => { e.insert(vec![tp.clone()]); },
+                                                               }
+                                                               match crate_types.traits_impld.entry(tp) {
+                                                                       hash_map::Entry::Occupied(mut e) => { e.get_mut().push(sp); },
+                                                                       hash_map::Entry::Vacant(e) => { e.insert(vec![sp]); },
                                                                }
                                                        }
                                                }
@@ -2312,9 +2338,13 @@ fn walk_ast_first_pass<'a>(ast_storage: &'a FullLibraryAST, crate_types: &mut Cr
                                                        }
                                                        if let Some(tp) = import_resolver.maybe_resolve_path(&trait_path.1, None) {
                                                                if let Some(sp) = import_resolver.maybe_resolve_path(&p.path, None) {
-                                                                       match crate_types.trait_impls.entry(sp) {
-                                                                               hash_map::Entry::Occupied(mut e) => { e.get_mut().push(tp); },
-                                                                               hash_map::Entry::Vacant(e) => { e.insert(vec![tp]); },
+                                                                       match crate_types.trait_impls.entry(sp.clone()) {
+                                                                               hash_map::Entry::Occupied(mut e) => { e.get_mut().push(tp.clone()); },
+                                                                               hash_map::Entry::Vacant(e) => { e.insert(vec![tp.clone()]); },
+                                                                       }
+                                                                       match crate_types.traits_impld.entry(tp) {
+                                                                               hash_map::Entry::Occupied(mut e) => { e.get_mut().push(sp); },
+                                                                               hash_map::Entry::Vacant(e) => { e.insert(vec![sp]); },
                                                                        }
                                                                }
                                                        }