Handle core:: and alloc::paths instead of just std:: (or prelude)
[ldk-c-bindings] / c-bindings-gen / src / main.rs
index 918a05a935e0c117d93f3dddfcb92365a178a78a..94d25e8bba03d77497ac199ebf41a03b4402a06c 100644 (file)
@@ -180,7 +180,7 @@ eprintln!("{}", trait_path);
 // *** Per-Type Printing Logic ***
 // *******************************
 
-macro_rules! walk_supertraits { ($t: expr, $types: expr, ($( $pat: pat => $e: expr),*) ) => { {
+macro_rules! walk_supertraits { ($t: expr, $types: expr, ($( $($pat: pat)|* => $e: expr),*) ) => { {
        if $t.colon_token.is_some() {
                for st in $t.supertraits.iter() {
                        match st {
@@ -194,14 +194,14 @@ macro_rules! walk_supertraits { ($t: expr, $types: expr, ($( $pat: pat => $e: ex
                                        if let Some(types) = types_opt {
                                                if let Some(path) = types.maybe_resolve_path(&supertrait.path, None) {
                                                        match (&path as &str, &supertrait.path.segments.iter().last().unwrap().ident) {
-                                                               $( $pat => $e, )*
+                                                               $( $($pat)|* => $e, )*
                                                        }
                                                        continue;
                                                }
                                        }
                                        if let Some(ident) = supertrait.path.get_ident() {
                                                match (&format!("{}", ident) as &str, &ident) {
-                                                       $( $pat => $e, )*
+                                                       $( $($pat)|* => $e, )*
                                                }
                                        } else if types_opt.is_some() {
                                                panic!("Supertrait unresolvable and not single-ident");
@@ -311,13 +311,13 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                        writeln!(w, "\tpub clone: Option<extern \"C\" fn (this_arg: *const c_void) -> *mut c_void>,").unwrap();
                        generated_fields.push(("clone".to_owned(), true));
                },
-               ("std::cmp::Eq", _) => {
+               ("std::cmp::Eq", _)|("core::cmp::Eq", _) => {
                        writeln!(w, "\t/// Checks if two objects are equal given this object's this_arg pointer and another object.").unwrap();
                        writeln!(w, "\tpub eq: extern \"C\" fn (this_arg: *const c_void, other_arg: &{}) -> bool,", trait_name).unwrap();
                        writeln!(extra_headers, "typedef struct LDK{} LDK{};", trait_name, trait_name).unwrap();
                        generated_fields.push(("eq".to_owned(), true));
                },
-               ("std::hash::Hash", _) => {
+               ("std::hash::Hash", _)|("core::hash::Hash", _) => {
                        writeln!(w, "\t/// Calculate a succinct non-cryptographic hash for an object given its this_arg pointer.").unwrap();
                        writeln!(w, "\t/// This is used, for example, for inclusion of this object in a hash map.").unwrap();
                        writeln!(w, "\tpub hash: extern \"C\" fn (this_arg: *const c_void) -> u64,").unwrap();
@@ -388,7 +388,7 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
                                                                                                        ident.mutability.is_some() || ident.subpat.is_some() {
                                                                                                unimplemented!();
                                                                                        }
-                                                                                       write!(w, ", {}{}: ", if $type_resolver.skip_arg(&*arg.ty, Some(&meth_gen_types)) { "_" } else { "" }, ident.ident).unwrap();
+                                                                                       write!(w, ", mut {}{}: ", if $type_resolver.skip_arg(&*arg.ty, Some(&meth_gen_types)) { "_" } else { "" }, ident.ident).unwrap();
                                                                                }
                                                                                _ => unimplemented!(),
                                                                        }
@@ -452,12 +452,12 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty
        walk_supertraits!(t, Some(&types), (
                ("Send", _) => writeln!(w, "unsafe impl Send for {} {{}}", trait_name).unwrap(),
                ("Sync", _) => writeln!(w, "unsafe impl Sync for {} {{}}", trait_name).unwrap(),
-               ("std::cmp::Eq", _) => {
+               ("std::cmp::Eq", _)|("core::cmp::Eq", _) => {
                        writeln!(w, "impl std::cmp::Eq for {} {{}}", trait_name).unwrap();
                        writeln!(w, "impl std::cmp::PartialEq for {} {{", trait_name).unwrap();
                        writeln!(w, "\tfn eq(&self, o: &Self) -> bool {{ (self.eq)(self.this_arg, o) }}\n}}").unwrap();
                },
-               ("std::hash::Hash", _) => {
+               ("std::hash::Hash", _)|("core::hash::Hash", _) => {
                        writeln!(w, "impl std::hash::Hash for {} {{", trait_name).unwrap();
                        writeln!(w, "\tfn hash<H: std::hash::Hasher>(&self, hasher: &mut H) {{ hasher.write_u64((self.hash)(self.this_arg)) }}\n}}").unwrap();
                },
@@ -966,7 +966,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                                                        writeln!(w, "#[no_mangle]").unwrap();
                                                        writeln!(w, "/// Read a {} object from a string", ident).unwrap();
                                                        writeln!(w, "pub extern \"C\" fn {}_from_str(s: crate::c_types::Str) -> {} {{", ident, container).unwrap();
-                                                       writeln!(w, "\tmatch {}::from_str(s.into()) {{", resolved_path).unwrap();
+                                                       writeln!(w, "\tmatch {}::from_str(s.into_str()) {{", resolved_path).unwrap();
                                                        writeln!(w, "\t\tOk(r) => {{").unwrap();
                                                        let new_var = types.write_to_c_conversion_new_var(w, &format_ident!("r"), &*i.self_ty, Some(&gen_types), false);
                                                        write!(w, "\t\t\tcrate::c_types::CResultTempl::ok(\n\t\t\t\t").unwrap();
@@ -974,7 +974,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
                                                        write!(w, "{}r", if new_var { "local_" } else { "" }).unwrap();
                                                        types.write_to_c_conversion_inline_suffix(w, &*i.self_ty, Some(&gen_types), false);
                                                        writeln!(w, "\n\t\t\t)\n\t\t}},").unwrap();
-                                                       writeln!(w, "\t\tErr(e) => crate::c_types::CResultTempl::err(0u8),").unwrap();
+                                                       writeln!(w, "\t\tErr(e) => crate::c_types::CResultTempl::err(()),").unwrap();
                                                        writeln!(w, "\t}}.into()\n}}").unwrap();
                                                }
                                        } else if path_matches_nongeneric(&trait_path.1, &["Display"]) {
@@ -1137,9 +1137,8 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
        }
        writeln_docs(w, &e.attrs, "");
 
-       if e.generics.lt_token.is_some() {
-               unimplemented!();
-       }
+       let mut gen_types = GenericTypes::new(None);
+       assert!(gen_types.learn_generics(&e.generics, types));
 
        let mut needs_free = false;
 
@@ -1155,21 +1154,31 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                                if export_status(&field.attrs) == ExportStatus::TestOnly { continue; }
                                writeln_docs(w, &field.attrs, "\t\t");
                                write!(w, "\t\t{}: ", field.ident.as_ref().unwrap()).unwrap();
-                               types.write_c_type(w, &field.ty, None, false);
+                               types.write_c_type(w, &field.ty, Some(&gen_types), false);
                                writeln!(w, ",").unwrap();
                        }
                        write!(w, "\t}}").unwrap();
                } else if let syn::Fields::Unnamed(fields) = &var.fields {
-                       needs_free = true;
-                       write!(w, "(").unwrap();
-                       for (idx, field) in fields.unnamed.iter().enumerate() {
-                               if export_status(&field.attrs) == ExportStatus::TestOnly { continue; }
-                               types.write_c_type(w, &field.ty, None, false);
-                               if idx != fields.unnamed.len() - 1 {
-                                       write!(w, ",").unwrap();
+                       let mut empty_tuple_variant = false;
+                       if fields.unnamed.len() == 1 {
+                               let mut empty_check = Vec::new();
+                               types.write_c_type(&mut empty_check, &fields.unnamed[0].ty, Some(&gen_types), false);
+                               if empty_check.is_empty() {
+                                       empty_tuple_variant = true;
+                               }
+                       }
+                       if !empty_tuple_variant {
+                               needs_free = true;
+                               write!(w, "(").unwrap();
+                               for (idx, field) in fields.unnamed.iter().enumerate() {
+                                       if export_status(&field.attrs) == ExportStatus::TestOnly { continue; }
+                                       types.write_c_type(w, &field.ty, Some(&gen_types), false);
+                                       if idx != fields.unnamed.len() - 1 {
+                                               write!(w, ",").unwrap();
+                                       }
                                }
+                               write!(w, ")").unwrap();
                        }
-                       write!(w, ")").unwrap();
                }
                if var.discriminant.is_some() { unimplemented!(); }
                writeln!(w, ",").unwrap();
@@ -1181,6 +1190,7 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                        writeln!(w, "\t#[allow(unused)]\n\tpub(crate) fn {} {{\n\t\tmatch {} {{", $fn_sig, if $to_c { "native" } else { "self" }).unwrap();
                        for var in e.variants.iter() {
                                write!(w, "\t\t\t{}{}::{} ", if $to_c { "native" } else { "" }, e.ident, var.ident).unwrap();
+                               let mut empty_tuple_variant = false;
                                if let syn::Fields::Named(fields) = &var.fields {
                                        write!(w, "{{").unwrap();
                                        for field in fields.named.iter() {
@@ -1189,12 +1199,21 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                                        }
                                        write!(w, "}} ").unwrap();
                                } else if let syn::Fields::Unnamed(fields) = &var.fields {
-                                       write!(w, "(").unwrap();
-                                       for (idx, field) in fields.unnamed.iter().enumerate() {
-                                               if export_status(&field.attrs) == ExportStatus::TestOnly { continue; }
-                                               write!(w, "{}{}, ", if $ref { "ref " } else { "mut " }, ('a' as u8 + idx as u8) as char).unwrap();
+                                       if fields.unnamed.len() == 1 {
+                                               let mut empty_check = Vec::new();
+                                               types.write_c_type(&mut empty_check, &fields.unnamed[0].ty, Some(&gen_types), false);
+                                               if empty_check.is_empty() {
+                                                       empty_tuple_variant = true;
+                                               }
+                                       }
+                                       if !empty_tuple_variant || $to_c {
+                                               write!(w, "(").unwrap();
+                                               for (idx, field) in fields.unnamed.iter().enumerate() {
+                                                       if export_status(&field.attrs) == ExportStatus::TestOnly { continue; }
+                                                       write!(w, "{}{}, ", if $ref { "ref " } else { "mut " }, ('a' as u8 + idx as u8) as char).unwrap();
+                                               }
+                                               write!(w, ") ").unwrap();
                                        }
-                                       write!(w, ") ").unwrap();
                                }
                                write!(w, "=>").unwrap();
 
@@ -1204,9 +1223,9 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                                                let mut sink = ::std::io::sink();
                                                let mut out: &mut dyn std::io::Write = if $ref { &mut sink } else { w };
                                                let new_var = if $to_c {
-                                                       types.write_to_c_conversion_new_var(&mut out, $field_ident, &$field.ty, None, false)
+                                                       types.write_to_c_conversion_new_var(&mut out, $field_ident, &$field.ty, Some(&gen_types), false)
                                                } else {
-                                                       types.write_from_c_conversion_new_var(&mut out, $field_ident, &$field.ty, None)
+                                                       types.write_from_c_conversion_new_var(&mut out, $field_ident, &$field.ty, Some(&gen_types))
                                                };
                                                if $ref || new_var {
                                                        if $ref {
@@ -1214,9 +1233,9 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                                                                if new_var {
                                                                        let nonref_ident = format_ident!("{}_nonref", $field_ident);
                                                                        if $to_c {
-                                                                               types.write_to_c_conversion_new_var(w, &nonref_ident, &$field.ty, None, false);
+                                                                               types.write_to_c_conversion_new_var(w, &nonref_ident, &$field.ty, Some(&gen_types), false);
                                                                        } else {
-                                                                               types.write_from_c_conversion_new_var(w, &nonref_ident, &$field.ty, None);
+                                                                               types.write_from_c_conversion_new_var(w, &nonref_ident, &$field.ty, Some(&gen_types));
                                                                        }
                                                                        write!(w, "\n\t\t\t\t").unwrap();
                                                                }
@@ -1234,7 +1253,9 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                                } else if let syn::Fields::Unnamed(fields) = &var.fields {
                                        write!(w, " {{\n\t\t\t\t").unwrap();
                                        for (idx, field) in fields.unnamed.iter().enumerate() {
-                                               handle_field_a!(field, &format_ident!("{}", ('a' as u8 + idx as u8) as char));
+                                               if !empty_tuple_variant {
+                                                       handle_field_a!(field, &format_ident!("{}", ('a' as u8 + idx as u8) as char));
+                                               }
                                        }
                                } else { write!(w, " ").unwrap(); }
 
@@ -1244,16 +1265,16 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                                        ($field: expr, $field_ident: expr) => { {
                                                if export_status(&$field.attrs) == ExportStatus::TestOnly { continue; }
                                                if $to_c {
-                                                       types.write_to_c_conversion_inline_prefix(w, &$field.ty, None, false);
+                                                       types.write_to_c_conversion_inline_prefix(w, &$field.ty, Some(&gen_types), false);
                                                } else {
-                                                       types.write_from_c_conversion_prefix(w, &$field.ty, None);
+                                                       types.write_from_c_conversion_prefix(w, &$field.ty, Some(&gen_types));
                                                }
                                                write!(w, "{}{}", $field_ident,
                                                        if $ref { "_nonref" } else { "" }).unwrap();
                                                if $to_c {
-                                                       types.write_to_c_conversion_inline_suffix(w, &$field.ty, None, false);
+                                                       types.write_to_c_conversion_inline_suffix(w, &$field.ty, Some(&gen_types), false);
                                                } else {
-                                                       types.write_from_c_conversion_suffix(w, &$field.ty, None);
+                                                       types.write_from_c_conversion_suffix(w, &$field.ty, Some(&gen_types));
                                                }
                                                write!(w, ",").unwrap();
                                        } }
@@ -1269,12 +1290,14 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
                                        writeln!(w, "\n\t\t\t\t}}").unwrap();
                                        write!(w, "\t\t\t}}").unwrap();
                                } else if let syn::Fields::Unnamed(fields) = &var.fields {
-                                       write!(w, " (").unwrap();
-                                       for (idx, field) in fields.unnamed.iter().enumerate() {
-                                               write!(w, "\n\t\t\t\t\t").unwrap();
-                                               handle_field_b!(field, &format_ident!("{}", ('a' as u8 + idx as u8) as char));
+                                       if !empty_tuple_variant || !$to_c {
+                                               write!(w, " (").unwrap();
+                                               for (idx, field) in fields.unnamed.iter().enumerate() {
+                                                       write!(w, "\n\t\t\t\t\t").unwrap();
+                                                       handle_field_b!(field, &format_ident!("{}", ('a' as u8 + idx as u8) as char));
+                                               }
+                                               writeln!(w, "\n\t\t\t\t)").unwrap();
                                        }
-                                       writeln!(w, "\n\t\t\t\t)").unwrap();
                                        write!(w, "\t\t\t}}").unwrap();
                                }
                                writeln!(w, ",").unwrap();
@@ -1399,6 +1422,7 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a>
                        writeln!(out, "#![allow(unused_braces)]").unwrap();
                        // TODO: We need to map deny(missing_docs) in the source crate(s)
                        //writeln!(out, "#![deny(missing_docs)]").unwrap();
+                       writeln!(out, "pub mod version;").unwrap();
                        writeln!(out, "pub mod c_types;").unwrap();
                        writeln!(out, "pub mod bitcoin;").unwrap();
                } else {