Skip to content

Commit ce56152

Browse files
committed
[bindings] Figure out in-file structs and enums before processing
Previously, types which were declared and used in the same file would fail if the use was before the declaration. This makes sense in a few cases where a "parent" class returns a reference to a "child" class and there's no reason we shouldn't support it. This change adds a second pass to our file processing which gathers the structs and enums whicha re declared in the file and adds them to the type resolver first, before doing the real conversion.
1 parent b2bf57e commit ce56152

File tree

1 file changed

+45
-11
lines changed

1 file changed

+45
-11
lines changed

c-bindings-gen/src/main.rs

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -500,21 +500,28 @@ fn writeln_opaque<W: std::io::Write>(w: &mut W, ident: &syn::Ident, struct_name:
500500
write_cpp_wrapper(cpp_headers, &format!("{}", ident), true);
501501
}
502502

503-
/// Writes out all the relevant mappings for a Rust struct, deferring to writeln_opaque to generate
504-
/// the struct itself, and then writing getters and setters for public, understood-type fields and
505-
/// a constructor if every field is public.
506-
fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct, types: &mut TypeResolver<'b, 'a>, extra_headers: &mut File, cpp_headers: &mut File) {
507-
let struct_name = &format!("{}", s.ident);
503+
fn declare_struct<'a, 'b>(s: &'a syn::ItemStruct, types: &mut TypeResolver<'b, 'a>) -> bool {
508504
let export = export_status(&s.attrs);
509505
match export {
510506
ExportStatus::Export => {},
511-
ExportStatus::TestOnly => return,
507+
ExportStatus::TestOnly => return false,
512508
ExportStatus::NoExport => {
513509
types.struct_ignored(&s.ident);
514-
return;
510+
return false;
515511
}
516512
}
517513

514+
types.struct_imported(&s.ident, format!("{}", s.ident));
515+
true
516+
}
517+
518+
/// Writes out all the relevant mappings for a Rust struct, deferring to writeln_opaque to generate
519+
/// the struct itself, and then writing getters and setters for public, understood-type fields and
520+
/// a constructor if every field is public.
521+
fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct, types: &mut TypeResolver<'b, 'a>, extra_headers: &mut File, cpp_headers: &mut File) {
522+
if !declare_struct(s, types) { return; }
523+
524+
let struct_name = &format!("{}", s.ident);
518525
writeln_opaque(w, &s.ident, struct_name, &s.generics, &s.attrs, types, extra_headers, cpp_headers);
519526

520527
eprintln!("exporting fields for {}", struct_name);
@@ -598,8 +605,6 @@ fn writeln_struct<'a, 'b, W: std::io::Write>(w: &mut W, s: &'a syn::ItemStruct,
598605
writeln!(w, "\t}})), is_owned: true }}\n}}").unwrap();
599606
}
600607
}
601-
602-
types.struct_imported(&s.ident, struct_name.clone());
603608
}
604609

605610
/// Prints a relevant conversion for impl *
@@ -916,6 +921,19 @@ fn is_enum_opaque(e: &syn::ItemEnum) -> bool {
916921
false
917922
}
918923

924+
fn declare_enum<'a, 'b>(e: &'a syn::ItemEnum, types: &mut TypeResolver<'b, 'a>) {
925+
match export_status(&e.attrs) {
926+
ExportStatus::Export => {},
927+
ExportStatus::NoExport|ExportStatus::TestOnly => return,
928+
}
929+
930+
if is_enum_opaque(e) {
931+
types.enum_ignored(&e.ident);
932+
} else {
933+
types.mirrored_enum_declared(&e.ident);
934+
}
935+
}
936+
919937
/// Print a mapping of an enum. If all of the enum's fields are C-mapped in some form (or the enum
920938
/// is unitary), we generate an equivalent enum with all types replaced with their C mapped
921939
/// versions followed by conversion functions which map between the Rust version and the C mapped
@@ -929,15 +947,13 @@ fn writeln_enum<'a, 'b, W: std::io::Write>(w: &mut W, e: &'a syn::ItemEnum, type
929947
if is_enum_opaque(e) {
930948
eprintln!("Skipping enum {} as it contains non-unit fields", e.ident);
931949
writeln_opaque(w, &e.ident, &format!("{}", e.ident), &e.generics, &e.attrs, types, extra_headers, cpp_headers);
932-
types.enum_ignored(&e.ident);
933950
return;
934951
}
935952
writeln_docs(w, &e.attrs, "");
936953

937954
if e.generics.lt_token.is_some() {
938955
unimplemented!();
939956
}
940-
types.mirrored_enum_declared(&e.ident);
941957

942958
let mut needs_free = false;
943959

@@ -1166,9 +1182,27 @@ fn convert_file<'a, 'b>(libast: &'a FullLibraryAST, crate_types: &mut CrateTypes
11661182

11671183
let mut type_resolver = TypeResolver::new(orig_crate, module, crate_types);
11681184

1185+
// First pass over the items and fill in imports and file-declared objects in the type resolver
11691186
for item in syntax.items.iter() {
11701187
match item {
11711188
syn::Item::Use(u) => type_resolver.process_use(&mut out, &u),
1189+
syn::Item::Struct(s) => {
1190+
if let syn::Visibility::Public(_) = s.vis {
1191+
declare_struct(&s, &mut type_resolver);
1192+
}
1193+
},
1194+
syn::Item::Enum(e) => {
1195+
if let syn::Visibility::Public(_) = e.vis {
1196+
declare_enum(&e, &mut type_resolver);
1197+
}
1198+
},
1199+
_ => {},
1200+
}
1201+
}
1202+
1203+
for item in syntax.items.iter() {
1204+
match item {
1205+
syn::Item::Use(_) => {}, // Handled above
11721206
syn::Item::Static(_) => {},
11731207
syn::Item::Enum(e) => {
11741208
if let syn::Visibility::Public(_) = e.vis {

0 commit comments

Comments
 (0)