[bindings] Handle MessageSendEventsProvider impl blocks in a util fn
[rust-lightning] / c-bindings-gen / src / main.rs
index 6c1c8a246b30096df058814bb5965caa38ce0b4c..b04d6b007828f9adc40eef56dae5bca551cc65b9 100644 (file)
@@ -80,6 +80,19 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
        }
 }
 
+/// 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 {
+               "util::events::MessageSendEventsProvider" => {
+                       writeln!(w, "impl lightning::{} for {} {{", trait_path, for_obj).unwrap();
+                       writeln!(w, "\tfn get_and_clear_pending_msg_events(&self) -> Vec<lightning::util::events::MessageSendEvent> {{").unwrap();
+                       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();
+               },
+               _ => panic!(),
+       }
+}
+
 // *******************************
 // *** Per-Type Printing Logic ***
 // *******************************
@@ -92,15 +105,18 @@ macro_rules! walk_supertraits { ($t: expr, $types: expr, ($( $pat: pat => $e: ex
                                        if supertrait.paren_token.is_some() || supertrait.lifetimes.is_some() {
                                                unimplemented!();
                                        }
-                                       if let Some(ident) = supertrait.path.get_ident() {
-                                               match (&format!("{}", ident) as &str, &ident) {
+                                       // First try to resolve path to find in-crate traits, but if that doesn't work
+                                       // assume its a prelude trait (eg Clone, etc) and just use the single ident.
+                                       if let Some(path) = $types.maybe_resolve_path(&supertrait.path, None) {
+                                               match (&path as &str, &supertrait.path.segments.iter().last().unwrap().ident) {
                                                        $( $pat => $e, )*
                                                }
-                                       } else {
-                                               let path = $types.resolve_path(&supertrait.path, None);
-                                               match (&path as &str, &supertrait.path.segments.iter().last().unwrap().ident) {
+                                       } else if let Some(ident) = supertrait.path.get_ident() {
+                                               match (&format!("{}", ident) as &str, &ident) {
                                                        $( $pat => $e, )*
                                                }
+                                       } else {
+                                               panic!("Supertrait unresolvable and not single-ident");
                                        }
                                },
                                syn::TypeParamBound::Lifetime(_) => unimplemented!(),
@@ -248,13 +264,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                        writeln!(w, "\t}}\n}}").unwrap();
                },
                (s, i) => {
-                       if s != "util::events::MessageSendEventsProvider" { unimplemented!(); }
-                       // XXX: We straight-up cheat here - instead of bothering to get the trait object we
-                       // just print what we need since this is only used in one place.
-                       writeln!(w, "impl lightning::{} for {} {{", s, trait_name).unwrap();
-                       writeln!(w, "\tfn get_and_clear_pending_msg_events(&self) -> Vec<lightning::util::events::MessageSendEvent> {{").unwrap();
-                       writeln!(w, "\t\t<crate::{} as lightning::{}>::get_and_clear_pending_msg_events(&self.{})", s, s, i).unwrap();
-                       writeln!(w, "\t}}\n}}").unwrap();
+                       do_write_impl_trait(w, s, i, &trait_name);
                }
        ) );
 
@@ -600,6 +610,21 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                                                        ExportStatus::Export => {},
                                                        ExportStatus::NoExport|ExportStatus::TestOnly => return,
                                                }
+
+                                               // For cases where we have a concrete native object which implements a
+                                               // trait and need to return the C-mapped version of the trait, provide a
+                                               // From<> implementation which does all the work to ensure free is handled
+                                               // properly. This way we can call this method from deep in the
+                                               // type-conversion logic without actually knowing the concrete native type.
+                                               writeln!(w, "impl From<native{}> for crate::{} {{", ident, full_trait_path).unwrap();
+                                               writeln!(w, "\tfn from(obj: native{}) -> Self {{", ident).unwrap();
+                                               writeln!(w, "\t\tlet mut rust_obj = {} {{ inner: Box::into_raw(Box::new(obj)), is_owned: true }};", ident).unwrap();
+                                               writeln!(w, "\t\tlet mut ret = {}_as_{}(&rust_obj);", ident, trait_obj.ident).unwrap();
+                                               writeln!(w, "\t\t// We want to free rust_obj when ret gets drop()'d, not rust_obj, so wipe rust_obj's pointer and set ret's free() fn").unwrap();
+                                               writeln!(w, "\t\trust_obj.inner = std::ptr::null_mut();").unwrap();
+                                               writeln!(w, "\t\tret.free = Some({}_free_void);", ident).unwrap();
+                                               writeln!(w, "\t\tret\n\t}}\n}}").unwrap();
+
                                                write!(w, "#[no_mangle]\npub extern \"C\" fn {}_as_{}(this_arg: *const {}) -> crate::{} {{\n", ident, trait_obj.ident, ident, full_trait_path).unwrap();
                                                writeln!(w, "\tcrate::{} {{", full_trait_path).unwrap();
                                                writeln!(w, "\t\tthis_arg: unsafe {{ (*this_arg).inner as *mut c_void }},").unwrap();
@@ -646,8 +671,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                                                                writeln!(w, "\t\tclone: Some({}_clone_void),", ident).unwrap();
                                                        },
                                                        (s, t) => {
-                                                               if s.starts_with("util::") {
-                                                                       let supertrait_obj = types.crate_types.traits.get(s).unwrap();
+                                                               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 {{ (*this_arg).inner as *mut c_void }},").unwrap();
                                                                        writeln!(w, "\t\t\tfree: None,").unwrap();
@@ -738,9 +762,8 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                                                }
                                                walk_supertraits!(trait_obj, types, (
                                                        (s, t) => {
-                                                               if s.starts_with("util::") {
+                                                               if let Some(supertrait_obj) = types.crate_types.traits.get(s).cloned() {
                                                                        writeln!(w, "use {}::{} as native{}Trait;", types.orig_crate, s, t).unwrap();
-                                                                       let supertrait_obj = *types.crate_types.traits.get(s).unwrap();
                                                                        for item in supertrait_obj.items.iter() {
                                                                                match item {
                                                                                        syn::TraitItem::Method(m) => {