[bindings] Support exposing `bitcoin::OutPoint`s as our common type
[rust-lightning] / c-bindings-gen / src / types.rs
index ef4bbb1740ff14a145df5f0a3d4a3a54cc49679a..e85729481a39841daf9a6159b3bd51c26e02e818 100644 (file)
@@ -401,10 +401,9 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "bitcoin::secp256k1::Error" if !is_ref => Some("crate::c_types::Secp256k1Error"),
                        "bitcoin::blockdata::script::Script" if is_ref => Some("crate::c_types::u8slice"),
                        "bitcoin::blockdata::script::Script" if !is_ref => Some("crate::c_types::derived::CVec_u8Z"),
-                       "bitcoin::blockdata::transaction::OutPoint" if is_ref => Some("crate::chain::transaction::OutPoint"),
+                       "bitcoin::blockdata::transaction::OutPoint" => Some("crate::chain::transaction::OutPoint"),
                        "bitcoin::blockdata::transaction::Transaction" => Some("crate::c_types::Transaction"),
                        "bitcoin::blockdata::transaction::TxOut" if !is_ref => Some("crate::c_types::TxOut"),
-                       "bitcoin::OutPoint" => Some("crate::chain::transaction::OutPoint"),
                        "bitcoin::network::constants::Network" => Some("crate::bitcoin::network::Network"),
                        "bitcoin::blockdata::block::BlockHeader" if is_ref  => Some("*const [u8; 80]"),
                        "bitcoin::blockdata::block::Block" if is_ref  => Some("crate::c_types::u8slice"),
@@ -414,6 +413,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "bitcoin::hash_types::Txid" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),
                        "bitcoin::hash_types::BlockHash" if is_ref  => Some("*const [u8; 32]"),
                        "bitcoin::hash_types::BlockHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),
+                       "bitcoin::secp256k1::Message" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),
                        "ln::channelmanager::PaymentHash" if is_ref => Some("*const [u8; 32]"),
                        "ln::channelmanager::PaymentHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),
                        "ln::channelmanager::PaymentPreimage" if is_ref => Some("*const [u8; 32]"),
@@ -614,6 +614,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "bitcoin::blockdata::script::Script" if is_ref => Some("crate::c_types::u8slice::from_slice(&"),
                        "bitcoin::blockdata::script::Script" if !is_ref => Some(""),
                        "bitcoin::blockdata::transaction::Transaction" => Some("crate::c_types::Transaction::from_vec(local_"),
+                       "bitcoin::blockdata::transaction::OutPoint" => Some("crate::c_types::bitcoin_to_C_outpoint("),
                        "bitcoin::blockdata::transaction::TxOut" if !is_ref => Some("crate::c_types::TxOut::from_rust("),
                        "bitcoin::blockdata::block::BlockHeader" if is_ref => Some("&local_"),
                        "bitcoin::blockdata::block::Block" if is_ref => Some("crate::c_types::u8slice::from_slice(&local_"),
@@ -624,6 +625,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "bitcoin::hash_types::Txid" if is_ref => Some(""),
                        "bitcoin::hash_types::BlockHash" if is_ref => Some(""),
                        "bitcoin::hash_types::BlockHash" => Some("crate::c_types::ThirtyTwoBytes { data: "),
+                       "bitcoin::secp256k1::Message" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "),
                        "ln::channelmanager::PaymentHash" if is_ref => Some("&"),
                        "ln::channelmanager::PaymentHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "),
                        "ln::channelmanager::PaymentPreimage" if is_ref => Some("&"),
@@ -677,6 +679,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "bitcoin::blockdata::script::Script" if is_ref => Some("[..])"),
                        "bitcoin::blockdata::script::Script" if !is_ref => Some(".into_bytes().into()"),
                        "bitcoin::blockdata::transaction::Transaction" => Some(")"),
+                       "bitcoin::blockdata::transaction::OutPoint" => Some(")"),
                        "bitcoin::blockdata::transaction::TxOut" if !is_ref => Some(")"),
                        "bitcoin::blockdata::block::BlockHeader" if is_ref => Some(""),
                        "bitcoin::blockdata::block::Block" if is_ref => Some(")"),
@@ -687,6 +690,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "bitcoin::hash_types::Txid" if is_ref => Some(".as_inner()"),
                        "bitcoin::hash_types::BlockHash" if is_ref => Some(".as_inner()"),
                        "bitcoin::hash_types::BlockHash" => Some(".into_inner() }"),
