X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Fmain.rs;h=94f2ed736ea1356d22f30312c7a20dd7ba1a8314;hb=d21758f885f87a3155057a2a93c8362139ebb539;hp=536e4420bda0faa405636ce4452c60750b57dee5;hpb=01c669f1868e5ff8ca8a212aa37bd8f278be22e1;p=ldk-c-bindings diff --git a/c-bindings-gen/src/main.rs b/c-bindings-gen/src/main.rs index 536e442..94f2ed7 100644 --- a/c-bindings-gen/src/main.rs +++ b/c-bindings-gen/src/main.rs @@ -597,7 +597,16 @@ fn writeln_trait<'a, 'b, W: std::io::Write>(w: &mut W, t: &'a syn::ItemTrait, ty (s, i) => { if let Some(supertrait) = types.crate_types.traits.get(s) { let resolver = get_module_type_resolver!(s, types.crate_libs, types.crate_types); - writeln!(w, "impl {} for {} {{", s, trait_name).unwrap(); + + // Blindly assume that the same imports where `supertrait` is defined are also + // imported here. This will almost certainly break at some point, but it should be + // a compilation failure when it does so. + write!(w, "impl").unwrap(); + maybe_write_lifetime_generics(w, &supertrait.generics, types); + write!(w, " {}", s).unwrap(); + maybe_write_generics(w, &supertrait.generics, types, false); + writeln!(w, " for {} {{", trait_name).unwrap(); + impl_trait_for_c!(supertrait, format!(".{}", i), &resolver); writeln!(w, "}}").unwrap(); } else { @@ -1374,167 +1383,7 @@ fn writeln_impl(w: &mut W, i: &syn::ItemImpl, types: &mut Typ } } } else if let Some(resolved_path) = types.maybe_resolve_ident(&ident) { - if let Some(aliases) = types.crate_types.reverse_alias_map.get(&resolved_path).cloned() { - let mut gen_types = Some(GenericTypes::new(Some(resolved_path.clone()))); - if !gen_types.as_mut().unwrap().learn_generics(&i.generics, types) { - gen_types = None; - } - let alias_module = rsplit_once(&resolved_path, "::").unwrap().0; - - 'alias_impls: for (alias_resolved, arguments) in aliases { - let mut new_ty_generics = Vec::new(); - let mut new_ty_bounds = Vec::new(); - let mut need_generics = false; - - let alias_resolver_override; - let alias_resolver = if alias_module != types.module_path { - alias_resolver_override = ImportResolver::new(types.types.crate_name, &types.crate_types.lib_ast.dependencies, - alias_module, &types.crate_types.lib_ast.modules.get(alias_module).unwrap().items); - &alias_resolver_override - } else { &types.types };/*.maybe_resolve_path(&alias, None).unwrap();*/ - let mut where_clause = Some(syn::WhereClause { - where_token: syn::Token![where](Span::call_site()), - predicates: syn::punctuated::Punctuated::new() - }); - for (idx, gen) in i.generics.params.iter().enumerate() { - match gen { - syn::GenericParam::Type(type_param) => { - 'bounds_check: for bound in type_param.bounds.iter() { - if let syn::TypeParamBound::Trait(trait_bound) = bound { - if let syn::PathArguments::AngleBracketed(ref t) = &arguments { - assert!(idx < t.args.len()); - if let syn::GenericArgument::Type(syn::Type::Path(p)) = &t.args[idx] { - let generic_bound = types.maybe_resolve_path(&trait_bound.path, None) - .unwrap_or_else(|| format!("{}::{}", types.module_path, single_ident_generic_path_to_ident(&trait_bound.path).unwrap())); - - if let Some(generic_arg) = alias_resolver.maybe_resolve_path(&p.path, None) { - new_ty_generics.push((type_param.ident.clone(), syn::Type::Path(p.clone()))); - if let Some(traits_impld) = types.crate_types.trait_impls.get(&generic_arg) { - for trait_impld in traits_impld { - if *trait_impld == generic_bound { continue 'bounds_check; } - } - eprintln!("struct {}'s generic arg {} didn't match bound {}", alias_resolved, generic_arg, generic_bound); - continue 'alias_impls; - } else { - eprintln!("struct {}'s generic arg {} didn't match bound {}", alias_resolved, generic_arg, generic_bound); - continue 'alias_impls; - } - } else if gen_types.is_some() { - let resp = types.maybe_resolve_path(&p.path, gen_types.as_ref()); - if generic_bound == "core::ops::Deref" && resp.is_some() { - new_ty_bounds.push((type_param.ident.clone(), - string_path_to_syn_path("core::ops::Deref"))); - let mut bounds = syn::punctuated::Punctuated::new(); - bounds.push(syn::TypeParamBound::Trait(syn::TraitBound { - paren_token: None, - modifier: syn::TraitBoundModifier::None, - lifetimes: None, - path: string_path_to_syn_path(&types.resolve_path(&p.path, gen_types.as_ref())), - })); - let mut path = string_path_to_syn_path(&format!("{}::Target", type_param.ident)); - path.leading_colon = None; - where_clause.as_mut().unwrap().predicates.push(syn::WherePredicate::Type(syn::PredicateType { - lifetimes: None, - bounded_ty: syn::Type::Path(syn::TypePath { qself: None, path }), - colon_token: syn::Token![:](Span::call_site()), - bounds, - })); - } else { - new_ty_generics.push((type_param.ident.clone(), - gen_types.as_ref().resolve_type(&syn::Type::Path(p.clone())).clone())); - } - need_generics = true; - } else { - unimplemented!(); - } - } else { unimplemented!(); } - } else { unimplemented!(); } - } else { unimplemented!(); } - } - }, - syn::GenericParam::Lifetime(_) => {}, - syn::GenericParam::Const(_) => unimplemented!(), - } - } - let mut params = syn::punctuated::Punctuated::new(); - let alias = string_path_to_syn_path(&alias_resolved); - let real_aliased = - if need_generics { - let alias_generics = types.crate_types.opaques.get(&alias_resolved).unwrap().1; - - // If we need generics on the alias, create impl generic bounds... - assert_eq!(new_ty_generics.len() + new_ty_bounds.len(), i.generics.params.len()); - let mut args = syn::punctuated::Punctuated::new(); - for (ident, param) in new_ty_generics.drain(..) { - // TODO: We blindly assume that generics in the type alias and - // the aliased type have the same names, which we really shouldn't. - if alias_generics.params.iter().any(|generic| - if let syn::GenericParam::Type(t) = generic { t.ident == ident } else { false }) - { - args.push(parse_quote!(#ident)); - } - params.push(syn::GenericParam::Type(syn::TypeParam { - attrs: Vec::new(), - ident, - colon_token: None, - bounds: syn::punctuated::Punctuated::new(), - eq_token: Some(syn::token::Eq(Span::call_site())), - default: Some(param), - })); - } - for (ident, param) in new_ty_bounds.drain(..) { - // TODO: We blindly assume that generics in the type alias and - // the aliased type have the same names, which we really shouldn't. - if alias_generics.params.iter().any(|generic| - if let syn::GenericParam::Type(t) = generic { t.ident == ident } else { false }) - { - args.push(parse_quote!(#ident)); - } - params.push(syn::GenericParam::Type(syn::TypeParam { - attrs: Vec::new(), - ident, - colon_token: Some(syn::token::Colon(Span::call_site())), - bounds: syn::punctuated::Punctuated::from_iter( - Some(syn::TypeParamBound::Trait(syn::TraitBound { - path: param, paren_token: None, lifetimes: None, - modifier: syn::TraitBoundModifier::None, - })) - ), - eq_token: None, - default: None, - })); - } - // ... and swap the last segment of the impl self_ty to use the generic bounds. - let mut res = alias.clone(); - res.segments.last_mut().unwrap().arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { - colon2_token: None, - lt_token: syn::token::Lt(Span::call_site()), - args, - gt_token: syn::token::Gt(Span::call_site()), - }); - res - } else { alias.clone() }; - let aliased_impl = syn::ItemImpl { - attrs: i.attrs.clone(), - brace_token: syn::token::Brace(Span::call_site()), - defaultness: None, - generics: syn::Generics { - lt_token: None, - params, - gt_token: None, - where_clause, - }, - impl_token: syn::Token![impl](Span::call_site()), - items: i.items.clone(), - self_ty: Box::new(syn::Type::Path(syn::TypePath { qself: None, path: real_aliased })), - trait_: i.trait_.clone(), - unsafety: None, - }; - writeln_impl(w, &aliased_impl, types); - } - } else { - eprintln!("Not implementing anything for {} due to it being marked not exported", ident); - } + create_alias_for_impl(resolved_path, i, types, move |aliased_impl, types| writeln_impl(w, &aliased_impl, types)); } else { eprintln!("Not implementing anything for {} due to no-resolve (probably the type isn't pub)", ident); } @@ -1542,6 +1391,168 @@ fn writeln_impl(w: &mut W, i: &syn::ItemImpl, types: &mut Typ } } +fn create_alias_for_impl(resolved_path: String, i: &syn::ItemImpl, types: &mut TypeResolver, mut callback: F) { + if let Some(aliases) = types.crate_types.reverse_alias_map.get(&resolved_path).cloned() { + let mut gen_types = Some(GenericTypes::new(Some(resolved_path.clone()))); + if !gen_types.as_mut().unwrap().learn_generics(&i.generics, types) { + gen_types = None; + } + let alias_module = rsplit_once(&resolved_path, "::").unwrap().0; + + 'alias_impls: for (alias_resolved, arguments) in aliases { + let mut new_ty_generics = Vec::new(); + let mut new_ty_bounds = Vec::new(); + let mut need_generics = false; + + let alias_resolver_override; + let alias_resolver = if alias_module != types.module_path { + alias_resolver_override = ImportResolver::new(types.types.crate_name, &types.crate_types.lib_ast.dependencies, + alias_module, &types.crate_types.lib_ast.modules.get(alias_module).unwrap().items); + &alias_resolver_override + } else { &types.types }; + let mut where_clause = syn::WhereClause { where_token: syn::Token![where](Span::call_site()), + predicates: syn::punctuated::Punctuated::new() + }; + for (idx, gen) in i.generics.params.iter().enumerate() { + match gen { + syn::GenericParam::Type(type_param) => { + 'bounds_check: for bound in type_param.bounds.iter() { + if let syn::TypeParamBound::Trait(trait_bound) = bound { + if let syn::PathArguments::AngleBracketed(ref t) = &arguments { + assert!(idx < t.args.len()); + if let syn::GenericArgument::Type(syn::Type::Path(p)) = &t.args[idx] { + let generic_bound = types.maybe_resolve_path(&trait_bound.path, None) + .unwrap_or_else(|| format!("{}::{}", types.module_path, single_ident_generic_path_to_ident(&trait_bound.path).unwrap())); + + if let Some(generic_arg) = alias_resolver.maybe_resolve_path(&p.path, None) { + new_ty_generics.push((type_param.ident.clone(), syn::Type::Path(p.clone()))); + if let Some(traits_impld) = types.crate_types.trait_impls.get(&generic_arg) { + for trait_impld in traits_impld { + if *trait_impld == generic_bound { continue 'bounds_check; } + } + eprintln!("struct {}'s generic arg {} didn't match bound {}", alias_resolved, generic_arg, generic_bound); + continue 'alias_impls; + } else { + eprintln!("struct {}'s generic arg {} didn't match bound {}", alias_resolved, generic_arg, generic_bound); + continue 'alias_impls; + } + } else if gen_types.is_some() { + let resp = types.maybe_resolve_path(&p.path, gen_types.as_ref()); + if generic_bound == "core::ops::Deref" && resp.is_some() { + new_ty_bounds.push((type_param.ident.clone(), + string_path_to_syn_path("core::ops::Deref"))); + let mut bounds = syn::punctuated::Punctuated::new(); + bounds.push(syn::TypeParamBound::Trait(syn::TraitBound { + paren_token: None, + modifier: syn::TraitBoundModifier::None, + lifetimes: None, + path: string_path_to_syn_path(&types.resolve_path(&p.path, gen_types.as_ref())), + })); + let mut path = string_path_to_syn_path(&format!("{}::Target", type_param.ident)); + path.leading_colon = None; + where_clause.predicates.push(syn::WherePredicate::Type(syn::PredicateType { + lifetimes: None, + bounded_ty: syn::Type::Path(syn::TypePath { qself: None, path }), + colon_token: syn::Token![:](Span::call_site()), + bounds, + })); + } else { + new_ty_generics.push((type_param.ident.clone(), + gen_types.as_ref().resolve_type(&syn::Type::Path(p.clone())).clone())); + } + need_generics = true; + } else { + unimplemented!(); + } + } else { unimplemented!(); } + } else { unimplemented!(); } + } else { unimplemented!(); } + } + }, + syn::GenericParam::Lifetime(_) => {}, + syn::GenericParam::Const(_) => unimplemented!(), + } + } + let mut params = syn::punctuated::Punctuated::new(); + let alias = string_path_to_syn_path(&alias_resolved); + let real_aliased = + if need_generics { + let alias_generics = types.crate_types.opaques.get(&alias_resolved).unwrap().1; + + // If we need generics on the alias, create impl generic bounds... + assert_eq!(new_ty_generics.len() + new_ty_bounds.len(), i.generics.params.len()); + let mut args = syn::punctuated::Punctuated::new(); + for (ident, param) in new_ty_generics.drain(..) { + // TODO: We blindly assume that generics in the type alias and + // the aliased type have the same names, which we really shouldn't. + if alias_generics.params.iter().any(|generic| + if let syn::GenericParam::Type(t) = generic { t.ident == ident } else { false }) + { + args.push(parse_quote!(#ident)); + } + params.push(syn::GenericParam::Type(syn::TypeParam { + attrs: Vec::new(), + ident, + colon_token: None, + bounds: syn::punctuated::Punctuated::new(), + eq_token: Some(syn::token::Eq(Span::call_site())), + default: Some(param), + })); + } + for (ident, param) in new_ty_bounds.drain(..) { + // TODO: We blindly assume that generics in the type alias and + // the aliased type have the same names, which we really shouldn't. + if alias_generics.params.iter().any(|generic| + if let syn::GenericParam::Type(t) = generic { t.ident == ident } else { false }) + { + args.push(parse_quote!(#ident)); + } + params.push(syn::GenericParam::Type(syn::TypeParam { + attrs: Vec::new(), + ident, + colon_token: Some(syn::token::Colon(Span::call_site())), + bounds: syn::punctuated::Punctuated::from_iter( + Some(syn::TypeParamBound::Trait(syn::TraitBound { + path: param, paren_token: None, lifetimes: None, + modifier: syn::TraitBoundModifier::None, + })) + ), + eq_token: None, + default: None, + })); + } + // ... and swap the last segment of the impl self_ty to use the generic bounds. + let mut res = alias.clone(); + res.segments.last_mut().unwrap().arguments = syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { + colon2_token: None, + lt_token: syn::token::Lt(Span::call_site()), + args, + gt_token: syn::token::Gt(Span::call_site()), + }); + res + } else { alias.clone() }; + callback(syn::ItemImpl { + attrs: i.attrs.clone(), + brace_token: syn::token::Brace(Span::call_site()), + defaultness: None, + generics: syn::Generics { + lt_token: None, + params, + gt_token: None, + where_clause: Some(where_clause), + }, + impl_token: syn::Token![impl](Span::call_site()), + items: i.items.clone(), + self_ty: Box::new(syn::Type::Path(syn::TypePath { qself: None, path: real_aliased })), + trait_: i.trait_.clone(), + unsafety: None, + }, types); + } + } else { + eprintln!("Not implementing anything for {} due to it being marked not exported", resolved_path); + } +} + /// Replaces upper case charachters with underscore followed by lower case except the first /// charachter and repeated upper case characthers (which are only made lower case). fn camel_to_snake_case(camel: &str) -> String { @@ -1601,29 +1612,32 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type writeln_field_docs(w, &field.attrs, "\t\t", types, Some(&gen_types), &field.ty); write!(w, "\t\t{}: ", field.ident.as_ref().unwrap()).unwrap(); write!(&mut constr, "{}{}: ", if idx != 0 { ", " } else { "" }, field.ident.as_ref().unwrap()).unwrap(); - types.write_c_type(w, &field.ty, Some(&gen_types), false); - types.write_c_type(&mut constr, &field.ty, Some(&gen_types), false); + types.write_c_type(w, &field.ty, Some(&gen_types), true); + types.write_c_type(&mut constr, &field.ty, Some(&gen_types), true); writeln!(w, ",").unwrap(); } write!(w, "\t}}").unwrap(); } else if let syn::Fields::Unnamed(fields) = &var.fields { 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); + types.write_c_type(&mut empty_check, &fields.unnamed[0].ty, Some(&gen_types), true); if empty_check.is_empty() { empty_tuple_variant = true; } } if !empty_tuple_variant { needs_free = true; - write!(w, "(").unwrap(); + writeln!(w, "(").unwrap(); for (idx, field) in fields.unnamed.iter().enumerate() { if export_status(&field.attrs) == ExportStatus::TestOnly { continue; } + writeln_field_docs(w, &field.attrs, "\t\t", types, Some(&gen_types), &field.ty); + write!(w, "\t\t").unwrap(); + types.write_c_type(w, &field.ty, Some(&gen_types), true); + write!(&mut constr, "{}: ", ('a' as u8 + idx as u8) as char).unwrap(); - types.write_c_type(w, &field.ty, Some(&gen_types), false); types.write_c_type(&mut constr, &field.ty, Some(&gen_types), false); if idx != fields.unnamed.len() - 1 { - write!(w, ",").unwrap(); + writeln!(w, ",").unwrap(); write!(&mut constr, ",").unwrap(); } } @@ -1641,8 +1655,19 @@ 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 { if !empty_tuple_variant { write!(&mut constr, "(").unwrap(); - for idx in 0..fields.unnamed.len() { - write!(&mut constr, "{}, ", ('a' as u8 + idx as u8) as char).unwrap(); + for (idx, field) in fields.unnamed.iter().enumerate() { + let mut ref_c_ty = Vec::new(); + let mut nonref_c_ty = Vec::new(); + types.write_c_type(&mut ref_c_ty, &field.ty, Some(&gen_types), false); + types.write_c_type(&mut nonref_c_ty, &field.ty, Some(&gen_types), true); + + if ref_c_ty != nonref_c_ty { + // We blindly assume references in field types are always opaque types, and + // print out an opaque reference -> owned reference conversion here. + write!(&mut constr, "{} {{ inner: {}.inner, is_owned: false }}, ", String::from_utf8(nonref_c_ty).unwrap(), ('a' as u8 + idx as u8) as char).unwrap(); + } else { + write!(&mut constr, "{}, ", ('a' as u8 + idx as u8) as char).unwrap(); + } } writeln!(&mut constr, ")").unwrap(); } else { @@ -1652,7 +1677,10 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type writeln!(&mut constr, "}}").unwrap(); writeln!(w, ",").unwrap(); } - writeln!(w, "}}\nuse {}::{} as native{};\nimpl {} {{", types.module_path, e.ident, e.ident, e.ident).unwrap(); + writeln!(w, "}}\nuse {}::{} as {}Import;", types.module_path, e.ident, e.ident).unwrap(); + write!(w, "pub(crate) type native{} = {}Import", e.ident, e.ident).unwrap(); + maybe_write_generics(w, &e.generics, &types, true); + writeln!(w, ";\n\nimpl {} {{", e.ident).unwrap(); macro_rules! write_conv { ($fn_sig: expr, $to_c: expr, $ref: expr) => { @@ -1670,7 +1698,7 @@ 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 { 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); + types.write_c_type(&mut empty_check, &fields.unnamed[0].ty, Some(&gen_types), true); if empty_check.is_empty() { empty_tuple_variant = true; } @@ -1692,7 +1720,7 @@ 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, Some(&gen_types), false) + types.write_to_c_conversion_new_var(&mut out, $field_ident, &$field.ty, Some(&gen_types), true) } else { types.write_from_c_conversion_new_var(&mut out, $field_ident, &$field.ty, Some(&gen_types)) }; @@ -1702,7 +1730,7 @@ 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, Some(&gen_types), false); + types.write_to_c_conversion_new_var(w, &nonref_ident, &$field.ty, Some(&gen_types), true); } else { types.write_from_c_conversion_new_var(w, &nonref_ident, &$field.ty, Some(&gen_types)); } @@ -1734,14 +1762,14 @@ 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, Some(&gen_types), false); + types.write_to_c_conversion_inline_prefix(w, &$field.ty, Some(&gen_types), true); } else { 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, Some(&gen_types), false); + types.write_to_c_conversion_inline_suffix(w, &$field.ty, Some(&gen_types), true); } else { types.write_from_c_conversion_suffix(w, &$field.ty, Some(&gen_types)); }