Added option to avoid nint/nuint types (compatibility with older C# versions).

The option is called `csharp_use_nint_types` and defaults to `true`.
	Setting it as `false` will cause csbindgen to map the appropriate types
	to `System.IntPtr` and `System.UIntPtr` (the .NET aliases for `nint` and
	`nuint`) that are supported by all C# versions.
This commit is contained in:
Marco Mastropaolo 2023-09-14 16:08:18 +02:00
parent 8861b83a97
commit 9eb88e4b34
3 changed files with 36 additions and 8 deletions

View File

@ -488,8 +488,21 @@ Rust types will map these C# types.
csbindgen is designed to return primitives that do not cause marshalling. It is better to convert from pointers to Span yourself than to do the conversion implicitly and in a black box. This is a recent trend, such as the addition of [DisableRuntimeMarshalling](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.disableruntimemarshallingattribute) from .NET 7. csbindgen is designed to return primitives that do not cause marshalling. It is better to convert from pointers to Span yourself than to do the conversion implicitly and in a black box. This is a recent trend, such as the addition of [DisableRuntimeMarshalling](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.disableruntimemarshallingattribute) from .NET 7.
Older C# version do not support `nint` and `nuint`. You can use `csharp_use_nint_types` to use `IntPtr` and `UIntPtr` in their place:
```rust
csbindgen::Builder::default()
.input_extern_file("lib.rs")
.csharp_dll_name("nativelib")
.generate_csharp_file("../dotnet/NativeMethods.g.cs")
.csharp_use_nint_types(false)
.unwrap();
```
`c_long` and `c_ulong` will convert to [CLong](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.clong), [CULong](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.culong) struct after .NET 6. If you want to convert in Unity, you will need Shim. `c_long` and `c_ulong` will convert to [CLong](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.clong), [CULong](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.culong) struct after .NET 6. If you want to convert in Unity, you will need Shim.
```csharp ```csharp
// Currently Unity is .NET Standard 2.1 so does not exist CLong and CULong // Currently Unity is .NET Standard 2.1 so does not exist CLong and CULong
namespace System.Runtime.InteropServices namespace System.Runtime.InteropServices

View File

@ -29,6 +29,7 @@ pub struct BindgenOptions {
pub csharp_if_symbol: String, pub csharp_if_symbol: String,
pub csharp_if_dll_name: String, pub csharp_if_dll_name: String,
pub csharp_use_function_pointer: bool, pub csharp_use_function_pointer: bool,
pub csharp_use_nint_types: bool,
pub csharp_imported_namespaces: Vec<String>, pub csharp_imported_namespaces: Vec<String>,
pub csharp_generate_const_filter: fn(const_name: &str) -> bool, pub csharp_generate_const_filter: fn(const_name: &str) -> bool,
} }
@ -53,6 +54,7 @@ impl Default for Builder {
csharp_if_symbol: "".to_string(), csharp_if_symbol: "".to_string(),
csharp_if_dll_name: "".to_string(), csharp_if_dll_name: "".to_string(),
csharp_use_function_pointer: true, csharp_use_function_pointer: true,
csharp_use_nint_types: true,
csharp_imported_namespaces: vec![], csharp_imported_namespaces: vec![],
csharp_generate_const_filter: |_| false, csharp_generate_const_filter: |_| false,
}, },
@ -85,7 +87,7 @@ impl Builder {
self self
} }
/// add original extern call type prefix to rust wrapper, /// add original extern call type prefix to rust wrapper,
/// `return {rust_method_type_path}::foo()` /// `return {rust_method_type_path}::foo()`
@ -185,13 +187,20 @@ impl Builder {
self self
} }
/// configure C# usage of `nint`/`nuint` in place of `System.IntPtr`/`System.UIntPtr`, default is true
/// (use `nint`/`nuint`)
pub fn csharp_use_nint_types(mut self, csharp_use_nint_types: bool) -> Builder {
self.options.csharp_use_nint_types = csharp_use_nint_types;
self
}
/// configure C# generate const, default is false /// configure C# generate const, default is false
/// equivalent to csharp_generate_const_filter(|_| csharp_generate_const) /// equivalent to csharp_generate_const_filter(|_| csharp_generate_const)
#[deprecated(note = "User csharp_generate_const_filter instead")] #[deprecated(note = "User csharp_generate_const_filter instead")]
pub fn csharp_generate_const(mut self, csharp_generate_const: bool) -> Builder { pub fn csharp_generate_const(mut self, csharp_generate_const: bool) -> Builder {
self.csharp_generate_const_filter(if csharp_generate_const { |_| true } else { |_| false }) self.csharp_generate_const_filter(if csharp_generate_const { |_| true } else { |_| false })
} }
/// configure C# generate const filter, default `|_| false` /// configure C# generate const filter, default `|_| false`
pub fn csharp_generate_const_filter(mut self, csharp_generate_const_filter: fn(const_name: &str) -> bool) -> Builder { pub fn csharp_generate_const_filter(mut self, csharp_generate_const_filter: fn(const_name: &str) -> bool) -> Builder {
self.options.csharp_generate_const_filter = csharp_generate_const_filter; self.options.csharp_generate_const_filter = csharp_generate_const_filter;

View File

@ -214,8 +214,10 @@ impl RustType {
method_name: &String, method_name: &String,
parameter_name: &String, parameter_name: &String,
) -> String { ) -> String {
fn convert_type_name(type_name: &str) -> String { fn convert_type_name(type_name: &str, options: &BindgenOptions) -> String {
let temp_string: String; let temp_string: String;
let use_nint_types = options.csharp_use_nint_types;
let name = match type_name { let name = match type_name {
// rust primitives // rust primitives
"i8" => "sbyte", "i8" => "sbyte",
@ -223,7 +225,8 @@ impl RustType {
"i32" => "int", "i32" => "int",
"i64" => "long", "i64" => "long",
"i128" => "Int128", // .NET 7 "i128" => "Int128", // .NET 7
"isize" => "nint", // C# 9.0 "isize" if use_nint_types => "nint", // C# 9.0
"isize" => "System.IntPtr", // C# 9.0
"u8" => "byte", "u8" => "byte",
"u16" => "ushort", "u16" => "ushort",
"u32" => "uint", "u32" => "uint",
@ -233,7 +236,8 @@ impl RustType {
"f64" => "double", "f64" => "double",
"bool" => "bool", "bool" => "bool",
"char" => "uint", "char" => "uint",
"usize" => "nuint", // C# 9.0 "usize" if use_nint_types => "nuint", // C# 9.0
"usize" => "System.UIntPtr",
"()" => "void", "()" => "void",
// std::os::raw https://doc.rust-lang.org/std/os/raw/index.html // std::os::raw https://doc.rust-lang.org/std/os/raw/index.html
// std::ffi::raw https://doc.rust-lang.org/core/ffi/index.html // std::ffi::raw https://doc.rust-lang.org/core/ffi/index.html
@ -258,13 +262,15 @@ impl RustType {
"NonZeroI32" => "int", "NonZeroI32" => "int",
"NonZeroI64" => "long", "NonZeroI64" => "long",
"NonZeroI128" => "Int128", "NonZeroI128" => "Int128",
"NonZeroIsize" => "nint", "NonZeroIsize" if use_nint_types => "nint",
"NonZeroIsize" => "System.IntPtr",
"NonZeroU8" => "byte", "NonZeroU8" => "byte",
"NonZeroU16" => "ushort", "NonZeroU16" => "ushort",
"NonZeroU32" => "uint", "NonZeroU32" => "uint",
"NonZeroU64" => "ulong", "NonZeroU64" => "ulong",
"NonZeroU128" => "UInt128", "NonZeroU128" => "UInt128",
"NonZeroUsize" => "nuint", "NonZeroUsize" if use_nint_types => "nuint",
"NonZeroUsize" => "System.UIntPtr",
_ => { _ => {
temp_string = escape_name(type_name); temp_string = escape_name(type_name);
temp_string.as_str() temp_string.as_str()
@ -289,7 +295,7 @@ impl RustType {
parameter_name, parameter_name,
) )
} else { } else {
convert_type_name(use_type.type_name.as_str()).to_string() convert_type_name(use_type.type_name.as_str(), options).to_string()
}; };
let mut sb = String::new(); let mut sb = String::new();