+                       "bitcoin::secp256k1::Message" if !is_ref => Some(".as_ref().clone() }"),
                        "ln::channelmanager::PaymentHash" if is_ref => Some(".0"),
                        "ln::channelmanager::PaymentHash" => Some(".0 }"),
                        "ln::channelmanager::PaymentPreimage" if is_ref => Some(".0"),
@@ -1250,17 +1254,16 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                        decl_lookup(w, &DeclType::StructImported, &resolved_path, is_ref, is_mut);
                                } else if self.crate_types.mirrored_enums.get(&resolved_path).is_some() {
                                        decl_lookup(w, &DeclType::MirroredEnum, &resolved_path, is_ref, is_mut);
+                               } else if let Some(t) = self.crate_types.traits.get(&resolved_path) {
+                                       decl_lookup(w, &DeclType::Trait(t), &resolved_path, is_ref, is_mut);
                                } else if let Some(ident) = single_ident_generic_path_to_ident(&p.path) {
-                                       if let Some(t) = self.crate_types.traits.get(&resolved_path) {
-                                               decl_lookup(w, &DeclType::Trait(t), &resolved_path, is_ref, is_mut);
-                                               return;
-                                       } else if let Some(_) = self.imports.get(ident) {
+                                       if let Some(_) = self.imports.get(ident) {
                                                // crate_types lookup has to have succeeded:
                                                panic!("Failed to print inline conversion for {}", ident);
                                        } else if let Some(decl_type) = self.declared.get(ident) {
                                                decl_lookup(w, decl_type, &self.maybe_resolve_ident(ident).unwrap(), is_ref, is_mut);
                                        } else { unimplemented!(); }
-                               }
+                               } else { unimplemented!(); }
                        },
                        syn::Type::Array(a) => {
                                // We assume all arrays contain only [int_literal; X]s.
@@ -1343,6 +1346,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                DeclType::EnumIgnored|DeclType::StructImported if !is_ref =>
                                                        write!(w, "crate::{} {{ inner: Box::into_raw(Box::new(", decl_path).unwrap(),
                                                DeclType::Trait(_) if is_ref => write!(w, "&").unwrap(),
+                                               DeclType::Trait(_) if !is_ref => {},
                                                _ => panic!("{:?}", decl_path),
                                        }
                                });
@@ -1365,6 +1369,13 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                write!(w, ", is_owned: true }}").unwrap(),
                                        DeclType::EnumIgnored|DeclType::StructImported if !is_ref => write!(w, ")), is_owned: true }}").unwrap(),
                                        DeclType::Trait(_) if is_ref => {},
+                                       DeclType::Trait(_) => {
+                                               // This is used when we're converting a concrete Rust type into a C trait
+                                               // for use when a Rust trait method returns an associated type.
+                                               // Because all of our C traits implement From<RustTypesImplementingTraits>
+                                               // we can just call .into() here and be done.
+                                               write!(w, ".into()").unwrap()
+                                       },
                                        _ => unimplemented!(),
                                });
        }
@@ -1727,14 +1738,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                        self.write_c_mangled_container_path_intern(w, Self::path_to_generic_args(path), generics,
                                                                &format!("{}", single_ident_generic_path_to_ident(path).unwrap()), is_ref, false, false, false);
                                                } else {
-                                                       self.write_template_generics(w, &mut [$item].iter().map(|t| *t), is_ref, true);
+                                                       self.write_template_generics(w, &mut [$item].iter().map(|t| *t), generics, is_ref, true);
                                                }
                                        } else if let syn::Type::Tuple(syn::TypeTuple { elems, .. }) = $item {
                                                self.write_c_mangled_container_path_intern(w, elems.iter().collect(), generics,
                                                        &format!("{}Tuple", elems.len()), is_ref, false, false, false);
                                        } else { unimplemented!(); }
                                        write!(w, ") -> {} =\n\t{}::CResultTempl::<", mangled_container, Self::container_templ_path()).unwrap();
-                                       self.write_template_generics(w, &mut args.iter().map(|t| *t), is_ref, true);
+                                       self.write_template_generics(w, &mut args.iter().map(|t| *t), generics, is_ref, true);
                                        writeln!(w, ">::{};\n", $call).unwrap();
                                } }
                        }
@@ -1763,7 +1774,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                }
        }
 
