Include argument info docs on all-pub struct constructors
[ldk-c-bindings] / c-bindings-gen / src / main.rs
index f5a7656c0af60aecba2729388b9d503087d89ae8..7c066875a5b6a0198e8dadf2ecdaa7d6e725831e 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();
                }
 
@@ -351,10 +352,10 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                                                // the Rust type and a flag to indicate whether deallocation needs to
                                                // happen) as well as provide an Option<>al function pointer which is
                                                // called when the trait method is called which allows updating on the fly.
-                                               write!(w, "\tpub {}: ", m.sig.ident).unwrap();
-                                               generated_fields.push((format!("{}", m.sig.ident), None, None));
+                                               write!(w, "\tpub {}: core::cell::UnsafeCell<", m.sig.ident).unwrap();
+                                               generated_fields.push((format!("{}", m.sig.ident), Some(("Clone::clone(unsafe { &*core::cell::UnsafeCell::get(".to_owned(), ")}).into()")), None));
                                                types.write_c_type(w, &*r.elem, Some(&meth_gen_types), false);
-                                               writeln!(w, ",").unwrap();
+                                               writeln!(w, ">,").unwrap();
                                                writeln!(w, "\t/// Fill in the {} field as a reference to it will be given to Rust after this returns", m.sig.ident).unwrap();
                                                writeln!(w, "\t/// Note that this takes a pointer to this object, not the this_ptr like other methods do").unwrap();
                                                writeln!(w, "\t/// This function pointer may be NULL if {} is filled in when this object is created and never needs updating.", m.sig.ident).unwrap();
@@ -366,9 +367,6 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                                                writeln!(extra_headers, "struct LDK{};", trait_name).unwrap();
                                                continue;
                                        }
-                                       // Sadly, this currently doesn't do what we want, but it should be easy to get
-                                       // cbindgen to support it. See https://github.com/eqrion/cbindgen/issues/531
-                                       writeln!(w, "\t#[must_use]").unwrap();
                                }
 
                                let mut cpp_docs = Vec::new();
@@ -430,7 +428,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                                let is_clonable = types.is_clonable(s);
                                writeln!(w, "\tpub {}: crate::{},", i, s).unwrap();
                                (format!("{}", i), if !is_clonable {
-                                       Some(format!("crate::{}_clone_fields", s))
+                                       Some((format!("crate::{}_clone_fields(", s), ")"))
                                } else { None }, None)
                        });
                }
@@ -513,7 +511,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                                                                writeln!(w, "\t\t\t(f)(&self{});", $impl_accessor).unwrap();
                                                                write!(w, "\t\t}}\n\t\t").unwrap();
                                                                $type_resolver.write_from_c_conversion_to_ref_prefix(w, &*r.elem, Some(&meth_gen_types));
-                                                               write!(w, "self{}.{}", $impl_accessor, m.sig.ident).unwrap();
+                                                               write!(w, "unsafe {{ &*self{}.{}.get() }}", $impl_accessor, m.sig.ident).unwrap();
                                                                $type_resolver.write_from_c_conversion_to_ref_suffix(w, &*r.elem, Some(&meth_gen_types));
                                                                writeln!(w, "\n\t}}").unwrap();
                                                                continue;
@@ -535,7 +533,11 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                                                                syn::TypeParamBound::Trait(tr) => {
                                                                        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(_) = bound { panic!("11"); }
+                                                                               if let syn::TypeParamBound::Trait(t) = bound {
+                                                                                       // We only allow for `Sized` here.
+                                                                                       assert_eq!(t.path.segments.len(), 1);
+                                                                                       assert_eq!(format!("{}", t.path.segments[0].ident), "Sized");
+                                                                               }
                                                                        }
                                                                        break;
                                                                },
