X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=c-bindings-gen%2Fsrc%2Fmain.rs;h=b9dba8c92e78188d3bb4abf4a80779fcb9ec2732;hb=276f2e7e6cf0149d56ca72c780e963938feb7206;hp=94f2ed736ea1356d22f30312c7a20dd7ba1a8314;hpb=d21758f885f87a3155057a2a93c8362139ebb539;p=ldk-c-bindings diff --git a/c-bindings-gen/src/main.rs b/c-bindings-gen/src/main.rs index 94f2ed7..b9dba8c 100644 --- a/c-bindings-gen/src/main.rs +++ b/c-bindings-gen/src/main.rs @@ -1594,8 +1594,37 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type let mut needs_free = false; let mut constr = Vec::new(); + let mut is_clonable = true; - writeln!(w, "#[must_use]\n#[derive(Clone)]\n#[repr(C)]\npub enum {} {{", e.ident).unwrap(); + for var in e.variants.iter() { + if let syn::Fields::Named(fields) = &var.fields { + needs_free = true; + for field in fields.named.iter() { + if export_status(&field.attrs) == ExportStatus::TestOnly { continue; } + + let mut ty_checks = Vec::new(); + types.write_c_type(&mut ty_checks, &field.ty, Some(&gen_types), false); + if !types.is_clonable(&String::from_utf8(ty_checks).unwrap()) { + is_clonable = false; + } + } + } else if let syn::Fields::Unnamed(fields) = &var.fields { + for field in fields.unnamed.iter() { + let mut ty_checks = Vec::new(); + types.write_c_type(&mut ty_checks, &field.ty, Some(&gen_types), false); + let ty = String::from_utf8(ty_checks).unwrap(); + if ty != "" && !types.is_clonable(&ty) { + is_clonable = false; + } + } + } + } + + if is_clonable { + writeln!(w, "#[derive(Clone)]").unwrap(); + types.crate_types.set_clonable(format!("{}::{}", types.module_path, e.ident)); + } + writeln!(w, "#[must_use]\n#[repr(C)]\npub enum {} {{", e.ident).unwrap(); for var in e.variants.iter() { assert_eq!(export_status(&var.attrs), ExportStatus::Export); // We can't partially-export a mirrored enum writeln_docs(w, &var.attrs, "\t"); @@ -1803,9 +1832,13 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type } } - write_conv!(format!("to_native(&self) -> native{}", e.ident), false, true); + if is_clonable { + write_conv!(format!("to_native(&self) -> native{}", e.ident), false, true); + } write_conv!(format!("into_native(self) -> native{}", e.ident), false, false); - write_conv!(format!("from_native(native: &native{}) -> Self", e.ident), true, true); + if is_clonable { + write_conv!(format!("from_native(native: &native{}) -> Self", e.ident), true, true); + } write_conv!(format!("native_into(native: native{}) -> Self", e.ident), true, false); writeln!(w, "}}").unwrap(); @@ -1813,11 +1846,13 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type writeln!(w, "/// Frees any resources used by the {}", e.ident).unwrap(); writeln!(w, "#[no_mangle]\npub extern \"C\" fn {}_free(this_ptr: {}) {{ }}", e.ident, e.ident).unwrap(); } - writeln!(w, "/// Creates a copy of the {}", e.ident).unwrap(); - writeln!(w, "#[no_mangle]").unwrap(); - writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{", e.ident, e.ident, e.ident).unwrap(); - writeln!(w, "\torig.clone()").unwrap(); - writeln!(w, "}}").unwrap(); + if is_clonable { + writeln!(w, "/// Creates a copy of the {}", e.ident).unwrap(); + writeln!(w, "#[no_mangle]").unwrap(); + writeln!(w, "pub extern \"C\" fn {}_clone(orig: &{}) -> {} {{", e.ident, e.ident, e.ident).unwrap(); + writeln!(w, "\torig.clone()").unwrap(); + writeln!(w, "}}").unwrap(); + } w.write_all(&constr).unwrap(); write_cpp_wrapper(cpp_headers, &format!("{}", e.ident), needs_free, None); } @@ -2046,6 +2081,49 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a> } } + +/// Walk the FullLibraryAST, determining if impl aliases need to be marked cloneable. +fn walk_ast_second_pass<'a>(ast_storage: &'a FullLibraryAST, crate_types: &CrateTypes<'a>) { + for (module, astmod) in ast_storage.modules.iter() { + let orig_crate = module.splitn(2, "::").next().unwrap(); + let ASTModule { ref attrs, ref items, .. } = astmod; + assert_eq!(export_status(&attrs), ExportStatus::Export); + + let import_resolver = ImportResolver::new(orig_crate, &ast_storage.dependencies, module, items); + let mut types = TypeResolver::new(module, import_resolver, crate_types); + + for item in items.iter() { + match item { + syn::Item::Impl(i) => { + match export_status(&i.attrs) { + ExportStatus::Export => {}, + ExportStatus::NoExport|ExportStatus::TestOnly => continue, + ExportStatus::NotImplementable => panic!("(C-not implementable) must only appear on traits"), + } + if let Some(trait_path) = i.trait_.as_ref() { + if path_matches_nongeneric(&trait_path.1, &["core", "clone", "Clone"]) || + path_matches_nongeneric(&trait_path.1, &["Clone"]) + { + if let &syn::Type::Path(ref p) = &*i.self_ty { + if let Some(resolved_path) = types.maybe_resolve_path(&p.path, None) { + create_alias_for_impl(resolved_path, i, &mut types, |aliased_impl, types| { + if let &syn::Type::Path(ref p) = &*aliased_impl.self_ty { + if let Some(resolved_aliased_path) = types.maybe_resolve_path(&p.path, None) { + crate_types.set_clonable("crate::".to_owned() + &resolved_aliased_path); + } + } + }); + } + } + } + } + } + _ => {} + } + } + } +} + fn walk_private_mod<'a>(ast_storage: &'a FullLibraryAST, orig_crate: &str, module: String, items: &'a syn::ItemMod, crate_types: &mut CrateTypes<'a>) { let import_resolver = ImportResolver::new(orig_crate, &ast_storage.dependencies, &module, &items.content.as_ref().unwrap().1); for item in items.content.as_ref().unwrap().1.iter() { @@ -2071,7 +2149,7 @@ fn walk_private_mod<'a>(ast_storage: &'a FullLibraryAST, orig_crate: &str, modul } /// Walk the FullLibraryAST, deciding how things will be mapped and adding tracking to CrateTypes. -fn walk_ast<'a>(ast_storage: &'a FullLibraryAST, crate_types: &mut CrateTypes<'a>) { +fn walk_ast_first_pass<'a>(ast_storage: &'a FullLibraryAST, crate_types: &mut CrateTypes<'a>) { for (module, astmod) in ast_storage.modules.iter() { let ASTModule { ref attrs, ref items, submods: _ } = astmod; assert_eq!(export_status(&attrs), ExportStatus::Export); @@ -2226,7 +2304,11 @@ fn main() { // ...then walk the ASTs tracking what types we will map, and how, so that we can resolve them // when parsing other file ASTs... let mut libtypes = CrateTypes::new(&mut derived_templates, &libast); - walk_ast(&libast, &mut libtypes); + walk_ast_first_pass(&libast, &mut libtypes); + + // ... using the generated data, determine a few additional fields, specifically which type + // aliases are to be clone-able... + walk_ast_second_pass(&libast, &libtypes); // ... finally, do the actual file conversion/mapping, writing out types as we go. convert_file(&libast, &libtypes, &args[1], &mut header_file, &mut cpp_header_file);