[bindings] Support traits with generic arguments (to support #681)
[rust-lightning] / c-bindings-gen / src / types.rs
index 5375c4240655fa90b9975b78facd23adbb7e996d..483c1d9b9d12821b427cf8e0e143a56abb9a2400 100644 (file)
@@ -1,6 +1,7 @@
 use std::collections::HashMap;
 use std::fs::File;
 use std::io::Write;
+use std::hash;
 
 use proc_macro2::{TokenTree, Span};
 
@@ -225,6 +226,13 @@ pub enum DeclType<'a> {
        EnumIgnored,
 }
 
+// templates_defined is walked to write the C++ header, so if we use the default hashing it get
+// reordered on each genbindings run. Instead, we use SipHasher (which defaults to 0-keys) so that
+// 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>;
+
 /// Top-level struct tracking everything which has been defined while walking the crate.
 pub struct CrateTypes<'a> {
        /// This may contain structs or enums, but only when either is mapped as
@@ -240,7 +248,7 @@ pub struct CrateTypes<'a> {
        /// exists.
        ///
        /// This is used at the end of processing to make C++ wrapper classes
-       pub templates_defined: HashMap<String, bool>,
+       pub templates_defined: HashMap<String, bool, NonRandomHash>,
        /// The output file for any created template container types, written to as we find new
        /// template containers which need to be defined.
        pub template_file: &'a mut File,
@@ -257,6 +265,17 @@ pub struct TypeResolver<'mod_lifetime, 'crate_lft: 'mod_lifetime> {
        pub crate_types: &'mod_lifetime mut CrateTypes<'crate_lft>,
 }
 
