From 37dc5e1972f08d299c91feae06557b35904ea59b Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Tue, 13 Jun 2023 21:37:43 +0200 Subject: [PATCH 1/2] [C#] replace header glue from `delegate` to `delegate*` --- src/layout/impls.rs | 70 +++++++++++---------------------------------- 1 file changed, 17 insertions(+), 53 deletions(-) diff --git a/src/layout/impls.rs b/src/layout/impls.rs index 1ac8cd82f3..8b42b7cd06 100644 --- a/src/layout/impls.rs +++ b/src/layout/impls.rs @@ -298,64 +298,28 @@ const _: () = { macro_rules! impl_CTypes { Ret::define_self(&crate::headers::languages::CSharp, definer)?; $( $An::define_self(&crate::headers::languages::CSharp, definer)?; $( $Ai::define_self(&crate::headers::languages::CSharp, definer)?; )*)? - let ref me = Self::name(&crate::headers::languages::CSharp).to_string(); - let ref mut _arg = { - let mut iter = (0 ..).map(|c| format!("_{}", c)); - move || iter.next().unwrap() - }; - definer.define_once(me, &mut |definer| writeln!(definer.out(), - concat!( - // IIUC, - // - For 32-bits / x86, - // Rust's extern "C" is the same as C#'s (default) Winapi: - // "cdecl" for Linux, and "stdcall" for Windows. - // - // - For everything else, this is param is ignored. - // I guess because both OSes agree on the calling convention? - "[UnmanagedFunctionPointer(CallingConvention.Winapi)]\n", - - "{ret_marshaler}public unsafe /* static */ delegate\n", - " {Ret}\n", - " {me} (", $("\n", - " {}{", stringify!($An), "}", $(",\n", - " {}{", stringify!($Ai), "}", )*)? - ");\n" - ),$( - $An::csharp_marshaler() - .map(|m| format!("[MarshalAs({})]\n ", m)) - .as_deref() - .unwrap_or("") - , $( - $Ai::csharp_marshaler() - .map(|m| format!("[MarshalAs({})]\n ", m)) - .as_deref() - .unwrap_or("") - , )*)? - me = me, - ret_marshaler = - Ret::csharp_marshaler() - .map(|m| format!("[return: MarshalAs({})]\n", m)) - .as_deref() - .unwrap_or("") - , - Ret = Ret::name(&crate::headers::languages::CSharp), $( - $An = $An::name_wrapping_var(&crate::headers::languages::CSharp, &_arg()), $( - $Ai = $Ai::name_wrapping_var(&crate::headers::languages::CSharp, &_arg()), )*)? - )) + Ok(()) } fn csharp_ty () -> rust::String { - Self::c_short_name().to_string() - } - - fn legacy_csharp_marshaler () - -> Option - { - // This assumes the calling convention from the above - // `UnmanagedFunctionPointer` attribute. - Some("UnmanagedType.FunctionPtr".into()) + use ::std::fmt::Write; + let mut ret = String::new(); + let fmt = &mut ret; + // FIXME: `managed`, `unmanaged`, or `unmanaged[…]`? For now, let's go with + // `unmanaged`-that-defaults-to-that-of-the-platform. + // + // Note: in order for C# to feed such a function pointer, it has to declare, + // with an annotation of: + // - `[UnmanagedCallersOnly()]` (for the default case), or + // - `[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })]` otherwise, + // a `static unsafe … cb(…) { … }` function, and then feed `&cb`. + fmt.push_str("delegate* unmanaged<"); $( + write!(fmt, "{}, ", $An::name(&crate::headers::languages::CSharp)).unwrap(); $( + write!(fmt, "{}, ", $Ai::name(&crate::headers::languages::CSharp)).unwrap(); )*)? + write!(fmt, "{}>", Ret::name(&crate::headers::languages::CSharp)).unwrap(); + ret } } } type OPAQUE_KIND = OpaqueKind::Concrete; } From a7f84f43bd27c26a10b2401a884f6aab10c36590 Mon Sep 17 00:00:00 2001 From: Daniel Henry-Mantilla Date: Tue, 13 Jun 2023 21:39:43 +0200 Subject: [PATCH 2/2] Adjust the `ffi_tests` accordingly --- ffi_tests/generated.cs | 132 +++++--------------------------- ffi_tests/tests/csharp/Tests.cs | 39 ++++++---- 2 files changed, 44 insertions(+), 127 deletions(-) diff --git a/ffi_tests/generated.cs b/ffi_tests/generated.cs index 0d89dde0b6..83483e4186 100644 --- a/ffi_tests/generated.cs +++ b/ffi_tests/generated.cs @@ -42,13 +42,6 @@ public enum Bar_t : sbyte { B = 42, } -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - void * - void_ptr_bool_fptr ( - [MarshalAs(UnmanagedType.U1)] - bool _0); - /// /// Hello, World! /// @@ -62,8 +55,7 @@ public unsafe struct next_generation_t { /// /// with function pointers and everything! /// - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_ptr_bool_fptr cb; + public delegate* unmanaged cb; } /// @@ -89,12 +81,6 @@ public unsafe partial class Ffi { Int32 async_get_ft (); } -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - void - void_void_ptr_fptr ( - void * _0); - /// /// Arc Ret> /// @@ -102,14 +88,11 @@ public unsafe /* static */ delegate public unsafe struct ArcDynFn0_void_t { public void * env_ptr; - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_void_ptr_fptr call; + public delegate* unmanaged call; - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_void_ptr_fptr release; + public delegate* unmanaged release; - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_void_ptr_fptr retain; + public delegate* unmanaged retain; } public unsafe partial class Ffi { @@ -226,16 +209,9 @@ Int32 read_foo ( foo_t /*const*/ * foo); } -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - UInt16 - uint16_uint8_fptr ( - byte _0); - public unsafe partial class Ffi { - [return: MarshalAs(UnmanagedType.FunctionPtr)] [DllImport(RustLib, ExactSpelling = true)] public static unsafe extern - uint16_uint8_fptr returns_a_fn_ptr (); + delegate* unmanaged returns_a_fn_ptr (); } /// @@ -265,18 +241,6 @@ public struct Erased_t { #pragma warning restore 0169 } -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - void - void_Erased_ptr_fptr ( - Erased_t * _0); - -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - Erased_t * - Erased_ptr_Erased_const_ptr_fptr ( - Erased_t /*const*/ * _0); - /// /// An FFI-safe Poll<()>. /// @@ -285,20 +249,11 @@ public enum PollFuture_t : sbyte { Pending = -1, } -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - PollFuture_t - PollFuture_Erased_ptr_Opaque_Context_ptr_fptr ( - Erased_t * _0, - Opaque_Context_t * _1); - [StructLayout(LayoutKind.Sequential, Size = 16)] public unsafe struct FfiFutureVTable_t { - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_Erased_ptr_fptr release_vptr; + public delegate* unmanaged release_vptr; - [MarshalAs(UnmanagedType.FunctionPtr)] - public PollFuture_Erased_ptr_Opaque_Context_ptr_fptr dyn_poll; + public delegate* unmanaged dyn_poll; } [StructLayout(LayoutKind.Sequential, Size = 24)] @@ -308,13 +263,6 @@ public unsafe struct VirtualPtr__Erased_ptr_FfiFutureVTable_t { public FfiFutureVTable_t vtable; } -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - VirtualPtr__Erased_ptr_FfiFutureVTable_t - VirtualPtr__Erased_ptr_FfiFutureVTable_Erased_const_ptr_VirtualPtr__Erased_ptr_FfiFutureVTable_fptr ( - Erased_t /*const*/ * _0, - VirtualPtr__Erased_ptr_FfiFutureVTable_t _1); - /// /// Box Ret> /// @@ -322,31 +270,14 @@ public unsafe /* static */ delegate public unsafe struct BoxDynFnMut0_void_t { public void * env_ptr; - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_void_ptr_fptr call; + public delegate* unmanaged call; - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_void_ptr_fptr free; + public delegate* unmanaged free; } -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - VirtualPtr__Erased_ptr_FfiFutureVTable_t - VirtualPtr__Erased_ptr_FfiFutureVTable_Erased_const_ptr_BoxDynFnMut0_void_fptr ( - Erased_t /*const*/ * _0, - BoxDynFnMut0_void_t _1); - -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - void - void_Erased_const_ptr_VirtualPtr__Erased_ptr_FfiFutureVTable_fptr ( - Erased_t /*const*/ * _0, - VirtualPtr__Erased_ptr_FfiFutureVTable_t _1); - [StructLayout(LayoutKind.Sequential, Size = 8)] public unsafe struct DropGlueVTable_t { - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_Erased_ptr_fptr release_vptr; + public delegate* unmanaged release_vptr; } [StructLayout(LayoutKind.Sequential, Size = 16)] @@ -356,31 +287,19 @@ public unsafe struct VirtualPtr__Erased_ptr_DropGlueVTable_t { public DropGlueVTable_t vtable; } -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - VirtualPtr__Erased_ptr_DropGlueVTable_t - VirtualPtr__Erased_ptr_DropGlueVTable_Erased_const_ptr_fptr ( - Erased_t /*const*/ * _0); - [StructLayout(LayoutKind.Sequential, Size = 48)] public unsafe struct FfiFutureExecutorVTable_t { - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_Erased_ptr_fptr release_vptr; + public delegate* unmanaged release_vptr; - [MarshalAs(UnmanagedType.FunctionPtr)] - public Erased_ptr_Erased_const_ptr_fptr retain_vptr; + public delegate* unmanaged retain_vptr; - [MarshalAs(UnmanagedType.FunctionPtr)] - public VirtualPtr__Erased_ptr_FfiFutureVTable_Erased_const_ptr_VirtualPtr__Erased_ptr_FfiFutureVTable_fptr dyn_spawn; + public delegate* unmanaged dyn_spawn; - [MarshalAs(UnmanagedType.FunctionPtr)] - public VirtualPtr__Erased_ptr_FfiFutureVTable_Erased_const_ptr_BoxDynFnMut0_void_fptr dyn_spawn_blocking; + public delegate* unmanaged dyn_spawn_blocking; - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_Erased_const_ptr_VirtualPtr__Erased_ptr_FfiFutureVTable_fptr dyn_block_on; + public delegate* unmanaged dyn_block_on; - [MarshalAs(UnmanagedType.FunctionPtr)] - public VirtualPtr__Erased_ptr_DropGlueVTable_Erased_const_ptr_fptr dyn_enter; + public delegate* unmanaged dyn_enter; } [StructLayout(LayoutKind.Sequential, Size = 56)] @@ -396,13 +315,6 @@ Int32 test_spawner ( VirtualPtr__Erased_ptr_FfiFutureExecutorVTable_t executor); } -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - void - void_void_ptr_char_const_ptr_fptr ( - void * _0, - byte /*const*/ * _1); - /// /// &'lt mut (dyn 'lt + Send + FnMut(A1) -> Ret) /// @@ -410,8 +322,7 @@ public unsafe /* static */ delegate public unsafe struct RefDynFnMut1_void_char_const_ptr_t { public void * env_ptr; - [MarshalAs(UnmanagedType.FunctionPtr)] - public void_void_ptr_char_const_ptr_fptr call; + public delegate* unmanaged call; } public unsafe partial class Ffi { @@ -426,18 +337,11 @@ void with_concat ( RefDynFnMut1_void_char_const_ptr_t cb); } -[UnmanagedFunctionPointer(CallingConvention.Winapi)] -public unsafe /* static */ delegate - void - void_foo_ptr_fptr ( - foo_t * _0); - public unsafe partial class Ffi { [return: MarshalAs(UnmanagedType.U1)] [DllImport(RustLib, ExactSpelling = true)] public static unsafe extern bool with_foo ( - [MarshalAs(UnmanagedType.FunctionPtr)] - void_foo_ptr_fptr cb); + delegate* unmanaged cb); } diff --git a/ffi_tests/tests/csharp/Tests.cs b/ffi_tests/tests/csharp/Tests.cs index 63f5a3b570..a71dc3fc93 100644 --- a/ffi_tests/tests/csharp/Tests.cs +++ b/ffi_tests/tests/csharp/Tests.cs @@ -1,8 +1,11 @@ using System; -using System.Runtime.InteropServices; +using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text; using FfiTests; + static class Tests { public unsafe delegate R WithUTF8Continuation(byte * _); @@ -63,19 +66,29 @@ static void Main(string[] _) // test with_concat unsafe { - string s = null; + var s = new List(); + var handle = GCHandle.Alloc(s); + + [UnmanagedCallersOnly()] + static unsafe void cb(void * ctx, byte /*const*/ * p) { + GCHandle handle = GCHandle.FromIntPtr((IntPtr) ctx); + var s = (List)handle.Target; + s.Add(Marshal.PtrToStringUTF8((IntPtr)p)); + } + s1.WithUTF8(p1 => s2.WithUTF8(p2 => { Ffi.with_concat( p1, p2, - new RefDynFnMut1_void_char_const_ptr_t { env_ptr = (void *) 0xbad00, call = (void * _, - byte * p) => { - s = Marshal.PtrToStringUTF8((IntPtr)p); - }, - }); + new RefDynFnMut1_void_char_const_ptr_t { + env_ptr = (void *)(IntPtr)handle, + call = &cb, + } + ); return 0; })); - Trace.Assert(s == s1 + s2); + handle.Free(); + Trace.Assert(s[0] == s1 + s2); } // test max @@ -110,16 +123,16 @@ static void Main(string[] _) Ffi.free_foo(foo); Ffi.free_foo(null); - bool called = false; - Ffi.with_foo((foo_t * foo) => { + [UnmanagedCallersOnly()] + static unsafe void cb(foo_t * foo) { Trace.Assert( Ffi.read_foo(foo) == 42 ); - called = true; - }); - Trace.Assert(called); + } + + Ffi.with_foo(&cb); } // test constant