Gen bindings with rustc --pretty=expanded instead of reading files
[rust-lightning] / c-bindings-gen / src / types.rs
index 7205c9f6f2668fa96517b06955d68b929e6e2002..7f979a5675235b1b54d83e9634dc9f86199ffccc 100644 (file)
@@ -41,28 +41,13 @@ pub fn single_ident_generic_path_to_ident(p: &syn::Path) -> Option<&syn::Ident>
        } else { None }
 }
 
-pub fn attrs_derives_clone(attrs: &[syn::Attribute]) -> bool {
-       for attr in attrs.iter() {
-               let tokens_clone = attr.tokens.clone();
-               let mut token_iter = tokens_clone.into_iter();
-               if let Some(token) = token_iter.next() {
-                       match token {
-                               TokenTree::Group(g) => {
-                                       if format!("{}", single_ident_generic_path_to_ident(&attr.path).unwrap()) == "derive" {
-                                               for id in g.stream().into_iter() {
-                                                       if let TokenTree::Ident(i) = id {
-                                                               if i == "Clone" {
-                                                                       return true;
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               },
-                               _ => {},
-                       }
-               }
+pub fn path_matches_nongeneric(p: &syn::Path, exp: &[&str]) -> bool {
+       if p.segments.len() != exp.len() { return false; }
+       for (seg, e) in p.segments.iter().zip(exp.iter()) {
+               if seg.arguments != syn::PathArguments::None { return false; }
+               if &format!("{}", seg.ident) != *e { return false; }
        }
-       false
+       true
 }
 
 #[derive(Debug, PartialEq)]
@@ -165,6 +150,7 @@ impl<'a> GenericTypes<'a> {
                                                        if let Some(ident) = single_ident_generic_path_to_ident(&trait_bound.path) {
                                                                match &format!("{}", ident) as &str { "Send" => continue, "Sync" => continue, _ => {} }
                                                        }
+                                                       if path_matches_nongeneric(&trait_bound.path, &["core", "clone", "Clone"]) { continue; }
 
                                                        assert_simple_bound(&trait_bound);
                                                        if let Some(mut path) = types.maybe_resolve_path(&trait_bound.path, None) {
@@ -298,7 +284,7 @@ pub enum DeclType<'a> {
 // the sorting is stable across runs. It is deprecated, but the "replacement" doesn't actually
 // accomplish the same goals, so we just ignore it.
 #[allow(deprecated)]
-type NonRandomHash = hash::BuildHasherDefault<hash::SipHasher>;
+pub type NonRandomHash = hash::BuildHasherDefault<hash::SipHasher>;
 
 /// Top-level struct tracking everything which has been defined while walking the crate.
 pub struct CrateTypes<'a> {
@@ -466,10 +452,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "ln::features::InitFeatures" if is_ref && ptr_for_ref => Some("crate::ln::features::InitFeatures"),
                        "ln::features::InitFeatures" if is_ref => Some("*const crate::ln::features::InitFeatures"),
                        "ln::features::InitFeatures" => Some("crate::ln::features::InitFeatures"),
-                       _ => {
-                               eprintln!("    Type {} (ref: {}) unresolvable in C", full_path, is_ref);
-                               None
-                       },
+                       _ => None,
                }
        }
 
@@ -534,10 +517,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        // List of traits we map (possibly during processing of other files):
                        "crate::util::logger::Logger" => Some(""),
 
-                       _ => {
-                               eprintln!("    Type {} unconvertable from C", full_path);
-                               None
-                       },
+                       _ => None,
                }.map(|s| s.to_owned())
        }
        fn from_c_conversion_suffix_from_path<'b>(&self, full_path: &str, is_ref: bool) -> Option<String> {
@@ -593,10 +573,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        // List of traits we map (possibly during processing of other files):
                        "crate::util::logger::Logger" => Some(""),
 
-                       _ => {
-                               eprintln!("    Type {} unconvertable from C", full_path);
-                               None
-                       },
+                       _ => None,
                }.map(|s| s.to_owned())
        }
 
@@ -678,10 +655,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "ln::features::InitFeatures" if is_ref => Some("Box::into_raw(Box::new(crate::ln::features::InitFeatures { inner: &mut "),
                        "ln::features::InitFeatures" if !is_ref => Some("crate::ln::features::InitFeatures { inner: Box::into_raw(Box::new("),
 
-                       _ => {
-                               eprintln!("    Type {} (is_ref: {}) unconvertable to C", full_path, is_ref);
-                               None
-                       },
+                       _ => None,
                }.map(|s| s.to_owned())
        }
        fn to_c_conversion_inline_suffix_from_path(&self, full_path: &str, is_ref: bool, ptr_for_ref: bool) -> Option<String> {
@@ -743,10 +717,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "ln::features::InitFeatures" if is_ref => Some(", is_owned: false }))"),
                        "ln::features::InitFeatures" => Some(")), is_owned: true }"),
 
-                       _ => {
-                               eprintln!("    Type {} unconvertable to C", full_path);
-                               None
-                       },
+                       _ => None,
                }.map(|s| s.to_owned())
        }
 
