[bindings] Drop useless `#[no_mangle]` from `pub type` definitions
[rust-lightning] / c-bindings-gen / src / main.rs
index b04d6b007828f9adc40eef56dae5bca551cc65b9..f427b5063c5165e90f4a0a92574ac70e1395742f 100644 (file)
@@ -42,6 +42,10 @@ fn convert_macro<W: std::io::Write>(w: &mut W, macro_path: &syn::Path, stream: &
                                writeln!(w, "\tcrate::c_types::serialize_obj(unsafe {{ &(*(*obj).inner) }})").unwrap();
                                writeln!(w, "}}").unwrap();
                                writeln!(w, "#[no_mangle]").unwrap();
+                               writeln!(w, "pub(crate) extern \"C\" fn {}_write_void(obj: *const c_void) -> crate::c_types::derived::CVec_u8Z {{", struct_for).unwrap();
+                               writeln!(w, "\tcrate::c_types::serialize_obj(unsafe {{ &*(obj as *const native{}) }})", struct_for).unwrap();
+                               writeln!(w, "}}").unwrap();
+                               writeln!(w, "#[no_mangle]").unwrap();
                                writeln!(w, "pub extern \"C\" fn {}_read(ser: crate::c_types::u8slice) -> {} {{", struct_for, struct_for).unwrap();
                                writeln!(w, "\tif let Ok(res) = crate::c_types::deserialize_obj(ser) {{").unwrap();
                                writeln!(w, "\t\t{} {{ inner: Box::into_raw(Box::new(res)), is_owned: true }}", struct_for).unwrap();
@@ -65,6 +69,10 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
                                writeln!(w, "pub extern \"C\" fn {}_write(obj: *const {}) -> crate::c_types::derived::CVec_u8Z {{", for_obj, for_obj).unwrap();
                                writeln!(w, "\tcrate::c_types::serialize_obj(unsafe {{ &(*(*obj).inner) }})").unwrap();
                                writeln!(w, "}}").unwrap();
+                               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();
                        },
                        "util::ser::Readable" => {
                                writeln!(w, "#[no_mangle]").unwrap();
@@ -80,6 +88,28 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
        }
 }
 
+/// Convert "TraitA : TraitB" to a single function name and return type.
+///
+/// This is (obviously) somewhat over-specialized and only useful for TraitB's that only require a
+/// single function (eg for serialization).
+fn convert_trait_impl_field(trait_path: &str) -> (String, &'static str) {
+       match trait_path {
+               "util::ser::Writeable" => ("write".to_owned(), "crate::c_types::derived::CVec_u8Z"),
+               _ => unimplemented!(),
+       }
+}
+
+/// Companion to convert_trait_impl_field, write an assignment for the function defined by it for
+/// `for_obj` which implements the the trait at `trait_path`.
+fn write_trait_impl_field_assign<W: std::io::Write>(w: &mut W, trait_path: &str, for_obj: &syn::Ident) {
+       match trait_path {
+               "util::ser::Writeable" => {
+                       writeln!(w, "\t\twrite: {}_write_void,", for_obj).unwrap();
+               },
+               _ => unimplemented!(),
+       }
+}
+
 /// Write out the impl block for a defined trait struct which has a supertrait
 fn do_write_impl_trait<W: std::io::Write>(w: &mut W, trait_path: &str, trait_name: &syn::Ident, for_obj: &str) {
        match trait_path {
@@ -89,6 +119,13 @@ fn do_write_impl_trait<W: std::io::Write>(w: &mut W, trait_path: &str, trait_nam
                        writeln!(w, "\t\t<crate::{} as lightning::{}>::get_and_clear_pending_msg_events(&self.{})", trait_path, trait_path, trait_name).unwrap();
                        writeln!(w, "\t}}\n}}").unwrap();
                },
+               "util::ser::Writeable" => {
+                       writeln!(w, "impl lightning::{} for {} {{", trait_path, for_obj).unwrap();
+                       writeln!(w, "\tfn write<W: lightning::util::ser::Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {{").unwrap();
+                       writeln!(w, "\t\tlet vec = (self.write)(self.this_arg);").unwrap();
+                       writeln!(w, "\t\tw.write_all(vec.as_slice())").unwrap();
+                       writeln!(w, "\t}}\n}}").unwrap();
+               },
                _ => panic!(),
        }
 }
