]> git.bitcoin.ninja Git - ldk-c-bindings/commitdiff
Resolve generic params with default (eg `<A=B(>) as their default.
authorMatt Corallo <git@bluematt.me>
Fri, 30 Apr 2021 18:35:58 +0000 (18:35 +0000)
committerMatt Corallo <git@bluematt.me>
Fri, 30 Apr 2021 23:41:31 +0000 (23:41 +0000)
c-bindings-gen/src/types.rs

index 57678669a19ef1b6197ccfaf0f996bee3cd5465b..395441b185f15476be764de81d7401b968795d85 100644 (file)
@@ -167,17 +167,18 @@ pub struct GenericTypes<'a, 'b> {
        self_ty: Option<(String, &'a syn::Path)>,
        parent: Option<&'b GenericTypes<'b, 'b>>,
        typed_generics: HashMap<&'a syn::Ident, (String, Option<&'a syn::Path>)>,
+       default_generics: HashMap<&'a syn::Ident, (&'a syn::Type, syn::Type)>,
 }
 impl<'a, 'p: 'a> GenericTypes<'a, 'p> {
        pub fn new(self_ty: Option<(String, &'a syn::Path)>) -> Self {
-               Self { self_ty, parent: None, typed_generics: HashMap::new(), }
+               Self { self_ty, parent: None, typed_generics: HashMap::new(), default_generics: HashMap::new(), }
        }
 
        /// push a new context onto the stack, allowing for a new set of generics to be learned which
        /// will override any lower contexts, but which will still fall back to resoltion via lower
        /// contexts.
        pub fn push_ctx<'c>(&'c self) -> GenericTypes<'a, 'c> {
-               GenericTypes { self_ty: None, parent: Some(self), typed_generics: HashMap::new(), }
+               GenericTypes { self_ty: None, parent: Some(self), typed_generics: HashMap::new(), default_generics: HashMap::new(), }
        }
 
        /// Learn the generics in generics in the current context, given a TypeResolver.
@@ -208,6 +209,10 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> {
                                                        } else { return false; }
                                                }
                                        }
+                                       if let Some(default) = type_param.default.as_ref() {
+                                               assert!(type_param.bounds.is_empty());
+                                               self.default_generics.insert(&type_param.ident, (default, parse_quote!(&#default)));
+                                       }
                                },
                                _ => {},
                        }
@@ -296,6 +301,7 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> {
                        None
                }
        }
+
        /// Attempt to resolve a Path as a generic parameter and return the full path. as both a string
        /// and syn::Path.
        pub fn maybe_resolve_path<'b>(&'b self, path: &syn::Path) -> Option<(&'b String, &'a syn::Path)> {
@@ -327,6 +333,34 @@ impl<'a, 'p: 'a> GenericTypes<'a, 'p> {
        }
 }
 
+trait ResolveType<'a> { fn resolve_type(&'a self, ty: &'a syn::Type) -> &'a syn::Type; }
+impl<'a, 'b, 'c: 'a + 'b> ResolveType<'c> for Option<&GenericTypes<'a, 'b>> {
+       fn resolve_type(&'c self, ty: &'c syn::Type) -> &'c syn::Type {
+               if let Some(us) = self {
+                       match ty {
+                               syn::Type::Path(p) => {
+                                       if let Some(ident) = p.path.get_ident() {
+                                               if let Some((ty, _)) = us.default_generics.get(ident) {
+                                                       return ty;
+                                               }
+                                       }
+                               },
+                               syn::Type::Reference(syn::TypeReference { elem, .. }) => {
+                                       if let syn::Type::Path(p) = &**elem {
+                                               if let Some(ident) = p.path.get_ident() {
+                                                       if let Some((_, refty)) = us.default_generics.get(ident) {
+                                                               return refty;
+                                                       }
+                                               }
+                                       }
+                               }
+                               _ => {},
+                       }
+               }
+               ty
+       }
+}
+
 #[derive(Clone, PartialEq)]
 // The type of declaration and the object itself
 pub enum DeclType<'a> {
@@ -1644,7 +1678,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        LP: Fn(&str, bool, bool) -> Option<String>, DL: Fn(&mut W, &DeclType, &str, bool, bool), SC: Fn(bool, Option<&str>) -> String>
                        (&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, is_mut: bool, ptr_for_ref: bool,
                         tupleconv: &str, prefix: bool, sliceconv: SC, path_lookup: LP, decl_lookup: DL) {
-               match t {
+               match generics.resolve_type(t) {
                        syn::Type::Reference(r) => {
                                self.write_conversion_inline_intern(w, &*r.elem, generics, true, r.mutability.is_some(),
                                        ptr_for_ref, tupleconv, prefix, sliceconv, path_lookup, decl_lookup);
@@ -1974,7 +2008,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        } }
                }
 
-               match t {
+               match generics.resolve_type(t) {
                        syn::Type::Reference(r) => {
                                if let syn::Type::Slice(_) = &*r.elem {
                                        self.write_conversion_new_var_intern(w, ident, var, &*r.elem, generics, is_ref, ptr_for_ref, to_c, path_lookup, container_lookup, var_prefix, var_suffix)
@@ -2418,7 +2452,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                }
        }
        fn write_c_type_intern<W: std::io::Write>(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, is_mut: bool, ptr_for_ref: bool) -> bool {
-               match t {
+               match generics.resolve_type(t) {
                        syn::Type::Path(p) => {
                                if p.qself.is_some() {
                                        return false;