@@ -552,14 +554,13 @@ 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() {
-               if let Some(f) = clone_fn {
+               if let Some((pfx, sfx)) = clone_fn {
                        // If the field isn't clonable, blindly assume its a trait and hope for the best.
-                       writeln!(w, "\t\t{}: {}(&orig.{}),", field, f, field).unwrap();
+                       writeln!(w, "\t\t{}: {}&orig.{}{},", field, pfx, field, sfx).unwrap();
                } else {
                        writeln!(w, "\t\t{}: Clone::clone(&orig.{}),", field, field).unwrap();
                }
@@ -600,18 +601,31 @@ 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);
-
-                               // 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
-                               // a compilation failure when it does so.
-                               write!(w, "impl").unwrap();
-                               maybe_write_lifetime_generics(w, &supertrait.generics, types);
-                               write!(w, " {}", s).unwrap();
-                               maybe_write_generics(w, &supertrait.generics, generic_args, types, false);
-                               writeln!(w, " for {} {{", trait_name).unwrap();
-
-                               impl_trait_for_c!(supertrait, format!(".{}", i), &resolver, generic_args);
-                               writeln!(w, "}}").unwrap();
+                               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);
+
+                                               // 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
+                                               // a compilation failure when it does so.
+                                               write!(w, "impl").unwrap();
+                                               maybe_write_lifetime_generics(w, &$supertrait.generics, types);
+                                               write!(w, " {}", $s).unwrap();
+                                               maybe_write_generics(w, &$supertrait.generics, $generic_args, types, false);
+                                               writeln!(w, " for {} {{", trait_name).unwrap();
+
+                                               impl_trait_for_c!($supertrait, format!(".{}", $i), &resolver, $generic_args);
+                                               writeln!(w, "}}").unwrap();
+                                       }
+                               }
+                               impl_supertrait!(s, supertrait, i, generic_args);
+                               walk_supertraits!(supertrait, Some(&resolver), (
+                                       (s, supertrait_i, generic_args) => {
+                                               if let Some(supertrait) = types.crate_types.traits.get(s) {
+                                                       impl_supertrait!(s, supertrait, format!("{}.{}", i, supertrait_i), generic_args);
+                                               }
+                                       }
+                               ) );
                        } else {
                                do_write_impl_trait(w, s, i, &trait_name);
                        }