@@ -915,6 +886,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        eprintln!("Ignoring pub(use) tree!");
                        return;
                }
+               if u.leading_colon.is_some() { eprintln!("Ignoring leading-colon use!"); return; }
                match &u.tree {
                        syn::UseTree::Path(p) => {
                                let new_path = format!("{}", p.ident);
@@ -926,18 +898,15 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        },
                        _ => unimplemented!(),
                }
-               if u.leading_colon.is_some() { unimplemented!() }
        }
 
        pub fn mirrored_enum_declared(&mut self, ident: &syn::Ident) {
-               eprintln!("{} mirrored", ident);
                self.declared.insert(ident.clone(), DeclType::MirroredEnum);
        }
        pub fn enum_ignored(&mut self, ident: &'c syn::Ident) {
                self.declared.insert(ident.clone(), DeclType::EnumIgnored);
        }
-       pub fn struct_imported(&mut self, ident: &'c syn::Ident, named: String) {
-               eprintln!("Imported {} as {}", ident, named);
+       pub fn struct_imported(&mut self, ident: &'c syn::Ident) {
                self.declared.insert(ident.clone(), DeclType::StructImported);
        }
        pub fn struct_ignored(&mut self, ident: &syn::Ident) {
@@ -945,7 +914,6 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                self.declared.insert(ident.clone(), DeclType::StructIgnored);
        }
        pub fn trait_declared(&mut self, ident: &syn::Ident, t: &'c syn::ItemTrait) {
-               eprintln!("Trait {} created", ident);
                self.declared.insert(ident.clone(), DeclType::Trait(t));
        }
        pub fn get_declared_type(&'a self, ident: &syn::Ident) -> Option<&'a DeclType<'c>> {
@@ -1758,102 +1726,28 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
        // *** C Container Type Equivalent and alias Printing ***
        // ******************************************************
 
-       fn write_template_constructor<W: std::io::Write>(&mut self, w: &mut W, container_type: &str, mangled_container: &str, args: &Vec<&syn::Type>, generics: Option<&GenericTypes>, is_ref: bool) -> bool {
-               if container_type.ends_with("Tuple") {
-                       write!(w, "#[no_mangle]\npub extern \"C\" fn {}_new(", mangled_container).unwrap();
-                       for (idx, gen) in args.iter().enumerate() {
-                               write!(w, "{}{}: ", if idx != 0 { ", " } else { "" }, ('a' as u8 + idx as u8) as char).unwrap();
-                               if !self.write_c_type_intern(w, gen, None, false, false, false) { return false; }
-                       }
-                       writeln!(w, ") -> {} {{", mangled_container).unwrap();
-                       write!(w, "\t{} {{ ", mangled_container).unwrap();
-                       for idx in 0..args.len() {
-                               write!(w, "{}, ", ('a' as u8 + idx as u8) as char).unwrap();
-                       }
-                       writeln!(w, "}}\n}}\n").unwrap();
-               } else {
-                       writeln!(w, "").unwrap();
-               }
-               true
-       }
-
-       fn write_template_generics<'b, W: std::io::Write>(&mut self, w: &mut W, args: &mut dyn Iterator<Item=&'b syn::Type>, generics: Option<&GenericTypes>, is_ref: bool, in_crate: bool) {
+       fn write_template_generics<'b, W: std::io::Write>(&mut self, w: &mut W, args: &mut dyn Iterator<Item=&'b syn::Type>, generics: Option<&GenericTypes>, is_ref: bool) -> bool {
+               assert!(!is_ref); // We don't currently support outer reference types
                for (idx, t) in args.enumerate() {
                        if idx != 0 {
                                write!(w, ", ").unwrap();
                        }
-                       if let syn::Type::Tuple(tup) = t {
-                               if tup.elems.is_empty() {
-                                       write!(w, "u8").unwrap();
-                               } else {
-                                       let mut inner_args = Vec::new();
-                                       for arg in tup.elems.iter() {
-                                               inner_args.push(arg);
-                                       }
-                                       assert!(self.write_c_mangled_container_path(w, inner_args, generics, &format!("{}Tuple", tup.elems.len()), is_ref, false, false));
-                               }
-                       } else if let syn::Type::Path(p_arg) = t {
-                               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) {
-                                       if self.is_known_container(&resolved_generic, is_ref) {
-                                               assert!(resolved_generic == "Vec" || resolved_generic == "Result");
-                                               let mut inner_args = Vec::new();
-                                               if let syn::PathArguments::AngleBracketed(args) = &p_arg.path.segments.iter().next().unwrap().arguments {
-                                                       for arg in args.args.iter() {
-                                                               if let syn::GenericArgument::Type(t) = arg { inner_args.push(t) } else { unimplemented!() };
-                                                       }
-                                               } else { unimplemented!(); }
-                                               assert!(self.write_c_mangled_container_path(w, inner_args, generics, &resolved_generic, is_ref, false, false));
-                                       } 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!() }),
-                                                               generics, is_ref, in_crate);
-                                               } else { unimplemented!(); }
-                                       } else if in_crate {
-                                               write!(w, "{}", c_type).unwrap();
-                                       } else {
-                                               self.write_rust_type(w, generics, &t);
-                                       }
-                               } else {
-                                       // If we just write out resolved_generic, it may mostly work, however for
-                                       // original types which are generic, we need the template args. We could
-                                       // figure them out and write them out, too, but its much easier to just
-                                       // reference the native{} type alias which exists at least for opaque types.
-                                       if in_crate {
-                                               write!(w, "crate::{}", resolved_generic).unwrap();
-                                       } else {
-                                               let path_name: Vec<&str> = resolved_generic.rsplitn(2, "::").collect();
-                                               if path_name.len() > 1 {
-                                                       write!(w, "crate::{}::native{}", path_name[1], path_name[0]).unwrap();
-                                               } else {
-                                                       write!(w, "crate::native{}", path_name[0]).unwrap();
-                                               }
-                                       }
-                               }
-                       } else if let syn::Type::Reference(r_arg) = t {
+                       if let syn::Type::Reference(r_arg) = t {
+                               if !self.write_c_type_intern(w, &*r_arg.elem, generics, false, false, false) { return false; }
+
+                               // While write_c_type_intern, above is correct, we don't want to blindly convert a
+                               // reference to something stupid, so check that the container is either opaque or a
+                               // predefined type (currently only Transaction).
                                if let syn::Type::Path(p_arg) = &*r_arg.elem {
                                        let resolved = self.resolve_path(&p_arg.path, generics);
-                                       if self.crate_types.opaques.get(&resolved).is_some() {
-                                               write!(w, "crate::{}", resolved).unwrap();
-                                       } else {
-                                               let cty = self.c_type_from_path(&resolved, true, true).expect("Template generics should be opaque or have a predefined mapping");
-                                               w.write(cty.as_bytes()).unwrap();
-                                       }
+                                       assert!(self.crate_types.opaques.get(&resolved).is_some() ||
+                                                       self.c_type_from_path(&resolved, true, true).is_some(), "Template generics should be opaque or have a predefined mapping");
                                } 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, generics);
-                                       assert!(self.is_primitive(&resolved));
-                                       if let syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Int(len), .. }) = &a_arg.len {
-                                               write!(w, "{}",
-                                                       self.c_type_from_path(&format!("[{}; {}]", resolved, len.base10_digits()), is_ref, false).unwrap()).unwrap();
-                                       }
-                               }
+                       } else {
+                               if !self.write_c_type_intern(w, t, generics, false, false, false) { return false; }
                        }
                }
