Push down type conversion logic around contained-has-inner some
[ldk-c-bindings] / c-bindings-gen / src / types.rs
index 35ec928bd42ed8b96cdb296a3e438b00535a52a0..739820d1cc6512abb771a2c034168c9161a93ff1 100644 (file)
@@ -772,6 +772,7 @@ impl<'a> CrateTypes<'a> {
                self.clonable_types.borrow_mut().insert(object);
        }
        pub fn is_clonable(&self, object: &str) -> bool {
+               object.starts_with("&'static ") ||
                self.clonable_types.borrow().contains(object)
        }
        pub fn write_new_template(&self, mangled_container: String, has_destructor: bool, created_container: &[u8]) {
@@ -1431,6 +1432,12 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        // Returns prefix + Vec<(prefix, var-name-to-inline-convert)> + suffix
                        // expecting one element in the vec per generic type, each of which is inline-converted
                        -> Option<(&'b str, Vec<(String, String)>, &'b str, ContainerPrefixLocation)> {
+               let mut only_contained_has_inner = false;
+               let only_contained_resolved = if let Some(syn::Type::Path(p)) = single_contained {
+                       let res = self.resolve_path(&p.path, generics);
+                       only_contained_has_inner = self.c_type_has_inner_from_path(&res);
+                       Some(res)
+               } else { None };
                match full_path {
                        "Result" if !is_ref => {
                                Some(("match ",
@@ -1438,18 +1445,17 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                     ("), false => Err(".to_string(), format!("(*unsafe {{ Box::from_raw(<*mut _>::take_ptr(&mut {}.contents.err)) }})", var_access))],
                                                ")}", ContainerPrefixLocation::PerConv))
                        },
-                       "Slice" if is_ref => {
+                       "Slice" if is_ref && only_contained_has_inner => {
                                Some(("Vec::new(); for mut item in ", vec![(format!(".as_slice().iter() {{ local_{}.push(", var_name), "item".to_string())], "); }", ContainerPrefixLocation::PerConv))
                        },
                        "Vec"|"Slice" => {
                                Some(("Vec::new(); for mut item in ", vec![(format!(".into_rust().drain(..) {{ local_{}.push(", var_name), "item".to_string())], "); }", ContainerPrefixLocation::PerConv))
                        },
                        "Option" => {
-                               if let Some(syn::Type::Path(p)) = single_contained {
-                                       let inner_path = self.resolve_path(&p.path, generics);
-                                       if self.is_primitive(&inner_path) {
+                               if let Some(resolved) = only_contained_resolved {
+                                       if self.is_primitive(&resolved) {
                                                return Some(("if ", vec![(".is_some() { Some(".to_string(), format!("{}.take()", var_access))], ") } else { None }", ContainerPrefixLocation::NoPrefix))
-                                       } else if self.c_type_has_inner_from_path(&inner_path) {
+                                       } else if only_contained_has_inner {
                                                if is_ref {
                                                        return Some(("if ", vec![(".inner.is_null() { None } else { Some((*".to_string(), format!("{}", var_access))], ").clone()) }", ContainerPrefixLocation::PerConv))
                                                } else {
@@ -1662,7 +1668,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                write!(w, ">").unwrap();
        }
        pub fn write_rust_type<W: std::io::Write>(&self, w: &mut W, generics: Option<&GenericTypes>, t: &syn::Type) {
-               match t {
+               match generics.resolve_type(t) {
                        syn::Type::Path(p) => {
                                if p.qself.is_some() {
                                        unimplemented!();
@@ -2160,7 +2166,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                        }
                                }
 
-                               if let Some((prefix, conversions, suffix, prefix_location)) = container_lookup(&$container_type, is_ref && ty_has_inner, only_contained_type, ident, var) {
+                               if let Some((prefix, conversions, suffix, prefix_location)) = container_lookup(&$container_type, is_ref, only_contained_type, ident, var) {
                                        assert_eq!(conversions.len(), $args_len);
                                        write!(w, "let mut local_{}{} = ", ident,
                                                if (!to_c && needs_ref_map) || (to_c && $container_type == "Option" && contains_slice) {"_base"} else { "" }).unwrap();
@@ -2332,6 +2338,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                        }
                                        write!(w, "let mut local_{} = (", ident).unwrap();
                                        for (idx, elem) in t.elems.iter().enumerate() {
+                                               let real_elem = generics.resolve_type(&elem);
                                                let ty_has_inner = {
                                                                if to_c {
                                                                        // "To C ptr_for_ref" means "return the regular object with
@@ -2339,16 +2346,16 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                                        // if we're about to set ty_has_inner.
                                                                        ptr_for_ref = true;
                                                                }
-                                                               if let syn::Type::Reference(t) = elem {
+                                                               if let syn::Type::Reference(t) = real_elem {
                                                                        if let syn::Type::Path(p) = &*t.elem {
                                                                                self.c_type_has_inner_from_path(&self.resolve_path(&p.path, generics))
                                                                        } else { false }
-                                                               } else if let syn::Type::Path(p) = elem {
+                                                               } else if let syn::Type::Path(p) = real_elem {
                                                                        self.c_type_has_inner_from_path(&self.resolve_path(&p.path, generics))
                                                                } else { false }
                                                        };
                                                if idx != 0 { write!(w, ", ").unwrap(); }
-                                               var_prefix(w, elem, generics, is_ref && ty_has_inner, ptr_for_ref, false);
+                                               var_prefix(w, real_elem, generics, is_ref && ty_has_inner, ptr_for_ref, false);
                                                if is_ref && ty_has_inner {
                                                        // For ty_has_inner, the regular var_prefix mapping will take a
                                                        // reference, so deref once here to make sure we keep the original ref.
@@ -2360,7 +2367,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                                                        // hope the type is Clonable and use that.
                                                        write!(w, ".clone()").unwrap();
                                                }
-                                               var_suffix(w, elem, generics, is_ref && ty_has_inner, ptr_for_ref, false);
+                                               var_suffix(w, real_elem, generics, is_ref && ty_has_inner, ptr_for_ref, false);
                                        }
                                        write!(w, "){};", if to_c { ".into()" } else { "" }).unwrap();
                                        true