Move top-level crate inside a pub module in prep for multi-crate bindings
authorMatt Corallo <git@bluematt.me>
Mon, 12 Apr 2021 21:37:55 +0000 (17:37 -0400)
committerMatt Corallo <git@bluematt.me>
Thu, 15 Apr 2021 22:01:27 +0000 (18:01 -0400)
This wraps the lightning crate inside a `pub mod lightning` wrapper
in genbindings.sh, and modifies the binding generator to handle it.

It ends up removing some code in the main TypeResolver, at the cost
of some extra handling of imports in the ImportResolver, which
focuses the amount of code that needs to be aware of the top-level
crate name down to a much smaller area. This preps us for creating
bindings for multiple crates at once.

c-bindings-gen/src/main.rs
c-bindings-gen/src/types.rs
genbindings.sh

index f0c5db39982a7101cf82a459c07dbf8053d1f751..0d002bbbeb40421598b34add308071dc7afe6532 100644 (file)
@@ -58,7 +58,7 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
                }
 
                match &t as &str {
-                       "util::ser::Writeable" => {
+                       "lightning::util::ser::Writeable" => {
                                writeln!(w, "#[no_mangle]").unwrap();
                                writeln!(w, "/// Serialize the {} object into a byte array which can be read by {}_read", for_obj, for_obj).unwrap();
                                writeln!(w, "pub extern \"C\" fn {}_write(obj: &{}) -> crate::c_types::derived::CVec_u8Z {{", for_obj, full_obj_path).unwrap();
@@ -82,7 +82,7 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
                                        writeln!(w, "}}").unwrap();
                                }
                        },
-                       "util::ser::Readable"|"util::ser::ReadableArgs" => {
+                       "lightning::util::ser::Readable"|"lightning::util::ser::ReadableArgs" => {
                                // Create the Result<Object, DecodeError> syn::Type
                                let mut err_segs = syn::punctuated::Punctuated::new();
                                err_segs.push(syn::PathSegment { ident: syn::Ident::new("ln", Span::call_site()), arguments: syn::PathArguments::None });
@@ -110,7 +110,7 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
                                write!(w, "pub extern \"C\" fn {}_read(ser: crate::c_types::u8slice", for_obj).unwrap();
 
                                let mut arg_conv = Vec::new();
-                               if t == "util::ser::ReadableArgs" {
+                               if t == "lightning::util::ser::ReadableArgs" {
                                        write!(w, ", arg: ").unwrap();
                                        assert!(trait_path.leading_colon.is_none());
                                        let args_seg = trait_path.segments.iter().last().unwrap();
@@ -133,7 +133,7 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
                                types.write_c_type(w, &res_ty, Some(generics), false);
                                writeln!(w, " {{").unwrap();
 
-                               if t == "util::ser::ReadableArgs" {
+                               if t == "lightning::util::ser::ReadableArgs" {
                                        w.write(&arg_conv).unwrap();
                                        write!(w, ";\n\tlet res: ").unwrap();
                                        // At least in one case we need type annotations here, so provide them.
@@ -162,7 +162,7 @@ fn maybe_convert_trait_impl<W: std::io::Write>(w: &mut W, trait_path: &syn::Path
 /// single function (eg for serialization).
 fn convert_trait_impl_field(trait_path: &str) -> (&'static str, String, &'static str) {
        match trait_path {
-               "util::ser::Writeable" => ("Serialize the object into a byte array", "write".to_owned(), "crate::c_types::derived::CVec_u8Z"),
+               "lightning::util::ser::Writeable" => ("Serialize the object into a byte array", "write".to_owned(), "crate::c_types::derived::CVec_u8Z"),
                _ => unimplemented!(),
        }
 }
@@ -171,7 +171,7 @@ fn convert_trait_impl_field(trait_path: &str) -> (&'static str, String, &'static
 /// `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" => {
+               "lightning::util::ser::Writeable" => {
                        writeln!(w, "\t\twrite: {}_write_void,", for_obj).unwrap();
                },
                _ => unimplemented!(),
@@ -182,8 +182,8 @@ fn write_trait_impl_field_assign<W: std::io::Write>(w: &mut W, trait_path: &str,
 fn do_write_impl_trait<W: std::io::Write>(w: &mut W, trait_path: &str, _trait_name: &syn::Ident, for_obj: &str) {
 eprintln!("{}", trait_path);
        match trait_path {
-               "util::ser::Writeable" => {
-                       writeln!(w, "impl lightning::{} for {} {{", trait_path, for_obj).unwrap();
+               "lightning::util::ser::Writeable" => {
+                       writeln!(w, "impl {} 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();
@@ -503,9 +503,10 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                                let mut module_iter = s.rsplitn(2, "::");
                                module_iter.next().unwrap();
                                let supertrait_module = module_iter.next().unwrap();
-                               let imports = ImportResolver::new(supertrait_module, &types.crate_types.lib_ast.modules.get(supertrait_module).unwrap().items);
-                               let resolver = TypeResolver::new("lightning", &supertrait_module, imports, types.crate_types); // TODO: Drop hard-coded crate name here
-                               writeln!(w, "impl lightning::{} for {} {{", s, trait_name).unwrap(); // TODO: Drop hard-coded crate name here
+                               let imports = ImportResolver::new(supertrait_module.splitn(2, "::").next().unwrap(), &types.crate_types.lib_ast.dependencies,
+                                       supertrait_module, &types.crate_types.lib_ast.modules.get(supertrait_module).unwrap().items);
+                               let resolver = TypeResolver::new(&supertrait_module, imports, types.crate_types);
+                               writeln!(w, "impl {} for {} {{", s, trait_name).unwrap();
                                impl_trait_for_c!(supertrait, format!(".{}", i), &resolver);
                                writeln!(w, "}}").unwrap();
                                walk_supertraits!(supertrait, Some(&types), (
@@ -520,7 +521,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
        ) );
 
        // Finally, implement the original Rust trait for the newly created mapped trait.
-       writeln!(w, "\nuse {}::{}::{} as rust{};", types.orig_crate, types.module_path, t.ident, trait_name).unwrap();
+       writeln!(w, "\nuse {}::{} as rust{};", types.module_path, t.ident, trait_name).unwrap();
        write!(w, "impl rust{}", t.ident).unwrap();
        maybe_write_generics(w, &t.generics, types, false);
        writeln!(w, " for {} {{", trait_name).unwrap();
@@ -550,7 +551,7 @@ fn writeln_opaque<W: std::io::Write>(w: &mut W, ident: &syn::Ident, struct_name:
        // If we directly read the original type by its original name, cbindgen hits
        // https://github.com/eqrion/cbindgen/issues/286 Thus, instead, we import it as a temporary
        // name and then reference it by that name, which works around the issue.
-       write!(w, "\nuse {}::{}::{} as native{}Import;\ntype native{} = native{}Import", types.orig_crate, types.module_path, ident, ident, ident, ident).unwrap();
+       write!(w, "\nuse {}::{} as native{}Import;\ntype native{} = native{}Import", types.module_path, ident, ident, ident, ident).unwrap();
        maybe_write_generics(w, &generics, &types, true);
        writeln!(w, ";\n").unwrap();
        writeln!(extra_headers, "struct native{}Opaque;\ntypedef struct native{}Opaque LDKnative{};", ident, ident, ident).unwrap();
@@ -884,9 +885,9 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                                                                        t_gen_args += "_"
                                                                }
                                                                if takes_self {
-                                                                       write!(w, "<native{} as {}::{}<{}>>::{}(unsafe {{ &mut *(this_arg as *mut native{}) }}, ", ident, types.orig_crate, $trait_path, t_gen_args, $m.sig.ident, ident).unwrap();
+                                                                       write!(w, "<native{} as {}<{}>>::{}(unsafe {{ &mut *(this_arg as *mut native{}) }}, ", ident, $trait_path, t_gen_args, $m.sig.ident, ident).unwrap();
                                                                } else {
-                                                                       write!(w, "<native{} as {}::{}<{}>>::{}(", ident, types.orig_crate, $trait_path, t_gen_args, $m.sig.ident).unwrap();
+                                                                       write!(w, "<native{} as {}<{}>>::{}(", ident, $trait_path, t_gen_args, $m.sig.ident).unwrap();
                                                                }
 
                                                                let mut real_type = "".to_string();
@@ -1020,7 +1021,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                                                                        } else if takes_self {
                                                                                write!(w, "unsafe {{ &*this_arg.inner }}.{}(", m.sig.ident).unwrap();
                                                                        } else {
-                                                                               write!(w, "{}::{}::{}(", types.orig_crate, resolved_path, m.sig.ident).unwrap();
+                                                                               write!(w, "{}::{}(", resolved_path, m.sig.ident).unwrap();
                                                                        }
                                                                        write_method_call_params(w, &m.sig, "", types, Some(&meth_gen_types), &ret_type, false);
                                                                        writeln!(w, "\n}}\n").unwrap();
@@ -1146,7 +1147,7 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                if var.discriminant.is_some() { unimplemented!(); }
                writeln!(w, ",").unwrap();
        }
-       writeln!(w, "}}\nuse {}::{}::{} as native{};\nimpl {} {{", types.orig_crate, types.module_path, e.ident, e.ident, e.ident).unwrap();
+       writeln!(w, "}}\nuse {}::{} as native{};\nimpl {} {{", types.module_path, e.ident, e.ident, e.ident).unwrap();
 
        macro_rules! write_conv {
                ($fn_sig: expr, $to_c: expr, $ref: expr) => {
@@ -1287,7 +1288,7 @@ fn writeln_fn<'a, 'b, W: std::io::Write>(w: &mut W, f: &'a syn::ItemFn, types: &
        write_method_params(w, &f.sig, "", types, Some(&gen_types), false, true);
        write!(w, " {{\n\t").unwrap();
        write_method_var_decl_body(w, &f.sig, "", types, Some(&gen_types), false);
-       write!(w, "{}::{}::{}(", types.orig_crate, types.module_path, f.sig.ident).unwrap();
+       write!(w, "{}::{}(", types.module_path, f.sig.ident).unwrap();
        write_method_call_params(w, &f.sig, "", types, Some(&gen_types), "", false);
        writeln!(w, "\n}}\n").unwrap();
 }
@@ -1329,6 +1330,7 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a>
                if module == "" {
                        // Special-case the top-level lib.rs with various lint allows and a pointer to the c_types
                        // and bitcoin hand-written modules.
+                       writeln!(out, "//! C Bindings").unwrap();
                        writeln!(out, "#![allow(unknown_lints)]").unwrap();
                        writeln!(out, "#![allow(non_camel_case_types)]").unwrap();
                        writeln!(out, "#![allow(non_snake_case)]").unwrap();
@@ -1351,8 +1353,8 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a>
 
                eprintln!("Converting {} entries...", module);
 
-               let import_resolver = ImportResolver::new(module, items);
-               let mut type_resolver = TypeResolver::new(orig_crate, module, import_resolver, crate_types);
+               let import_resolver = ImportResolver::new(orig_crate, &libast.dependencies, module, items);
+               let mut type_resolver = TypeResolver::new(module, import_resolver, crate_types);
 
                for item in items.iter() {
                        match item {
@@ -1385,7 +1387,7 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a>
                                                        if type_resolver.is_primitive(&resolved_path) {
                                                                writeln_docs(&mut out, &c.attrs, "");
                                                                writeln!(out, "\n#[no_mangle]").unwrap();
-                                                               writeln!(out, "pub static {}: {} = {}::{}::{};", c.ident, resolved_path, orig_crate, module, c.ident).unwrap();
+                                                               writeln!(out, "pub static {}: {} = {}::{};", c.ident, resolved_path, module, c.ident).unwrap();
                                                        }
                                                }
                                        }
@@ -1427,11 +1429,11 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a>
        }
 }
 
-fn walk_private_mod<'a>(module: String, items: &'a syn::ItemMod, crate_types: &mut CrateTypes<'a>) {
-       let import_resolver = ImportResolver::new(&module, &items.content.as_ref().unwrap().1);
+fn walk_private_mod<'a>(ast_storage: &'a FullLibraryAST, orig_crate: &str, module: String, items: &'a syn::ItemMod, crate_types: &mut CrateTypes<'a>) {
+       let import_resolver = ImportResolver::new(orig_crate, &ast_storage.dependencies, &module, &items.content.as_ref().unwrap().1);
        for item in items.content.as_ref().unwrap().1.iter() {
                match item {
-                       syn::Item::Mod(m) => walk_private_mod(format!("{}::{}", module, m.ident), m, crate_types),
+                       syn::Item::Mod(m) => walk_private_mod(ast_storage, orig_crate, format!("{}::{}", module, m.ident), m, crate_types),
                        syn::Item::Impl(i) => {
                                if let &syn::Type::Path(ref p) = &*i.self_ty {
                                        if let Some(trait_path) = i.trait_.as_ref() {
@@ -1452,11 +1454,11 @@ fn walk_private_mod<'a>(module: String, items: &'a syn::ItemMod, crate_types: &m
 }
 
 /// Walk the FullLibraryAST, deciding how things will be mapped and adding tracking to CrateTypes.
-fn walk_ast<'a>(ast_storage: &'a FullLibraryAST, crate_types: &mut CrateTypes<'a>) {
+fn walk_ast<'a>(ast_storage: &'a FullLibraryAST, orig_crate: &str, crate_types: &mut CrateTypes<'a>) {
        for (module, astmod) in ast_storage.modules.iter() {
                let ASTModule { ref attrs, ref items, submods: _ } = astmod;
                assert_eq!(export_status(&attrs), ExportStatus::Export);
-               let import_resolver = ImportResolver::new(module, items);
+               let import_resolver = ImportResolver::new(orig_crate, &ast_storage.dependencies, module, items);
 
                for item in items.iter() {
                        match item {
@@ -1562,7 +1564,7 @@ fn walk_ast<'a>(ast_storage: &'a FullLibraryAST, crate_types: &mut CrateTypes<'a
                                                }
                                        }
                                },
-                               syn::Item::Mod(m) => walk_private_mod(format!("{}::{}", module, m.ident), m, crate_types),
+                               syn::Item::Mod(m) => walk_private_mod(ast_storage, orig_crate, format!("{}::{}", module, m.ident), m, crate_types),
                                _ => {},
                        }
                }
@@ -1607,7 +1609,7 @@ fn main() {
        // ...then walk the ASTs tracking what types we will map, and how, so that we can resolve them
        // when parsing other file ASTs...
        let mut libtypes = CrateTypes::new(&mut derived_templates, &libast);
-       walk_ast(&libast, &mut libtypes);
+       walk_ast(&libast, &args[2], &mut libtypes);
 
        // ... finally, do the actual file conversion/mapping, writing out types as we go.
        convert_file(&libast, &libtypes, &args[1], &args[2], &mut header_file, &mut cpp_header_file);
index acfcc1d8a8c26c0b85a3493ae1c82646733fe38b..edd993f9be137fa45d752dc51d01ba6538fc30eb 100644 (file)
@@ -321,33 +321,46 @@ pub enum DeclType<'a> {
 }
 
 pub struct ImportResolver<'mod_lifetime, 'crate_lft: 'mod_lifetime> {
+       crate_name: &'mod_lifetime str,
+       dependencies: &'mod_lifetime HashSet<syn::Ident>,
        module_path: &'mod_lifetime str,
        imports: HashMap<syn::Ident, (String, syn::Path)>,
        declared: HashMap<syn::Ident, DeclType<'crate_lft>>,
        priv_modules: HashSet<syn::Ident>,
 }
 impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'crate_lft> {
-       fn process_use_intern(imports: &mut HashMap<syn::Ident, (String, syn::Path)>, u: &syn::UseTree, partial_path: &str, mut path: syn::punctuated::Punctuated<syn::PathSegment, syn::token::Colon2>) {
+       fn process_use_intern(crate_name: &str, dependencies: &HashSet<syn::Ident>, imports: &mut HashMap<syn::Ident, (String, syn::Path)>,
+                       u: &syn::UseTree, partial_path: &str, mut path: syn::punctuated::Punctuated<syn::PathSegment, syn::token::Colon2>) {
+
+               let new_path;
+               macro_rules! push_path {
+                       ($ident: expr, $path_suffix: expr) => {
+                               if partial_path == "" && !dependencies.contains(&$ident) {
+                                       new_path = format!("{}::{}{}", crate_name, $ident, $path_suffix);
+                                       path.push(syn::PathSegment { ident: syn::Ident::new(crate_name, Span::call_site()), arguments: syn::PathArguments::None });
+                               } else {
+                                       new_path = format!("{}{}{}", partial_path, $ident, $path_suffix);
+                               }
+                               path.push(syn::PathSegment { ident: $ident.clone(), arguments: syn::PathArguments::None });
+                       }
+               }
                match u {
                        syn::UseTree::Path(p) => {
-                               let new_path = format!("{}{}::", partial_path, p.ident);
-                               path.push(syn::PathSegment { ident: p.ident.clone(), arguments: syn::PathArguments::None });
-                               Self::process_use_intern(imports, &p.tree, &new_path, path);
+                               push_path!(p.ident, "::");
+                               Self::process_use_intern(crate_name, dependencies, imports, &p.tree, &new_path, path);
                        },
                        syn::UseTree::Name(n) => {
-                               let full_path = format!("{}{}", partial_path, n.ident);
-                               path.push(syn::PathSegment { ident: n.ident.clone(), arguments: syn::PathArguments::None });
-                               imports.insert(n.ident.clone(), (full_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path }));
+                               push_path!(n.ident, "");
+                               imports.insert(n.ident.clone(), (new_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path }));
                        },
                        syn::UseTree::Group(g) => {
                                for i in g.items.iter() {
-                                       Self::process_use_intern(imports, i, partial_path, path.clone());
+                                       Self::process_use_intern(crate_name, dependencies, imports, i, partial_path, path.clone());
                                }
                        },
                        syn::UseTree::Rename(r) => {
-                               let full_path = format!("{}{}", partial_path, r.ident);
-                               path.push(syn::PathSegment { ident: r.ident.clone(), arguments: syn::PathArguments::None });
-                               imports.insert(r.rename.clone(), (full_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path }));
+                               push_path!(r.ident, "");
+                               imports.insert(r.rename.clone(), (new_path, syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path }));
                        },
                        syn::UseTree::Glob(_) => {
                                eprintln!("Ignoring * use for {} - this may result in resolution failures", partial_path);
@@ -355,24 +368,24 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                }
        }
 
-       fn process_use(imports: &mut HashMap<syn::Ident, (String, syn::Path)>, u: &syn::ItemUse) {
+       fn process_use(crate_name: &str, dependencies: &HashSet<syn::Ident>, imports: &mut HashMap<syn::Ident, (String, syn::Path)>, u: &syn::ItemUse) {
                if let syn::Visibility::Public(_) = u.vis {
                        // We actually only use these for #[cfg(fuzztarget)]
                        eprintln!("Ignoring pub(use) tree!");
                        return;
                }
                if u.leading_colon.is_some() { eprintln!("Ignoring leading-colon use!"); return; }
-               Self::process_use_intern(imports, &u.tree, "", syn::punctuated::Punctuated::new());
+               Self::process_use_intern(crate_name, dependencies, imports, &u.tree, "", syn::punctuated::Punctuated::new());
        }
 
        fn insert_primitive(imports: &mut HashMap<syn::Ident, (String, syn::Path)>, id: &str) {
                let ident = syn::Ident::new(id, Span::call_site());
                let mut path = syn::punctuated::Punctuated::new();
                path.push(syn::PathSegment { ident: ident.clone(), arguments: syn::PathArguments::None });
-               imports.insert(ident, (id.to_owned(), syn::Path { leading_colon: Some(syn::Token![::](Span::call_site())), segments: path }));
+               imports.insert(ident, (id.to_owned(), syn::Path { leading_colon: None, segments: path }));
        }
 
-       pub fn new(module_path: &'mod_lifetime str, contents: &'crate_lft [syn::Item]) -> Self {
+       pub fn new(crate_name: &'mod_lifetime str, dependencies: &'mod_lifetime HashSet<syn::Ident>, module_path: &'mod_lifetime str, contents: &'crate_lft [syn::Item]) -> Self {
                let mut imports = HashMap::new();
                // Add primitives to the "imports" list:
                Self::insert_primitive(&mut imports, "bool");
@@ -395,7 +408,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
 
                for item in contents.iter() {
                        match item {
-                               syn::Item::Use(u) => Self::process_use(&mut imports, &u),
+                               syn::Item::Use(u) => Self::process_use(crate_name, dependencies, &mut imports, &u),
                                syn::Item::Struct(s) => {
                                        if let syn::Visibility::Public(_) = s.vis {
                                                match export_status(&s.attrs) {
@@ -438,7 +451,7 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                        }
                }
 
-               Self { module_path, imports, declared, priv_modules }
+               Self { crate_name, dependencies, module_path, imports, declared, priv_modules }
        }
 
        pub fn get_declared_type(&self, ident: &syn::Ident) -> Option<&DeclType<'crate_lft>> {
@@ -476,9 +489,14 @@ impl<'mod_lifetime, 'crate_lft: 'mod_lifetime> ImportResolver<'mod_lifetime, 'cr
                } else { p_arg };
 
                if p.leading_colon.is_some() {
-                       Some(p.segments.iter().enumerate().map(|(idx, seg)| {
+                       let mut res: String = p.segments.iter().enumerate().map(|(idx, seg)| {
                                format!("{}{}", if idx == 0 { "" } else { "::" }, seg.ident)
-                       }).collect())
+                       }).collect();
+                       let firstseg = p.segments.iter().next().unwrap();
+                       if !self.dependencies.contains(&firstseg.ident) {
+                               res = self.crate_name.to_owned() + "::" + &res;
+                       }
+                       Some(res)
                } else if let Some(id) = p.get_ident() {
                        self.maybe_resolve_ident(id)
                } else {
@@ -555,6 +573,7 @@ pub struct ASTModule {
 /// A struct containing the syn::File AST for each file in the crate.
 pub struct FullLibraryAST {
        pub modules: HashMap<String, ASTModule, NonRandomHash>,
+       pub dependencies: HashSet<syn::Ident>,
 }
 impl FullLibraryAST {
        fn load_module(&mut self, module: String, attrs: Vec<syn::Attribute>, mut items: Vec<syn::Item>) {
@@ -579,6 +598,11 @@ impl FullLibraryAST {
                                        }
                                },
                                syn::Item::Mod(_) => panic!("--pretty=expanded output should never have non-body modules"),
+                               syn::Item::ExternCrate(c) => {
+                                       if export_status(&c.attrs) == ExportStatus::Export {
+                                               self.dependencies.insert(c.ident);
+                                       }
+                               },
                                _ => { non_mod_items.push(item); }
                        }
                }
@@ -587,7 +611,7 @@ impl FullLibraryAST {
 
        pub fn load_lib(lib: syn::File) -> Self {
                assert_eq!(export_status(&lib.attrs), ExportStatus::Export);
-               let mut res = Self { modules: HashMap::default() };
+               let mut res = Self { modules: HashMap::default(), dependencies: HashSet::new() };
                res.load_module("".to_owned(), lib.attrs, lib.items);
                res
        }
@@ -647,7 +671,6 @@ impl<'a> CrateTypes<'a> {
 /// A struct which tracks resolving rust types into C-mapped equivalents, exists for one specific
 /// module but contains a reference to the overall CrateTypes tracking.
 pub struct TypeResolver<'mod_lifetime, 'crate_lft: 'mod_lifetime> {
-       pub orig_crate: &'mod_lifetime str,
        pub module_path: &'mod_lifetime str,
        pub crate_types: &'mod_lifetime CrateTypes<'crate_lft>,
        types: ImportResolver<'mod_lifetime, 'crate_lft>,
@@ -679,8 +702,8 @@ enum ContainerPrefixLocation {
 }
 
 impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
-       pub fn new(orig_crate: &'a str, module_path: &'a str, types: ImportResolver<'a, 'c>, crate_types: &'a CrateTypes<'c>) -> Self {
-               Self { orig_crate, module_path, types, crate_types }
+       pub fn new(module_path: &'a str, types: ImportResolver<'a, 'c>, crate_types: &'a CrateTypes<'c>) -> Self {
+               Self { module_path, types, crate_types }
        }
 
        // *************************************************
@@ -756,7 +779,7 @@ 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" => Some("crate::chain::transaction::OutPoint"),
+                       "bitcoin::blockdata::transaction::OutPoint" => Some("crate::lightning::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::network::constants::Network" => Some("crate::bitcoin::network::Network"),
@@ -769,15 +792,15 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "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]"),
-                       "ln::channelmanager::PaymentPreimage" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),
-                       "ln::channelmanager::PaymentSecret" if is_ref => Some("crate::c_types::ThirtyTwoBytes"),
-                       "ln::channelmanager::PaymentSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),
+                       "lightning::ln::channelmanager::PaymentHash" if is_ref => Some("*const [u8; 32]"),
+                       "lightning::ln::channelmanager::PaymentHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),
+                       "lightning::ln::channelmanager::PaymentPreimage" if is_ref => Some("*const [u8; 32]"),
+                       "lightning::ln::channelmanager::PaymentPreimage" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),
+                       "lightning::ln::channelmanager::PaymentSecret" if is_ref => Some("crate::c_types::ThirtyTwoBytes"),
+                       "lightning::ln::channelmanager::PaymentSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes"),
 
                        // Override the default since Records contain an fmt with a lifetime:
-                       "util::logger::Record" => Some("*const std::os::raw::c_char"),
+                       "lightning::util::logger::Record" => Some("*const std::os::raw::c_char"),
 
                        _ => None,
                }
@@ -832,11 +855,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "bitcoin::hash_types::Txid" if is_ref => Some("&::bitcoin::hash_types::Txid::from_slice(&unsafe { &*"),
                        "bitcoin::hash_types::Txid" if !is_ref => Some("::bitcoin::hash_types::Txid::from_slice(&"),
                        "bitcoin::hash_types::BlockHash" => Some("::bitcoin::hash_types::BlockHash::from_slice(&"),
-                       "ln::channelmanager::PaymentHash" if !is_ref => Some("::lightning::ln::channelmanager::PaymentHash("),
-                       "ln::channelmanager::PaymentHash" if is_ref => Some("&::lightning::ln::channelmanager::PaymentHash(unsafe { *"),
-                       "ln::channelmanager::PaymentPreimage" if !is_ref => Some("::lightning::ln::channelmanager::PaymentPreimage("),
-                       "ln::channelmanager::PaymentPreimage" if is_ref => Some("&::lightning::ln::channelmanager::PaymentPreimage(unsafe { *"),
-                       "ln::channelmanager::PaymentSecret" => Some("::lightning::ln::channelmanager::PaymentSecret("),
+                       "lightning::ln::channelmanager::PaymentHash" if !is_ref => Some("::lightning::ln::channelmanager::PaymentHash("),
+                       "lightning::ln::channelmanager::PaymentHash" if is_ref => Some("&::lightning::ln::channelmanager::PaymentHash(unsafe { *"),
+                       "lightning::ln::channelmanager::PaymentPreimage" if !is_ref => Some("::lightning::ln::channelmanager::PaymentPreimage("),
+                       "lightning::ln::channelmanager::PaymentPreimage" if is_ref => Some("&::lightning::ln::channelmanager::PaymentPreimage(unsafe { *"),
+                       "lightning::ln::channelmanager::PaymentSecret" => Some("::lightning::ln::channelmanager::PaymentSecret("),
 
                        // List of traits we map (possibly during processing of other files):
                        "crate::util::logger::Logger" => Some(""),
@@ -884,11 +907,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "bitcoin::hash_types::Txid" if is_ref => Some(" }[..]).unwrap()"),
                        "bitcoin::hash_types::Txid" => Some(".data[..]).unwrap()"),
                        "bitcoin::hash_types::BlockHash" if !is_ref => Some(".data[..]).unwrap()"),
-                       "ln::channelmanager::PaymentHash" if !is_ref => Some(".data)"),
-                       "ln::channelmanager::PaymentHash" if is_ref => Some(" })"),
-                       "ln::channelmanager::PaymentPreimage" if !is_ref => Some(".data)"),
-                       "ln::channelmanager::PaymentPreimage" if is_ref => Some(" })"),
-                       "ln::channelmanager::PaymentSecret" => Some(".data)"),
+                       "lightning::ln::channelmanager::PaymentHash" if !is_ref => Some(".data)"),
+                       "lightning::ln::channelmanager::PaymentHash" if is_ref => Some(" })"),
+                       "lightning::ln::channelmanager::PaymentPreimage" if !is_ref => Some(".data)"),
+                       "lightning::ln::channelmanager::PaymentPreimage" if is_ref => Some(" })"),
+                       "lightning::ln::channelmanager::PaymentSecret" => Some(".data)"),
 
                        // List of traits we map (possibly during processing of other files):
                        "crate::util::logger::Logger" => Some(""),
@@ -913,7 +936,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
 
                        // Override the default since Records contain an fmt with a lifetime:
                        // TODO: We should include the other record fields
-                       "util::logger::Record" => Some(("std::ffi::CString::new(format!(\"{}\", ", ".args)).unwrap()")),
+                       "lightning::util::logger::Record" => Some(("std::ffi::CString::new(format!(\"{}\", ", ".args)).unwrap()")),
                        _ => None,
                }.map(|s| s.to_owned())
        }
@@ -962,14 +985,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "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("&"),
-                       "ln::channelmanager::PaymentPreimage" => Some("crate::c_types::ThirtyTwoBytes { data: "),
-                       "ln::channelmanager::PaymentSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "),
+                       "lightning::ln::channelmanager::PaymentHash" if is_ref => Some("&"),
+                       "lightning::ln::channelmanager::PaymentHash" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "),
+                       "lightning::ln::channelmanager::PaymentPreimage" if is_ref => Some("&"),
+                       "lightning::ln::channelmanager::PaymentPreimage" => Some("crate::c_types::ThirtyTwoBytes { data: "),
+                       "lightning::ln::channelmanager::PaymentSecret" if !is_ref => Some("crate::c_types::ThirtyTwoBytes { data: "),
 
                        // Override the default since Records contain an fmt with a lifetime:
-                       "util::logger::Record" => Some("local_"),
+                       "lightning::util::logger::Record" => Some("local_"),
 
                        _ => None,
                }.map(|s| s.to_owned())
@@ -1020,14 +1043,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "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"),
-                       "ln::channelmanager::PaymentPreimage" => Some(".0 }"),
-                       "ln::channelmanager::PaymentSecret" if !is_ref => Some(".0 }"),
+                       "lightning::ln::channelmanager::PaymentHash" if is_ref => Some(".0"),
+                       "lightning::ln::channelmanager::PaymentHash" => Some(".0 }"),
+                       "lightning::ln::channelmanager::PaymentPreimage" if is_ref => Some(".0"),
+                       "lightning::ln::channelmanager::PaymentPreimage" => Some(".0 }"),
+                       "lightning::ln::channelmanager::PaymentSecret" if !is_ref => Some(".0 }"),
 
                        // Override the default since Records contain an fmt with a lifetime:
-                       "util::logger::Record" => Some(".as_ptr()"),
+                       "lightning::util::logger::Record" => Some(".as_ptr()"),
 
                        _ => None,
                }.map(|s| s.to_owned())
@@ -1035,7 +1058,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
 
        fn empty_val_check_suffix_from_path(&self, full_path: &str) -> Option<&str> {
                match full_path {
-                       "ln::channelmanager::PaymentSecret" => Some(".data == [0; 32]"),
+                       "lightning::ln::channelmanager::PaymentSecret" => Some(".data == [0; 32]"),
                        "bitcoin::secp256k1::key::PublicKey" => Some(".is_null()"),
                        "bitcoin::secp256k1::Signature" => Some(".is_null()"),
                        _ => None
@@ -1264,7 +1287,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                // If we're printing a generic argument, it needs to reference the crate, otherwise
                                // the original crate:
                                } else if self.maybe_resolve_path(&path, None).as_ref() == Some(&resolved) {
-                                       write!(w, "{}::{}", self.orig_crate, resolved).unwrap();
+                                       write!(w, "{}", resolved).unwrap();
                                } else {
                                        write!(w, "crate::{}", resolved).unwrap();
                                }
index 0d03950f106dcff10f9f1d8ffcb889e0dd4d07c0..67489a669ec49c7411788da9ce96fd2699b9ab3d 100755 (executable)
@@ -32,7 +32,7 @@ mv lightning-c-bindings/src/bitcoin ./
 
 rm -rf lightning-c-bindings/src
 
-mkdir -p lightning-c-bindings/src/c_types/
+mkdir -p lightning-c-bindings/src/{c_types,lightning}
 mv ./mod.rs lightning-c-bindings/src/c_types/
 mv ./bitcoin lightning-c-bindings/src/
 
@@ -44,11 +44,20 @@ OUT_CPP="$(pwd)/lightning-c-bindings/include/lightningpp.hpp"
 BIN="$(pwd)/c-bindings-gen/target/release/c-bindings-gen"
 
 pushd "$LIGHTNING_PATH"
-RUSTC_BOOTSTRAP=1 cargo rustc $FEATURES_ARGS --profile=check -- -Zunstable-options --pretty=expanded |
-       RUST_BACKTRACE=1 "$BIN" "$OUT/" lightning "$OUT_TEMPL" "$OUT_F" "$OUT_CPP"
-popd
+RUSTC_BOOTSTRAP=1 cargo rustc $FEATURES_ARGS --profile=check -- -Zunstable-options --pretty=expanded > /tmp/lightning-crate-source.txt
 
 HOST_PLATFORM="$(rustc --version --verbose | grep "host:")"
+if [ "$HOST_PLATFORM" = "host: x86_64-apple-darwin" ]; then
+       # OSX sed is for some reason not compatible with GNU sed
+       sed -E -i '' 's/#!\[crate_name = "(.*)"\]/pub mod \1 {/' /tmp/lightning-crate-source.txt
+else
+       sed -E -i 's/#!\[crate_name = "(.*)"\]/pub mod \1 {/' /tmp/lightning-crate-source.txt
+fi
+echo "}" >> /tmp/lightning-crate-source.txt
+
+cat /tmp/lightning-crate-source.txt | RUST_BACKTRACE=1 "$BIN" "$OUT/" lightning "$OUT_TEMPL" "$OUT_F" "$OUT_CPP"
+popd
+
 if [ "$HOST_PLATFORM" = "host: x86_64-apple-darwin" ]; then
        # OSX sed is for some reason not compatible with GNU sed
        sed -i '' 's|lightning = { .*|lightning = { path = "'"$LIGHTNING_PATH"'", features = ['"$FEATURES"'] }|' lightning-c-bindings/Cargo.toml