+               true
        }
        fn check_create_container(&mut self, mangled_container: String, container_type: &str, args: Vec<&syn::Type>, generics: Option<&GenericTypes>, is_ref: bool) -> bool {
                if !self.crate_types.templates_defined.get(&mangled_container).is_some() {
@@ -1865,10 +1759,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                        if tup.elems.is_empty() {
                                                write!(&mut a_ty, "()").unwrap();
                                        } else {
-                                               self.write_template_generics(&mut a_ty, &mut args.iter().map(|t| *t).take(1), generics, is_ref, true);
+                                               if !self.write_template_generics(&mut a_ty, &mut args.iter().map(|t| *t).take(1), generics, is_ref) { return false; }
                                        }
                                } else {
-                                       self.write_template_generics(&mut a_ty, &mut args.iter().map(|t| *t).take(1), generics, is_ref, true);
+                                       if !self.write_template_generics(&mut a_ty, &mut args.iter().map(|t| *t).take(1), generics, is_ref) { return false; }
                                }
 
                                let mut b_ty: Vec<u8> = Vec::new();
@@ -1876,10 +1770,10 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                        if tup.elems.is_empty() {
                                                write!(&mut b_ty, "()").unwrap();
                                        } else {
-                                               self.write_template_generics(&mut b_ty, &mut args.iter().map(|t| *t).skip(1), generics, is_ref, true);
+                                               if !self.write_template_generics(&mut b_ty, &mut args.iter().map(|t| *t).skip(1), generics, is_ref) { return false; }
                                        }
                                } else {
-                                       self.write_template_generics(&mut b_ty, &mut args.iter().map(|t| *t).skip(1), generics, is_ref, true);
+                                       if !self.write_template_generics(&mut b_ty, &mut args.iter().map(|t| *t).skip(1), generics, is_ref) { return false; }
                                }
 
                                let ok_str = String::from_utf8(a_ty).unwrap();