+/// Returned by write_empty_rust_val_check_suffix to indicate what type of dereferencing needs to
+/// happen to get the inner value of a generic.
+enum EmptyValExpectedTy {
+       /// A type which has a flag for being empty (eg an array where we treat all-0s as empty).
+       NonPointer,
+       /// A pointer that we want to dereference and move out of.
+       OwnedPointer,
+       /// A pointer which we want to convert to a reference.
+       ReferenceAsPointer,
+}
+
 impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
        pub fn new(orig_crate: &'a str, module_path: &'a str, crate_types: &'a mut CrateTypes<'c>) -> Self {
                let mut imports = HashMap::new();
@@ -757,20 +776,21 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
 
                                if let Some(t) = single_contained {
                                        let mut v = Vec::new();
-                                       let (needs_deref, ret_ref) = self.write_empty_rust_val_check_suffix(generics, &mut v, t);
+                                       let ret_ref = self.write_empty_rust_val_check_suffix(generics, &mut v, t);
                                        let s = String::from_utf8(v).unwrap();
-                                       if needs_deref && ret_ref {
-                                               return Some(("if ", vec![
-                                                       (format!("{} {{ None }} else {{ Some(", s), format!("unsafe {{ &mut *{} }}", var_access))
-                                               ], ") }"));
-                                       } else if needs_deref {
-                                               return Some(("if ", vec![
-                                                       (format!("{} {{ None }} else {{ Some(", s), format!("unsafe {{ *Box::from_raw({}) }}", var_access))
-                                               ], ") }"));
-                                       } else {
-                                               return Some(("if ", vec![
-                                                       (format!("{} {{ None }} else {{ Some(", s), format!("{}", var_access))
-                                               ], ") }"));
+                                       match ret_ref {
+                                               EmptyValExpectedTy::ReferenceAsPointer =>
+                                                       return Some(("if ", vec![
+                                                               (format!("{} {{ None }} else {{ Some(", s), format!("unsafe {{ &mut *{} }}", var_access))
+                                                       ], ") }")),
+                                               EmptyValExpectedTy::OwnedPointer =>
+                                                       return Some(("if ", vec![
+                                                               (format!("{} {{ None }} else {{ Some(", s), format!("unsafe {{ *Box::from_raw({}) }}", var_access))
+                                                       ], ") }")),
+                                               EmptyValExpectedTy::NonPointer =>
+                                                       return Some(("if ", vec![
+                                                               (format!("{} {{ None }} else {{ Some(", s), format!("{}", var_access))
+                                                       ], ") }")),
                                        }
                                } else { unreachable!(); }
                        },
@@ -912,19 +932,34 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
        // *** Original Rust Type Printing ***
        // ***********************************
 
-       fn write_rust_path<W: std::io::Write>(&self, w: &mut W, path: &syn::Path) {
-               if let Some(resolved) = self.maybe_resolve_path(&path, None) {
+       fn in_rust_prelude(resolved_path: &str) -> bool {
+               match resolved_path {
+                       "Vec" => true,
+                       "Result" => true,
+                       "Option" => true,
+                       _ => false,
+               }
+       }
+
+       fn write_rust_path<W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, path: &syn::Path) {
+               if let Some(resolved) = self.maybe_resolve_path(&path, generics_resolver) {
                        if self.is_primitive(&resolved) {
                                write!(w, "{}", path.get_ident().unwrap()).unwrap();
                        } else {
-                               if resolved.starts_with("ln::") || resolved.starts_with("chain::") || resolved.starts_with("util::") {
-                                       write!(w, "lightning::{}", resolved).unwrap();
+                               // TODO: We should have a generic "is from a dependency" check here instead of
+                               // checking for "bitcoin" explicitly.
+                               if resolved.starts_with("bitcoin::") || Self::in_rust_prelude(&resolved) {
+                                       write!(w, "{}", resolved).unwrap();
+                               // 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();
                                } else {
-                                       write!(w, "{}", resolved).unwrap(); // XXX: Probably doens't work, get_ident().unwrap()
+                                       write!(w, "crate::{}", resolved).unwrap();
                                }
                        }
                        if let syn::PathArguments::AngleBracketed(args) = &path.segments.iter().last().unwrap().arguments {
-                               self.write_rust_generic_arg(w, args.args.iter());
+                               self.write_rust_generic_arg(w, generics_resolver, args.args.iter());
                        }
                } else {
                        if path.leading_colon.is_some() {
@@ -934,12 +969,12 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                if idx != 0 { write!(w, "::").unwrap(); }
                                write!(w, "{}", seg.ident).unwrap();
                                if let syn::PathArguments::AngleBracketed(args) = &seg.arguments {
-                                       self.write_rust_generic_arg(w, args.args.iter());
+                                       self.write_rust_generic_arg(w, generics_resolver, args.args.iter());
                                }
                        }
                }
        }
-       pub fn write_rust_generic_param<'b, W: std::io::Write>(&self, w: &mut W, generics: impl Iterator<Item=&'b syn::GenericParam>) {
+       pub fn write_rust_generic_param<'b, W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, generics: impl Iterator<Item=&'b syn::GenericParam>) {
                let mut had_params = false;
                for (idx, arg) in generics.enumerate() {
                        if idx != 0 { write!(w, ", ").unwrap(); } else { write!(w, "<").unwrap(); }
@@ -954,7 +989,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                match bound {
                                                        syn::TypeParamBound::Trait(tb) => {
                                                                if tb.paren_token.is_some() || tb.lifetimes.is_some() { unimplemented!(); }
-                                                               self.write_rust_path(w, &tb.path);
+                                                               self.write_rust_path(w, generics_resolver, &tb.path);
                                                        },
                                                        _ => unimplemented!(),
                                                }
@@ -967,24 +1002,24 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                if had_params { write!(w, ">").unwrap(); }
        }
 
-       pub fn write_rust_generic_arg<'b, W: std::io::Write>(&self, w: &mut W, generics: impl Iterator<Item=&'b syn::GenericArgument>) {
+       pub fn write_rust_generic_arg<'b, W: std::io::Write>(&self, w: &mut W, generics_resolver: Option<&GenericTypes>, generics: impl Iterator<Item=&'b syn::GenericArgument>) {
                write!(w, "<").unwrap();
                for (idx, arg) in generics.enumerate() {
                        if idx != 0 { write!(w, ", ").unwrap(); }
                        match arg {
-                               syn::GenericArgument::Type(t) => self.write_rust_type(w, t),
+                               syn::GenericArgument::Type(t) => self.write_rust_type(w, generics_resolver, t),
                                _ => unimplemented!(),
                        }
                }
                write!(w, ">").unwrap();
        }
-       pub fn write_rust_type<W: std::io::Write>(&self, w: &mut W, t: &syn::Type) {
+       pub fn write_rust_type<W: std::io::Write>(&self, w: &mut W, generics: Option<&GenericTypes>, t: &syn::Type) {
                match t {
                        syn::Type::Path(p) => {
                                if p.qself.is_some() || p.path.leading_colon.is_some() {
                                        unimplemented!();
                                }
-                               self.write_rust_path(w, &p.path);
+                               self.write_rust_path(w, generics, &p.path);
                        },
                        syn::Type::Reference(r) => {
                                write!(w, "&").unwrap();
@@ -994,11 +1029,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                if r.mutability.is_some() {
                                        write!(w, "mut ").unwrap();
                                }
-                               self.write_rust_type(w, &*r.elem);
+                               self.write_rust_type(w, generics, &*r.elem);
                        },
                        syn::Type::Array(a) => {
                                write!(w, "[").unwrap();
-                               self.write_rust_type(w, &a.elem);
+                               self.write_rust_type(w, generics, &a.elem);
                                if let syn::Expr::Lit(l) = &a.len {
                                        if let syn::Lit::Int(i) = &l.lit {
                                                write!(w, "; {}]", i).unwrap();
@@ -1007,14 +1042,14 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        }
                        syn::Type::Slice(s) => {
                                write!(w, "[").unwrap();
-                               self.write_rust_type(w, &s.elem);
+                               self.write_rust_type(w, generics, &s.elem);
                                write!(w, "]").unwrap();
                        },
                        syn::Type::Tuple(s) => {
                                write!(w, "(").unwrap();
                                for (idx, t) in s.elems.iter().enumerate() {
                                        if idx != 0 { write!(w, ", ").unwrap(); }
-                                       self.write_rust_type(w, &t);
+                                       self.write_rust_type(w, generics, &t);
                                }
                                write!(w, ")").unwrap();
                        },
@@ -1054,23 +1089,23 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                }
        }
 
-       /// Prints a suffix to determine if a variable is empty (ie was set by write_empty_rust_val),
-       /// returning whether we need to dereference the inner value before using it (ie it is a
-       /// pointer).
-       pub fn write_empty_rust_val_check_suffix<W: std::io::Write>(&self, generics: Option<&GenericTypes>, w: &mut W, t: &syn::Type) -> (bool, bool) {
+       /// Prints a suffix to determine if a variable is empty (ie was set by write_empty_rust_val).
+       /// See EmptyValExpectedTy for information on return types.
+       fn write_empty_rust_val_check_suffix<W: std::io::Write>(&self, generics: Option<&GenericTypes>, w: &mut W, t: &syn::Type) -> EmptyValExpectedTy {
                match t {
                        syn::Type::Path(p) => {
                                let resolved = self.resolve_path(&p.path, generics);
                                if self.crate_types.opaques.get(&resolved).is_some() {
                                        write!(w, ".inner.is_null()").unwrap();
-                                       (false, false)
+                                       EmptyValExpectedTy::NonPointer
                                } else {
                                        if let Some(suffix) = self.empty_val_check_suffix_from_path(&resolved) {
                                                write!(w, "{}", suffix).unwrap();
-                                               (false, false) // We may eventually need to allow empty_val_check_suffix_from_path to specify if we need a deref or not
+                                               // We may eventually need to allow empty_val_check_suffix_from_path to specify if we need a deref or not
+                                               EmptyValExpectedTy::NonPointer
                                        } else {
                                                write!(w, " == std::ptr::null_mut()").unwrap();
-                                               (true, false)
+                                               EmptyValExpectedTy::OwnedPointer
                                        }
                                }
                        },
@@ -1078,7 +1113,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                if let syn::Expr::Lit(l) = &a.len {
                                        if let syn::Lit::Int(i) = &l.lit {
                                                write!(w, " == [0; {}]", i.base10_digits()).unwrap();
-                                               (false, false)
+                                               EmptyValExpectedTy::NonPointer
                                        } else { unimplemented!(); }
                                } else { unimplemented!(); }
                        },
@@ -1086,7 +1121,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                // Option<[]> always implies that we want to treat len() == 0 differently from
                                // None, so we always map an Option<[]> into a pointer.
                                write!(w, " == std::ptr::null_mut()").unwrap();
-                               (true, true)
+                               EmptyValExpectedTy::ReferenceAsPointer
                        },
                        _ => unimplemented!(),
                }
@@ -1677,11 +1712,11 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                assert!(self.write_c_type_intern(w, gen, None, false, false, false));
                        }
                        writeln!(w, ") -> {} {{", mangled_container).unwrap();
-                       writeln!(w, "\t{} {{", mangled_container).unwrap();
+                       write!(w, "\t{} {{ ", mangled_container).unwrap();
                        for idx in 0..args.len() {
-                               writeln!(w, "\t\t{}: Box::into_raw(Box::new({})),", ('a' as u8 + idx as u8) as char, ('a' as u8 + idx as u8) as char).unwrap();
+                               write!(w, "{}, ", ('a' as u8 + idx as u8) as char).unwrap();
                        }
-                       writeln!(w, "\t}}\n}}\n").unwrap();
+                       writeln!(w, "}}\n}}\n").unwrap();
                } else {
                        writeln!(w, "").unwrap();
                }
@@ -1723,7 +1758,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                        } else if in_crate {
                                                write!(w, "{}", c_type).unwrap();
                                        } else {
-                                               self.write_rust_type(w, &t);
+                                               self.write_rust_type(w, None, &t);
                                        }
                                } else {
                                        // If we just write out resolved_generic, it may mostly work, however for