@@ -227,10 +264,15 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                },
                ("Send", _) => {}, ("Sync", _) => {},
                (s, i) => {
-                       // For in-crate supertraits, just store a C-mapped copy of the supertrait as a member.
-                       if types.crate_types.traits.get(s).is_none() { unimplemented!(); }
-                       writeln!(w, "\tpub {}: crate::{},", i, s).unwrap();
-                       generated_fields.push(format!("{}", i));
+                       generated_fields.push(if types.crate_types.traits.get(s).is_none() {
+                               let (name, ret) = convert_trait_impl_field(s);
+                               writeln!(w, "\tpub {}: extern \"C\" fn (this_arg: *const c_void) -> {},", name, ret).unwrap();
+                               name
+                       } else {
+                               // For in-crate supertraits, just store a C-mapped copy of the supertrait as a member.
+                               writeln!(w, "\tpub {}: crate::{},", i, s).unwrap();
+                               format!("{}", i)
+                       });
                }
        ) );
        writeln!(w, "\tpub free: Option<extern \"C\" fn(this_arg: *mut c_void)>,").unwrap();
@@ -412,7 +454,7 @@ fn writeln_opaque<W: std::io::Write>(w: &mut W, ident: &syn::Ident, struct_name:
        writeln!(w, "#[allow(unused)]").unwrap();
        writeln!(w, "/// When moving out of the pointer, we have to ensure we aren't a reference, this makes that easy").unwrap();
        writeln!(w, "impl {} {{", struct_name).unwrap();
-       writeln!(w, "\tpub(crate) fn take_ptr(mut self) -> *mut native{} {{", struct_name).unwrap();
+       writeln!(w, "\tpub(crate) fn take_inner(mut self) -> *mut native{} {{", struct_name).unwrap();
        writeln!(w, "\t\tassert!(self.is_owned);").unwrap();
        writeln!(w, "\t\tlet ret = self.inner;").unwrap();
        writeln!(w, "\t\tself.inner = std::ptr::null_mut();").unwrap();
@@ -458,21 +500,28 @@ fn writeln_opaque<W: std::io::Write>(w: &mut W, ident: &syn::Ident, struct_name:
        write_cpp_wrapper(cpp_headers, &format!("{}", ident), true);
 }
 
-/// Writes out all the relevant mappings for a Rust struct, deferring to writeln_opaque to generate
-/// the struct itself, and then writing getters and setters for public, understood-type fields and
-/// a constructor if every field is public.
-fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct, types: &mut TypeResolver<'b, 'a>, extra_headers: &mut File, cpp_headers: &mut File) {
-       let struct_name = &format!("{}", s.ident);
+fn declare_struct<'a, 'b>(s: &'a syn::ItemStruct, types: &mut TypeResolver<'b, 'a>) -> bool {
        let export = export_status(&s.attrs);
        match export {
                ExportStatus::Export => {},
-               ExportStatus::TestOnly => return,
+               ExportStatus::TestOnly => return false,
                ExportStatus::NoExport => {
                        types.struct_ignored(&s.ident);
-                       return;
+                       return false;
                }
        }
 
+       types.struct_imported(&s.ident, format!("{}", s.ident));
+       true
+}
+
+/// Writes out all the relevant mappings for a Rust struct, deferring to writeln_opaque to generate
+/// the struct itself, and then writing getters and setters for public, understood-type fields and
+/// a constructor if every field is public.
+fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct, types: &mut TypeResolver<'b, 'a>, extra_headers: &mut File, cpp_headers: &mut File) {
+       if !declare_struct(s, types) { return; }
+
+       let struct_name = &format!("{}", s.ident);
        writeln_opaque(w, &s.ident, struct_name, &s.generics, &s.attrs, types, extra_headers, cpp_headers);
 
        eprintln!("exporting fields for {}", struct_name);
@@ -556,8 +605,6 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
                        writeln!(w, "\t}})), is_owned: true }}\n}}").unwrap();
                }
        }
