mirror of
https://github.com/Sarsoo/csbindgen.git
synced 2024-12-23 06:56:27 +00:00
v1.1
This commit is contained in:
parent
e1b69be5b7
commit
5b1de23200
52
README.md
52
README.md
@ -224,7 +224,7 @@ csbindgen::Builder::default()
|
|||||||
.input_bindgen_file("src/lz4.rs") // required
|
.input_bindgen_file("src/lz4.rs") // required
|
||||||
.method_filter(|x| { x.starts_with("LZ4") } ) // optional, default: |x| !x.starts_with('_')
|
.method_filter(|x| { x.starts_with("LZ4") } ) // optional, default: |x| !x.starts_with('_')
|
||||||
.rust_method_prefix("csbindgen_") // optional, default: "csbindgen_"
|
.rust_method_prefix("csbindgen_") // optional, default: "csbindgen_"
|
||||||
.rust_file_header("use super::lz4;") // optional, default: ""
|
.rust_file_header("use super::lz4::*;") // optional, default: ""
|
||||||
.rust_method_type_path("lz4") // optional, default: ""
|
.rust_method_type_path("lz4") // optional, default: ""
|
||||||
.csharp_dll_name("lz4") // required
|
.csharp_dll_name("lz4") // required
|
||||||
.csharp_class_name("NativeMethods") // optional, default: NativeMethods
|
.csharp_class_name("NativeMethods") // optional, default: NativeMethods
|
||||||
@ -369,6 +369,8 @@ Rust types will map these C# types.
|
|||||||
| `*const T` | `T*` |
|
| `*const T` | `T*` |
|
||||||
| `*mut *mut T` | `T**` |
|
| `*mut *mut T` | `T**` |
|
||||||
| `*const *const T` | `T**` |
|
| `*const *const T` | `T**` |
|
||||||
|
| `*mut *const T` | `T**` |
|
||||||
|
| `*const *mut T` | `T**` |
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
@ -814,7 +816,53 @@ finally
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
C# to Rust would be a bit simpler to send, just pass byte* and length. In Rust, use `std::slice::from_raw_parts` to create slice. Again, the important thing is that memory allocated in Rust must release in Rust and memory allocated in C# must release in C#.
|
C# to Rust would be a bit simpler to send, just pass byte* and length. In Rust, use `std::slice::from_raw_parts` to create slice.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn csharp_to_rust_string(utf16_str: *const u16, utf16_len: i32) {
|
||||||
|
let slice = std::slice::from_raw_parts(utf16_str, utf16_len as usize);
|
||||||
|
let str = String::from_utf16(slice).unwrap();
|
||||||
|
println!("{}", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn csharp_to_rust_utf8(utf8_str: *const u8, utf8_len: i32) {
|
||||||
|
let slice = std::slice::from_raw_parts(utf8_str, utf8_len as usize);
|
||||||
|
let str = String::from_utf8_unchecked(slice.to_vec());
|
||||||
|
println!("{}", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn csharp_to_rust_bytes(bytes: *const u8, len: i32) {
|
||||||
|
let slice = std::slice::from_raw_parts(bytes, len as usize);
|
||||||
|
let vec = slice.to_vec();
|
||||||
|
println!("{:?}", vec);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
var str = "foobarbaz:あいうえお"; // JPN(Unicode)
|
||||||
|
fixed (char* p = str)
|
||||||
|
{
|
||||||
|
NativeMethods.csharp_to_rust_string((ushort*)p, str.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
var str2 = Encoding.UTF8.GetBytes("あいうえお:foobarbaz");
|
||||||
|
fixed (byte* p = str2)
|
||||||
|
{
|
||||||
|
NativeMethods.csharp_to_rust_utf8(p, str2.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes = new byte[] { 1, 10, 100, 255 };
|
||||||
|
fixed (byte* p = bytes)
|
||||||
|
{
|
||||||
|
NativeMethods.csharp_to_rust_bytes(p, bytes.Length);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Again, the important thing is that memory allocated in Rust must release in Rust and memory allocated in C# must release in C#.
|
||||||
|
|
||||||
Build Tracing
|
Build Tracing
|
||||||
---
|
---
|
||||||
|
4
csbindgen-tests/build.rs
vendored
4
csbindgen-tests/build.rs
vendored
@ -61,10 +61,10 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
csbindgen::Builder::default()
|
csbindgen::Builder::default()
|
||||||
.input_extern_file("src/lib.rs")
|
.input_extern_file("src/lib.rs")
|
||||||
.csharp_class_name("LibRust")
|
.csharp_class_name("NativeMethods")
|
||||||
.csharp_dll_name("csbindgen_tests")
|
.csharp_dll_name("csbindgen_tests")
|
||||||
.csharp_use_function_pointer(true)
|
.csharp_use_function_pointer(true)
|
||||||
.generate_csharp_file("../dotnet-sandbox/method_call.cs")
|
.generate_csharp_file("../dotnet-sandbox/NativeMethods.cs")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// csbindgen::Builder::new()
|
// csbindgen::Builder::new()
|
||||||
|
37
csbindgen-tests/src/lib.rs
vendored
37
csbindgen-tests/src/lib.rs
vendored
@ -25,7 +25,6 @@ mod lz4_ffi;
|
|||||||
// #[allow(non_camel_case_types)]
|
// #[allow(non_camel_case_types)]
|
||||||
// mod bullet3_ffi;
|
// mod bullet3_ffi;
|
||||||
|
|
||||||
|
|
||||||
// #[allow(dead_code)]
|
// #[allow(dead_code)]
|
||||||
// #[allow(non_snake_case)]
|
// #[allow(non_snake_case)]
|
||||||
// #[allow(non_camel_case_types)]
|
// #[allow(non_camel_case_types)]
|
||||||
@ -37,7 +36,6 @@ mod lz4_ffi;
|
|||||||
// #[allow(non_camel_case_types)]
|
// #[allow(non_camel_case_types)]
|
||||||
// mod quiche_ffi;
|
// mod quiche_ffi;
|
||||||
|
|
||||||
|
|
||||||
// #[allow(dead_code)]
|
// #[allow(dead_code)]
|
||||||
// #[allow(non_snake_case)]
|
// #[allow(non_snake_case)]
|
||||||
// #[allow(non_camel_case_types)]
|
// #[allow(non_camel_case_types)]
|
||||||
@ -49,10 +47,6 @@ mod lz4_ffi;
|
|||||||
// #[allow(non_camel_case_types)]
|
// #[allow(non_camel_case_types)]
|
||||||
// mod zstd_ffi;
|
// mod zstd_ffi;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type LONG_PTR = ::std::os::raw::c_longlong;
|
pub type LONG_PTR = ::std::os::raw::c_longlong;
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
@ -73,6 +67,33 @@ pub unsafe extern "C" fn nullpointer_test(p: *const u8) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn csharp_to_rust_string(utf16_str: *const u16, utf16_len: i32) {
|
||||||
|
let slice = std::slice::from_raw_parts(utf16_str, utf16_len as usize);
|
||||||
|
|
||||||
|
let str = String::from_utf16(slice).unwrap();
|
||||||
|
|
||||||
|
println!("{}", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn csharp_to_rust_utf8(utf8_str: *const u8, utf8_len: i32) {
|
||||||
|
let slice = std::slice::from_raw_parts(utf8_str, utf8_len as usize);
|
||||||
|
let str = String::from_utf8_unchecked(slice.to_vec());
|
||||||
|
println!("{}", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn csharp_to_rust_bytes(bytes: *const u8, len: i32) {
|
||||||
|
let slice = std::slice::from_raw_parts(bytes, len as usize);
|
||||||
|
let vec = slice.to_vec();
|
||||||
|
println!("{:?}", vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn callback_test(cb: extern "C" fn(a: i32) -> i32) -> i32 {
|
pub extern "C" fn callback_test(cb: extern "C" fn(a: i32) -> i32) -> i32 {
|
||||||
cb(100)
|
cb(100)
|
||||||
@ -85,11 +106,11 @@ pub extern "C" fn csharp_to_rust(cb: extern "C" fn(x: i32, y: i32) -> i32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn rust_to_csharp() -> extern fn(x: i32, y: i32) -> i32 {
|
pub extern "C" fn rust_to_csharp() -> extern "C" fn(x: i32, y: i32) -> i32 {
|
||||||
sum // return rust method
|
sum // return rust method
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn sum(x:i32, y:i32) -> i32 {
|
extern "C" fn sum(x: i32, y: i32) -> i32 {
|
||||||
x + y
|
x + y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "csbindgen"
|
name = "csbindgen"
|
||||||
version = "1.0.0"
|
version = "1.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = [
|
authors = [
|
||||||
"Yoshifumi Kawai <ils@neue.cc>",
|
"Yoshifumi Kawai <ils@neue.cc>",
|
||||||
|
@ -8,7 +8,7 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace CsBindgen
|
namespace CsBindgen
|
||||||
{
|
{
|
||||||
internal static unsafe partial class LibRust
|
internal static unsafe partial class NativeMethods
|
||||||
{
|
{
|
||||||
const string __DllName = "csbindgen_tests";
|
const string __DllName = "csbindgen_tests";
|
||||||
|
|
||||||
@ -21,6 +21,15 @@ namespace CsBindgen
|
|||||||
[DllImport(__DllName, EntryPoint = "nullpointer_test", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport(__DllName, EntryPoint = "nullpointer_test", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern void nullpointer_test(byte* p);
|
public static extern void nullpointer_test(byte* p);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "csharp_to_rust_string", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void csharp_to_rust_string(ushort* utf16_str, int utf16_len);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "csharp_to_rust_utf8", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void csharp_to_rust_utf8(byte* utf8_str, int utf8_len);
|
||||||
|
|
||||||
|
[DllImport(__DllName, EntryPoint = "csharp_to_rust_bytes", CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
public static extern void csharp_to_rust_bytes(byte* bytes, int len);
|
||||||
|
|
||||||
[DllImport(__DllName, EntryPoint = "callback_test", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport(__DllName, EntryPoint = "callback_test", CallingConvention = CallingConvention.Cdecl)]
|
||||||
public static extern int callback_test(delegate* unmanaged[Cdecl]<int, int> cb);
|
public static extern int callback_test(delegate* unmanaged[Cdecl]<int, int> cb);
|
||||||
|
|
50
dotnet-sandbox/Program.cs
vendored
50
dotnet-sandbox/Program.cs
vendored
@ -14,21 +14,45 @@ using System.Text;
|
|||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
|
|
||||||
LibRust.call_bindgen_lz4();
|
|
||||||
|
|
||||||
LibRust.alias_test1(null);
|
|
||||||
|
|
||||||
|
//NativeMethods.call_bindgen_lz4();
|
||||||
|
|
||||||
|
|
||||||
|
var str = "foobarbaz:あいうえお"; // JPN(Unicode)
|
||||||
|
fixed (char* p = str)
|
||||||
|
{
|
||||||
|
NativeMethods.csharp_to_rust_string((ushort*)p, str.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
var str2 = Encoding.UTF8.GetBytes("あいうえお:foobarbaz");
|
||||||
|
fixed (byte* p = str2)
|
||||||
|
{
|
||||||
|
NativeMethods.csharp_to_rust_utf8(p, str2.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
var bytes = new byte[] { 1, 10, 100, 255 };
|
||||||
|
fixed (byte* p = bytes)
|
||||||
|
{
|
||||||
|
NativeMethods.csharp_to_rust_bytes(p, bytes.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//NativeMethods.csharp_to_rust_utf8
|
||||||
|
//NativeMethods.alias_test1(null);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// C# -> Rust, pass static UnmanagedCallersOnly method with `&`
|
// C# -> Rust, pass static UnmanagedCallersOnly method with `&`
|
||||||
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]
|
||||||
static int Sum(int x, int y) => x + y;
|
static int Sum(int x, int y) => x + y;
|
||||||
|
|
||||||
LibRust.csharp_to_rust(&Sum);
|
NativeMethods.csharp_to_rust(&Sum);
|
||||||
|
|
||||||
// Rust -> C#, get typed delegate*
|
// Rust -> C#, get typed delegate*
|
||||||
var f = LibRust.rust_to_csharp();
|
var f = NativeMethods.rust_to_csharp();
|
||||||
|
|
||||||
var v = f(20, 30);
|
var v = f(20, 30);
|
||||||
Console.WriteLine(v); // 50
|
Console.WriteLine(v); // 50
|
||||||
@ -50,18 +74,18 @@ unsafe
|
|||||||
//Console.WriteLine(cc);
|
//Console.WriteLine(cc);
|
||||||
|
|
||||||
|
|
||||||
var context = LibRust.create_context();
|
// var context = LibRust.create_context();
|
||||||
|
|
||||||
// do anything...
|
// // do anything...
|
||||||
|
|
||||||
LibRust.delete_context(context);
|
// LibRust.delete_context(context);
|
||||||
|
|
||||||
var ctx = LibRust.create_counter_context(); // ctx = void*
|
//var ctx = LibRust.create_counter_context(); // ctx = void*
|
||||||
|
|
||||||
LibRust.insert_counter_context(ctx, 10);
|
|
||||||
LibRust.insert_counter_context(ctx, 20);
|
|
||||||
|
|
||||||
LibRust.delete_counter_context(ctx);
|
//LibRust.insert_counter_context(ctx, 10);
|
||||||
|
//LibRust.insert_counter_context(ctx, 20);
|
||||||
|
|
||||||
|
//LibRust.delete_counter_context(ctx);
|
||||||
|
|
||||||
//LibRust.insert_counter_context(ctx, 20);
|
//LibRust.insert_counter_context(ctx, 20);
|
||||||
//LibRust.insert_counter_context(ctx, 30);
|
//LibRust.insert_counter_context(ctx, 30);
|
||||||
|
Loading…
Reference in New Issue
Block a user