-       fn write_template_generics<'b, W: std::io::Write>(&self, w: &mut W, args: &mut dyn Iterator<Item=&'b syn::Type>, is_ref: bool, in_crate: bool) {
+       fn write_template_generics<'b, W: std::io::Write>(&self, w: &mut W, args: &mut dyn Iterator<Item=&'b syn::Type>, generics: Option<&GenericTypes>, is_ref: bool, in_crate: bool) {
                for (idx, t) in args.enumerate() {
                        if idx != 0 {
                                write!(w, ", ").unwrap();
@@ -1773,11 +1784,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                        write!(w, "u8").unwrap();
                                } else {
                                        write!(w, "{}::C{}TupleTempl<", Self::container_templ_path(), tup.elems.len()).unwrap();
-                                       self.write_template_generics(w, &mut tup.elems.iter(), is_ref, in_crate);
+                                       self.write_template_generics(w, &mut tup.elems.iter(), generics, is_ref, in_crate);
                                        write!(w, ">").unwrap();
                                }
                        } else if let syn::Type::Path(p_arg) = t {
-                               let resolved_generic = self.resolve_path(&p_arg.path, None);
+                               let resolved_generic = self.resolve_path(&p_arg.path, generics);
                                if self.is_primitive(&resolved_generic) {
                                        write!(w, "{}", resolved_generic).unwrap();
                                } else if let Some(c_type) = self.c_type_from_path(&resolved_generic, is_ref, false) {
@@ -1787,19 +1798,19 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                if let syn::PathArguments::AngleBracketed(args) = &p_arg.path.segments.iter().next().unwrap().arguments {
                                                        self.write_template_generics(w, &mut args.args.iter().map(|gen|
                                                                if let syn::GenericArgument::Type(t) = gen { t } else { unimplemented!() }),
-                                                               is_ref, in_crate);
+                                                               generics, is_ref, in_crate);
                                                } else { unimplemented!(); }
                                                write!(w, ">").unwrap();
                                        } else if resolved_generic == "Option" {
                                                if let syn::PathArguments::AngleBracketed(args) = &p_arg.path.segments.iter().next().unwrap().arguments {
                                                        self.write_template_generics(w, &mut args.args.iter().map(|gen|
                                                                if let syn::GenericArgument::Type(t) = gen { t } else { unimplemented!() }),
-                                                               is_ref, in_crate);
+                                                               generics, is_ref, in_crate);
                                                } else { unimplemented!(); }
                                        } else if in_crate {
                                                write!(w, "{}", c_type).unwrap();
                                        } else {
-                                               self.write_rust_type(w, None, &t);
+                                               self.write_rust_type(w, generics, &t);
                                        }
                                } else {
                                        // If we just write out resolved_generic, it may mostly work, however for
@@ -1819,7 +1830,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                }
                        } else if let syn::Type::Reference(r_arg) = t {
                                if let syn::Type::Path(p_arg) = &*r_arg.elem {
-                                       let resolved = self.resolve_path(&p_arg.path, None);
+                                       let resolved = self.resolve_path(&p_arg.path, generics);
                                        if self.crate_types.opaques.get(&resolved).is_some() {
                                                write!(w, "crate::{}", resolved).unwrap();
                                        } else {
@@ -1829,7 +1840,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                } else { unimplemented!(); }
                        } else if let syn::Type::Array(a_arg) = t {
                                if let syn::Type::Path(p_arg) = &*a_arg.elem {
-                                       let resolved = self.resolve_path(&p_arg.path, None);
+                                       let resolved = self.resolve_path(&p_arg.path, generics);
                                        assert!(self.is_primitive(&resolved));
                                        if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(len), .. }) = &a_arg.len {
                                                write!(w, "{}",
@@ -1846,12 +1857,12 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
 
                        write!(&mut created_container, "#[no_mangle]\npub type {} = ", mangled_container).unwrap();
                        write!(&mut created_container, "{}::C{}Templ<", Self::container_templ_path(), container_type).unwrap();
-                       self.write_template_generics(&mut created_container, &mut args.iter().map(|t| *t), is_ref, true);
+                       self.write_template_generics(&mut created_container, &mut args.iter().map(|t| *t), generics, is_ref, true);
                        writeln!(&mut created_container, ">;").unwrap();
 
                        write!(&mut created_container, "#[no_mangle]\npub static {}_free: extern \"C\" fn({}) = ", mangled_container, mangled_container).unwrap();
                        write!(&mut created_container, "{}::C{}Templ_free::<", Self::container_templ_path(), container_type).unwrap();
-                       self.write_template_generics(&mut created_container, &mut args.iter().map(|t| *t), is_ref, true);
+                       self.write_template_generics(&mut created_container, &mut args.iter().map(|t| *t), generics, is_ref, true);
                        writeln!(&mut created_container, ">;").unwrap();
 
                        self.write_template_constructor(&mut created_container, container_type, &mangled_container, &args, generics, is_ref);