-
-       types.struct_imported(&s.ident, struct_name.clone());
 }
 
 /// Prints a relevant conversion for impl *
@@ -670,6 +717,8 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                                                        ("Clone", _) => {
                                                                writeln!(w, "\t\tclone: Some({}_clone_void),", ident).unwrap();
                                                        },
+                                                       ("Sync", _) => {}, ("Send", _) => {},
+                                                       ("std::marker::Sync", _) => {}, ("std::marker::Send", _) => {},
                                                        (s, t) => {
                                                                if let Some(supertrait_obj) = types.crate_types.traits.get(s) {
                                                                        writeln!(w, "\t\t{}: crate::{} {{", t, s).unwrap();
@@ -684,6 +733,8 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                                                                                }
                                                                        }
                                                                        write!(w, "\t\t}},\n").unwrap();
+                                                               } else {
+                                                                       write_trait_impl_field_assign(w, s, ident);
                                                                }
                                                        }
                                                ) );
@@ -870,6 +921,19 @@ fn is_enum_opaque(e: &syn::ItemEnum) -> bool {
        false
 }
 
+fn declare_enum<'a, 'b>(e: &'a syn::ItemEnum, types: &mut TypeResolver<'b, 'a>) {
+       match export_status(&e.attrs) {
+               ExportStatus::Export => {},
+               ExportStatus::NoExport|ExportStatus::TestOnly => return,
+       }
+
+       if is_enum_opaque(e) {
+               types.enum_ignored(&e.ident);
+       } else {
+               types.mirrored_enum_declared(&e.ident);
+       }
+}
+
 /// Print a mapping of an enum. If all of the enum's fields are C-mapped in some form (or the enum
 /// is unitary), we generate an equivalent enum with all types replaced with their C mapped
 /// versions followed by conversion functions which map between the Rust version and the C mapped
@@ -883,7 +947,6 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
        if is_enum_opaque(e) {
                eprintln!("Skipping enum {} as it contains non-unit fields", e.ident);
                writeln_opaque(w, &e.ident, &format!("{}", e.ident), &e.generics, &e.attrs, types, extra_headers, cpp_headers);
-               types.enum_ignored(&e.ident);
                return;
        }
        writeln_docs(w, &e.attrs, "");
@@ -891,7 +954,6 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
        if e.generics.lt_token.is_some() {
                unimplemented!();
        }
-       types.mirrored_enum_declared(&e.ident);
 
        let mut needs_free = false;
 
@@ -1120,9 +1182,27 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &mut CrateTypes
 
        let mut type_resolver = TypeResolver::new(orig_crate, module, crate_types);
 
+       // First pass over the items and fill in imports and file-declared objects in the type resolver
        for item in syntax.items.iter() {
                match item {
                        syn::Item::Use(u) => type_resolver.process_use(&mut out, &u),
+                       syn::Item::Struct(s) => {
+                               if let syn::Visibility::Public(_) = s.vis {
+                                       declare_struct(&s, &mut type_resolver);
+                               }
+                       },
+                       syn::Item::Enum(e) => {
+                               if let syn::Visibility::Public(_) = e.vis {
+                                       declare_enum(&e, &mut type_resolver);
+                               }
+                       },
+                       _ => {},
+               }
+       }
+
+       for item in syntax.items.iter() {
+               match item {
+                       syn::Item::Use(_) => {}, // Handled above
                        syn::Item::Static(_) => {},
                        syn::Item::Enum(e) => {
                                if let syn::Visibility::Public(_) = e.vis {