Skip to content

Commit 7059159

Browse files
committed
Handle multiple impls of the same trait in the same file
This should be easy, but we end up with redundant `use` statements. Thus, we instead track which use statements we want and put them at the end when generating new files
1 parent 50af954 commit 7059159

File tree

1 file changed

+17
-12
lines changed

1 file changed

+17
-12
lines changed

c-bindings-gen/src/main.rs

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
//! It also generates relevant memory-management functions and free-standing functions with
1919
//! parameters mapped.
2020
21-
use std::collections::{HashMap, hash_map};
21+
use std::collections::{HashMap, hash_map, HashSet};
2222
use std::env;
2323
use std::fs::File;
2424
use std::io::{Read, Write};
@@ -875,7 +875,7 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
875875
/// Trait struct containing a pointer to the passed struct's inner field and the wrapper functions.
876876
///
877877
/// A few non-crate Traits are hard-coded including Default.
878-
fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut TypeResolver) {
878+
fn writeln_impl<W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRandomHash>, i: &syn::ItemImpl, types: &mut TypeResolver) {
879879
match export_status(&i.attrs) {
880880
ExportStatus::Export => {},
881881
ExportStatus::NoExport|ExportStatus::TestOnly => return,
@@ -979,11 +979,11 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
979979
// type-conversion logic without actually knowing the concrete native type.
980980
if !resolved_path.starts_with(types.module_path) {
981981
if !first_seg_is_stdlib(resolved_path.split("::").next().unwrap()) {
982-
writeln!(w, "use crate::{}::native{} as native{};", resolved_path.rsplitn(2, "::").skip(1).next().unwrap(), ident, ident).unwrap();
983-
writeln!(w, "use crate::{};", resolved_path).unwrap();
984-
writeln!(w, "use crate::{}_free_void;", resolved_path).unwrap();
982+
w_uses.insert(format!("use crate::{}::native{} as native{};", resolved_path.rsplitn(2, "::").skip(1).next().unwrap(), ident, ident));
983+
w_uses.insert(format!("use crate::{};", resolved_path));
984+
w_uses.insert(format!("use crate::{}_free_void;", resolved_path));
985985
} else {
986-
writeln!(w, "use {} as native{};", resolved_path, ident).unwrap();
986+
w_uses.insert(format!("use {} as native{};", resolved_path, ident));
987987
}
988988
}
989989
writeln!(w, "impl From<native{}> for crate::{} {{", ident, full_trait_path).unwrap();
@@ -1407,7 +1407,7 @@ fn writeln_impl<W: std::io::Write>(w: &mut W, i: &syn::ItemImpl, types: &mut Typ
14071407
}
14081408
}
14091409
} else if let Some(resolved_path) = types.maybe_resolve_ident(&ident) {
1410-
create_alias_for_impl(resolved_path, i, types, move |aliased_impl, types| writeln_impl(w, &aliased_impl, types));
1410+
create_alias_for_impl(resolved_path, i, types, move |aliased_impl, types| writeln_impl(w, w_uses, &aliased_impl, types));
14111411
} else {
14121412
eprintln!("Not implementing anything for {} due to no-resolve (probably the type isn't pub)", ident);
14131413
}
@@ -1915,7 +1915,7 @@ fn writeln_fn<'a, 'b, W: std::io::Write>(w: &mut W, f: &'a syn::ItemFn, types: &
19151915
// *** File/Crate Walking Logic ***
19161916
// ********************************
19171917

1918-
fn convert_priv_mod<'a, 'b: 'a, W: std::io::Write>(w: &mut W, libast: &'b FullLibraryAST, crate_types: &CrateTypes<'b>, out_dir: &str, mod_path: &str, module: &'b syn::ItemMod) {
1918+
fn convert_priv_mod<'a, 'b: 'a, W: std::io::Write>(w: &mut W, w_uses: &mut HashSet<String, NonRandomHash>, libast: &'b FullLibraryAST, crate_types: &CrateTypes<'b>, out_dir: &str, mod_path: &str, module: &'b syn::ItemMod) {
19191919
// We want to ignore all items declared in this module (as they are not pub), but we still need
19201920
// to give the ImportResolver any use statements, so we copy them here.
19211921
let mut use_items = Vec::new();
@@ -1930,9 +1930,9 @@ fn convert_priv_mod<'a, 'b: 'a, W: std::io::Write>(w: &mut W, libast: &'b FullLi
19301930
writeln!(w, "mod {} {{\n{}", module.ident, DEFAULT_IMPORTS).unwrap();
19311931
for item in module.content.as_ref().unwrap().1.iter() {
19321932
match item {
1933-
syn::Item::Mod(m) => convert_priv_mod(w, libast, crate_types, out_dir, &format!("{}::{}", mod_path, module.ident), m),
1933+
syn::Item::Mod(m) => convert_priv_mod(w, w_uses, libast, crate_types, out_dir, &format!("{}::{}", mod_path, module.ident), m),
19341934
syn::Item::Impl(i) => {
1935-
writeln_impl(w, i, &mut types);
1935+
writeln_impl(w, w_uses, i, &mut types);
19361936
},
19371937
_ => {},
19381938
}
@@ -1959,6 +1959,7 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a>
19591959
let _ = std::fs::create_dir((&new_file_path.as_ref() as &std::path::Path).parent().unwrap());
19601960
let mut out = std::fs::OpenOptions::new().write(true).create(true).truncate(true)
19611961
.open(new_file_path).expect("Unable to open new src file");
1962+
let mut out_uses = HashSet::default();
19621963

19631964
writeln!(out, "// This file is Copyright its original authors, visible in version control").unwrap();
19641965
writeln!(out, "// history and in the source files from which this was generated.").unwrap();
@@ -2018,7 +2019,7 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a>
20182019
}
20192020
},
20202021
syn::Item::Impl(i) => {
2021-
writeln_impl(&mut out, &i, &mut type_resolver);
2022+
writeln_impl(&mut out, &mut out_uses, &i, &mut type_resolver);
20222023
},
20232024
syn::Item::Struct(s) => {
20242025
if let syn::Visibility::Public(_) = s.vis {
@@ -2031,7 +2032,7 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a>
20312032
}
20322033
},
20332034
syn::Item::Mod(m) => {
2034-
convert_priv_mod(&mut out, libast, crate_types, out_dir, &format!("{}::{}", module, m.ident), m);
2035+
convert_priv_mod(&mut out, &mut out_uses, libast, crate_types, out_dir, &format!("{}::{}", module, m.ident), m);
20352036
},
20362037
syn::Item::Const(c) => {
20372038
// Re-export any primitive-type constants.
@@ -2101,6 +2102,10 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &CrateTypes<'a>
21012102
}
21022103
}
21032104

2105+
for use_stmt in out_uses {
2106+
writeln!(out, "{}", use_stmt).unwrap();
2107+
}
2108+
21042109
out.flush().unwrap();
21052110
}
21062111
}

0 commit comments

Comments
 (0)