@@ -1891,7 +1785,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                }
                        } else if container_type == "Vec" {
                                let mut a_ty: Vec<u8> = Vec::new();
-                               self.write_template_generics(&mut a_ty, &mut args.iter().map(|t| *t), generics, is_ref, true);
+                               if !self.write_template_generics(&mut a_ty, &mut args.iter().map(|t| *t), generics, is_ref) { return false; }
                                let ty = String::from_utf8(a_ty).unwrap();
                                let is_clonable = self.is_clonable(&ty);
                                write_vec_block(&mut created_container, &mangled_container, &ty, is_clonable);
@@ -1903,7 +1797,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                let mut is_clonable = true;
                                for arg in args.iter() {
                                        let mut ty: Vec<u8> = Vec::new();
-                                       self.write_template_generics(&mut ty, &mut [arg].iter().map(|t| **t), generics, is_ref, true);
+                                       if !self.write_template_generics(&mut ty, &mut [arg].iter().map(|t| **t), generics, is_ref) { return false; }
                                        let ty_str = String::from_utf8(ty).unwrap();
                                        if !self.is_clonable(&ty_str) {
                                                is_clonable = false;
@@ -1970,7 +1864,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                                        generics, &subtype, is_ref, is_mut, ptr_for_ref, true);
                                                        }
                                                } else {
-                                                       let id = &&$p_arg.path.segments.iter().rev().next().unwrap().ident;
+                                                       let id = subtype.rsplitn(2, ':').next().unwrap(); // Get the "Base" name of the resolved type
                                                        write!(w, "{}", id).unwrap();
                                                        write!(mangled_type, "{}", id).unwrap();
                                                        if let Some(w2) = $extra_write as Option<&mut Vec<u8>> {