[bindings] Un-special-case returning an associated type
[rust-lightning] / c-bindings-gen / src / types.rs
index 483c1d9b9d12821b427cf8e0e143a56abb9a2400..ef38b080405080744bcbcd73e11465077e2662ef 100644 (file)
@@ -33,11 +33,6 @@ pub fn get_single_remaining_path_seg<'a, I: Iterator<Item=&'a syn::PathSegment>>
        } else { None }
 }
 
-pub fn assert_single_path_seg<'a>(p: &'a syn::Path) -> &'a syn::Ident {
-       if p.leading_colon.is_some() { unimplemented!(); }
-       get_single_remaining_path_seg(&mut p.segments.iter()).unwrap()
-}
-
 pub fn single_ident_generic_path_to_ident(p: &syn::Path) -> Option<&syn::Ident> {
        if p.segments.len() == 1 {
                Some(&p.segments.iter().next().unwrap().ident)
@@ -193,6 +188,34 @@ impl<'a> GenericTypes<'a> {
                true
        }
 
+       /// Learn the associated types from the trait in the current context.
+       pub fn learn_associated_types<'b, 'c>(&mut self, t: &'a syn::ItemTrait, types: &'b TypeResolver<'a, 'c>) {
+               for item in t.items.iter() {
+                       match item {
+                               &syn::TraitItem::Type(ref t) => {
+                                       if t.default.is_some() || t.generics.lt_token.is_some() { unimplemented!(); }
+                                       let mut bounds_iter = t.bounds.iter();
+                                       match bounds_iter.next().unwrap() {
+                                               syn::TypeParamBound::Trait(tr) => {
+                                                       assert_simple_bound(&tr);
+                                                       if let Some(mut path) = types.maybe_resolve_path(&tr.path, None) {
+                                                               if types.skip_path(&path) { continue; }
+                                                               let new_ident = if path != "std::ops::Deref" {
+                                                                       path = "crate::".to_string() + &path;
+                                                                       Some(&tr.path)
+                                                               } else { None };
+                                                               self.typed_generics.last_mut().unwrap().insert(&t.ident, (path, new_ident));
+                                                       } else { unimplemented!(); }
+                                               },
+                                               _ => unimplemented!(),
+                                       }
+                                       if bounds_iter.next().is_some() { unimplemented!(); }
+                               },
+                               _ => {},
+                       }
+               }
+       }
+
        /// Attempt to resolve an Ident as a generic parameter and return the full path.
        pub fn maybe_resolve_ident<'b>(&'b self, ident: &syn::Ident) -> Option<&'b String> {
                for gen in self.typed_generics.iter().rev() {
@@ -211,6 +234,16 @@ impl<'a> GenericTypes<'a> {
                                        return Some(res);
                                }
                        }
+               } else {
+                       let mut it = path.segments.iter();
+                       if path.segments.len() == 2 && format!("{}", it.next().unwrap().ident) == "Self" {
+                               let ident = &it.next().unwrap().ident;
+                               for gen in self.typed_generics.iter().rev() {
+                                       if let Some(res) = gen.get(ident).map(|(a, b)| (a, b.unwrap())) {
+                                               return Some(res);
+                                       }
+                               }
+                       }
                }
                None
        }
@@ -1209,17 +1242,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.
@@ -1302,6 +1334,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),
                                        }
                                });
@@ -1324,6 +1357,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!(),
                                });
        }