@@ -632,6 +646,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();
@@ -790,12 +806,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 {
@@ -813,7 +842,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 {
@@ -833,7 +862,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 {
@@ -861,7 +890,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();
        }
@@ -930,9 +959,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;
@@ -1033,7 +1064,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
                                                                        if let syn::Type::Reference(r) = &**rtype {
                                                                                write!(w, "\n\t\t{}{}: ", $indent, $m.sig.ident).unwrap();
                                                                                types.write_empty_rust_val(Some(&gen_types), w, &*r.elem);
-                                                                               writeln!(w, ",\n{}\t\tset_{}: Some({}_{}_set_{}),", $indent, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
+                                                                               writeln!(w, ".into(),\n{}\t\tset_{}: Some({}_{}_set_{}),", $indent, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
                                                                                printed = true;
                                                                        }
                                                                }
@@ -1061,17 +1092,38 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
                                                        ("core::fmt::Debug", _, _) => {},
                                                        (s, t, _) => {
                                                                if let Some(supertrait_obj) = types.crate_types.traits.get(s) {
-                                                                       writeln!(w, "\t\t{}: crate::{} {{", t, s).unwrap();
-                                                                       writeln!(w, "\t\t\tthis_arg: unsafe {{ ObjOps::untweak_ptr((*this_arg).inner) as *mut c_void }},").unwrap();
-                                                                       writeln!(w, "\t\t\tfree: None,").unwrap();
-                                                                       for item in supertrait_obj.items.iter() {
-                                                                               match item {
-                                                                                       syn::TraitItem::Method(m) => {
-                                                                                               write_meth!(m, supertrait_obj, "\t");
+                                                                       macro_rules! write_impl_fields {
+                                                                               ($s: expr, $supertrait_obj: expr, $t: expr, $pfx: expr, $resolver: expr) => {
+                                                                                       writeln!(w, "{}\t{}: crate::{} {{", $pfx, $t, $s).unwrap();
+                                                                                       writeln!(w, "{}\t\tthis_arg: unsafe {{ ObjOps::untweak_ptr((*this_arg).inner) as *mut c_void }},", $pfx).unwrap();
+                                                                                       writeln!(w, "{}\t\tfree: None,", $pfx).unwrap();
+                                                                                       for item in $supertrait_obj.items.iter() {
+                                                                                               match item {
+                                                                                                       syn::TraitItem::Method(m) => {
+                                                                                                               write_meth!(m, $supertrait_obj, $pfx);
+                                                                                                       },
+                                                                                                       _ => {},
+                                                                                               }
+                                                                                       }
+                                                                               walk_supertraits!($supertrait_obj, Some(&$resolver), (
+                                                                                       ("Clone", _, _) => {
+                                                                                               writeln!(w, "{}\tcloned: Some({}_{}_cloned),", $pfx, $supertrait_obj.ident, ident).unwrap();
                                                                                        },
-                                                                                       _ => {},
+                                                                                       (_, _, _) => {}
+                                                                               ) );
                                                                                }
                                                                        }
+                                                                       write_impl_fields!(s, supertrait_obj, t, "\t", types);
+
+                                                                       let resolver = get_module_type_resolver!(s, types.crate_libs, types.crate_types);
+                                                                       walk_supertraits!(supertrait_obj, Some(&resolver), (
+                                                                               (s, t, _) => {
+                                                                                       if let Some(supertrait_obj) = types.crate_types.traits.get(s) {
+                                                                                               write_impl_fields!(s, supertrait_obj, t, "\t\t", resolver);
+                                                                                               write!(w, "\t\t\t}},\n").unwrap();
+                                                                                       }
+                                                                               }
+                                                                       ) );
                                                                        write!(w, "\t\t}},\n").unwrap();
                                                                } else {
                                                                        write_trait_impl_field_assign(w, s, ident);
@@ -1164,9 +1216,9 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
                                                                                writeln!(w, "\t// This is a bit race-y in the general case, but for our specific use-cases today, we're safe").unwrap();
                                                                                writeln!(w, "\t// Specifically, we must ensure that the first time we're called it can never be in parallel").unwrap();
                                                                                write!(w, "\tif ").unwrap();
-                                                                               $types.write_empty_rust_val_check(Some(&meth_gen_types), w, &*r.elem, &format!("trait_self_arg.{}", $m.sig.ident));
+                                                                               $types.write_empty_rust_val_check(Some(&meth_gen_types), w, &*r.elem, &format!("unsafe {{ &*trait_self_arg.{}.get() }}", $m.sig.ident));
                                                                                writeln!(w, " {{").unwrap();
-                                                                               writeln!(w, "\t\tunsafe {{ &mut *(trait_self_arg as *const {}  as *mut {}) }}.{} = {}_{}_{}(trait_self_arg.this_arg);", $trait.ident, $trait.ident, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
+                                                                               writeln!(w, "\t\t*unsafe {{ &mut *(&*(trait_self_arg as *const {})).{}.get() }} = {}_{}_{}(trait_self_arg.this_arg).into();", $trait.ident, $m.sig.ident, ident, $trait.ident, $m.sig.ident).unwrap();
                                                                                writeln!(w, "\t}}").unwrap();
                                                                                writeln!(w, "}}").unwrap();
                                                                        }
@@ -1255,7 +1307,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRa
 
                                                writeln!(w, " {{ true }} else {{ false }}\n}}").unwrap();
                                        } else if path_matches_nongeneric(&trait_path.1, &["core", "hash", "Hash"]) {
-                                               writeln!(w, "/// Checks if two {}s contain equal inner contents.", ident).unwrap();
+                                               writeln!(w, "/// Generates a non-cryptographic 64-bit hash of the {}.", ident).unwrap();
                                                write!(w, "#[no_mangle]\npub extern \"C\" fn {}_hash(o: &{}) -> u64 {{\n", ident, ident).unwrap();
                                                if types.c_type_has_inner_from_path(&resolved_path) {
                                                        write!(w, "\tif o.inner.is_null() {{ return 0; }}\n").unwrap();
@@ -1699,7 +1751,6 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                                write!(w, ")").unwrap();
                        }
                }
-               if var.discriminant.is_some() { unimplemented!(); }
                write!(&mut constr, ") -> {} {{\n\t{}::{}", e.ident, e.ident, var.ident).unwrap();
                if let syn::Fields::Named(fields) = &var.fields {
                        writeln!(&mut constr, " {{").unwrap();
@@ -2165,9 +2216,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]); },
                                                                }
                                                        }
                                                }
@@ -2277,9 +2332,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]); },
                                                                        }
                                                                }
                                                        }