From 1a9c89d5c37e7eae672522eab1550c1437d9b297 Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Tue, 16 May 2023 18:57:34 -0500 Subject: [PATCH 1/2] walk module tree recursively when parsing for symbols from any rust file --- csbindgen-tests/build.rs | 8 +++++ csbindgen-tests/src/nested_module_test.rs | 31 ++++++++++++++++ csbindgen/src/parser.rs | 31 +++++++++++++--- dotnet-sandbox/NestedModuleTests.cs | 44 +++++++++++++++++++++++ 4 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 csbindgen-tests/src/nested_module_test.rs create mode 100644 dotnet-sandbox/NestedModuleTests.cs diff --git a/csbindgen-tests/build.rs b/csbindgen-tests/build.rs index 83c4b05..d03a73b 100644 --- a/csbindgen-tests/build.rs +++ b/csbindgen-tests/build.rs @@ -91,6 +91,14 @@ fn main() -> Result<(), Box> { .generate_csharp_file("../dotnet-sandbox/NativeMethods.cs") .unwrap(); + csbindgen::Builder::default() + .input_extern_file("src/nested_module_test.rs") + .csharp_class_name("NestedModuleTests") + .csharp_dll_name("csbindgen_tests_nested_module") + .csharp_use_function_pointer(true) + .generate_csharp_file("../dotnet-sandbox/NestedModuleTests.cs") + .unwrap(); + csbindgen::Builder::new() .input_bindgen_file("src/zstd.rs") .method_filter(|x| x.starts_with("ZSTD_")) diff --git a/csbindgen-tests/src/nested_module_test.rs b/csbindgen-tests/src/nested_module_test.rs new file mode 100644 index 0000000..38588fc --- /dev/null +++ b/csbindgen-tests/src/nested_module_test.rs @@ -0,0 +1,31 @@ +mod nested_mod { + #[repr(C)] + pub struct NumberStruct { + pub num: i32, + } + type NumberStructAlias = NumberStruct; + #[no_mangle] + pub extern "C" fn triple_input(input: NumberStruct) -> i32 { + input.num * 3 + } + #[no_mangle] + pub extern "C" fn triple_input_aliased(input: NumberStructAlias) -> i32 { + input.num * 3 + } + + #[repr(u8)] + pub enum NumberEnum { + One, + Two, + Three, + } + #[no_mangle] + pub extern "C" fn number_map(input: NumberEnum) -> i32 { + match input { + NumberEnum::One => 1, + NumberEnum::Two => 2, + NumberEnum::Three => 3, + _ => -1 + } + } +} \ No newline at end of file diff --git a/csbindgen/src/parser.rs b/csbindgen/src/parser.rs index f7ddeb1..0f2ff2b 100644 --- a/csbindgen/src/parser.rs +++ b/csbindgen/src/parser.rs @@ -8,12 +8,33 @@ enum FnItem { Item(syn::ItemFn), } +/// build a Vec of all Items, unless the Item is a Item::Mod, then append the Item contents of the vect +/// Do this recursively +fn depth_first_module_walk<'a>(ast: &'a Vec) -> Vec<&'a syn::Item>{ + let mut unwrapped_items : Vec<&syn::Item> = vec![]; + for item in ast { + match item { + Item::Mod(m) => match &m.content { + Some((_, items)) => { + unwrapped_items.extend(depth_first_module_walk(items)); + } + _ => {} + }, + _ => { + unwrapped_items.push(item); + } + } + } + + unwrapped_items +} + pub fn collect_foreign_method( ast: &syn::File, options: &BindgenOptions, list: &mut Vec, ) { - for item in ast.items.iter() { + for item in depth_first_module_walk(&ast.items) { if let Item::ForeignMod(m) = item { for item in m.items.iter() { if let ForeignItem::Fn(m) = item { @@ -32,7 +53,7 @@ pub fn collect_extern_method( options: &BindgenOptions, list: &mut Vec, ) { - for item in ast.items.iter() { + for item in depth_first_module_walk(&ast.items) { if let Item::Fn(m) = item { if m.sig.abi.is_some() { // has extern @@ -112,7 +133,7 @@ fn parse_method(item: FnItem, options: &BindgenOptions) -> Option } pub fn collect_type_alias(ast: &syn::File, result: &mut AliasMap) { - for item in ast.items.iter() { + for item in depth_first_module_walk(&ast.items) { if let Item::Type(t) = item { let name = t.ident.to_string(); let alias = parse_type(&t.ty); @@ -137,7 +158,7 @@ pub fn collect_type_alias(ast: &syn::File, result: &mut AliasMap) { pub fn collect_struct(ast: &syn::File, result: &mut Vec) { // collect union or struct - for item in ast.items.iter() { + for item in depth_first_module_walk(&ast.items) { if let Item::Union(t) = item { let struct_name = t.ident.to_string(); let fields = collect_fields(&t.fields); @@ -211,7 +232,7 @@ fn collect_fields_unnamed(fields: &syn::FieldsUnnamed) -> Vec { } pub fn collect_enum(ast: &syn::File, result: &mut Vec) { - for item in ast.items.iter() { + for item in depth_first_module_walk(&ast.items) { if let Item::Enum(t) = item { let mut repr = None; for attr in &t.attrs { diff --git a/dotnet-sandbox/NestedModuleTests.cs b/dotnet-sandbox/NestedModuleTests.cs new file mode 100644 index 0000000..3013429 --- /dev/null +++ b/dotnet-sandbox/NestedModuleTests.cs @@ -0,0 +1,44 @@ +// +// This code is generated by csbindgen. +// DON'T CHANGE THIS DIRECTLY. +// +#pragma warning disable CS8500 +#pragma warning disable CS8981 +using System; +using System.Runtime.InteropServices; + +namespace CsBindgen +{ + internal static unsafe partial class NestedModuleTests + { + const string __DllName = "csbindgen_tests_nested_module"; + + [DllImport(__DllName, EntryPoint = "triple_input", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern int triple_input(NumberStruct input); + + [DllImport(__DllName, EntryPoint = "triple_input_aliased", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern int triple_input_aliased(NumberStruct input); + + [DllImport(__DllName, EntryPoint = "number_map", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] + public static extern int number_map(NumberEnum input); + + + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe partial struct NumberStruct + { + public int num; + } + + + internal enum NumberEnum : byte + { + One, + Two, + Three, + } + + +} + \ No newline at end of file From ef86e0c3ab251093a09cda099a3c6f5d5239f55a Mon Sep 17 00:00:00 2001 From: Dan Miller Date: Tue, 16 May 2023 18:59:26 -0500 Subject: [PATCH 2/2] add performance suggestion --- csbindgen/src/parser.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csbindgen/src/parser.rs b/csbindgen/src/parser.rs index 0f2ff2b..6a9d486 100644 --- a/csbindgen/src/parser.rs +++ b/csbindgen/src/parser.rs @@ -9,7 +9,8 @@ enum FnItem { } /// build a Vec of all Items, unless the Item is a Item::Mod, then append the Item contents of the vect -/// Do this recursively +/// Do this recursively. +/// This is not memory-efficient, would work better with an iterator, but does not seem performance critical. fn depth_first_module_walk<'a>(ast: &'a Vec) -> Vec<&'a syn::Item>{ let mut unwrapped_items : Vec<&syn::Item> = vec![]; for item in ast {