Merge pull request #19 from TheBlueMatt/2021-04-invoice-incl
[ldk-c-bindings] / c-bindings-gen / src / types.rs
index 1b3810878e782e86c9fc43353e4fbda96ef9226b..d945431199eab2ba51a9fffac3498f0bd3d5582c 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> {
@@ -808,8 +842,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "[u8; 3]" if !is_ref => Some("crate::c_types::ThreeBytes"), // Used for RGB values
 
                        "str" if is_ref => Some("crate::c_types::Str"),
-                       "String" if !is_ref => Some("crate::c_types::derived::CVec_u8Z"),
-                       "String" if is_ref => Some("crate::c_types::Str"),
+                       "String" => Some("crate::c_types::Str"),
 
                        "std::time::Duration" => Some("u64"),
                        "std::time::SystemTime" => Some("u64"),
@@ -881,7 +914,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "[usize]" if is_ref => Some(""),
 
                        "str" if is_ref => Some(""),
-                       "String" if !is_ref => Some("String::from_utf8("),
+                       "String" => Some(""),
                        // Note that we'll panic for String if is_ref, as we only have non-owned memory, we
                        // cannot create a &String.
 
@@ -946,8 +979,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "[u8]" if is_ref => Some(".to_slice()"),
                        "[usize]" if is_ref => Some(".to_slice()"),
 
-                       "str" if is_ref => Some(".into()"),
-                       "String" if !is_ref => Some(".into_rust()).unwrap()"),
+                       "str" if is_ref => Some(".into_str()"),
+                       "String" => Some(".into_string()"),
 
                        "std::time::Duration" => Some(")"),
                        "std::time::SystemTime" => Some("))"),
@@ -1095,8 +1128,8 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
                        "[usize]" if is_ref => Some(""),
 
                        "str" if is_ref => Some(".into()"),
-                       "String" if !is_ref => Some(".into_bytes().into()"),
                        "String" if is_ref => Some(".as_str().into()"),
+                       "String" => Some(".into()"),
 
                        "std::time::Duration" => Some(".as_secs()"),
                        "std::time::SystemTime" => Some(".duration_since(::std::time::SystemTime::UNIX_EPOCH).expect(\"Times must be post-1970\").as_secs()"),
@@ -1644,7 +1677,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);
@@ -1742,7 +1775,7 @@ impl<'a, 'c: 'a> TypeResolver<'a, 'c> {
        }
 
        fn write_to_c_conversion_inline_prefix_inner<W: std::io::Write>(&self, w: &mut W, t: &syn::Type, generics: Option<&GenericTypes>, is_ref: bool, ptr_for_ref: bool, from_ptr: bool) {
-               self.write_conversion_inline_intern(w, t, generics, is_ref, false, ptr_for_ref, "0u8 /*", true, |_, _| "local_".to_owned(),
+               self.write_conversion_inline_intern(w, t, generics, is_ref, false, ptr_for_ref, "() /*", true, |_, _| "local_".to_owned(),
                                |a, b, c| self.to_c_conversion_inline_prefix_from_path(a, b, c),
                                |w, decl_type, decl_path, is_ref, _is_mut| {
                                        match decl_type {
@@ -1974,7 +2007,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 +2451,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;