using System.Runtime.InteropServices; namespace NucleicProtocol.Interop; public enum ProtocolResult { Ok = 0, InvalidArgument = -1, InvalidState = -2, DecodeError = -3, Unsupported = -4, } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void NativeProtocolCallback(nint context, nint utf8Json); /// Injectable native surface: production delegates to the Swift DLL; tests use an in-memory /// implementation and exercise callback lifetime without loading a platform binary. public interface INativeProtocol { nint ClientCreate(string configurationJson); void ClientSetCallbacks( nint handle, NativeProtocolCallback? eventCallback, NativeProtocolCallback? stateCallback, nint context); int ClientConnectLocal(nint handle, string rendezvousJson); int ClientConnectRemote(nint handle, string endpointJson); int ClientPair(nint handle, string pairingCode); int ClientSendIntent(nint handle, string clientMessageJson); void ClientClose(nint handle); nint ProjectionCreate(); nint ProjectionApply(nint projection, string hostMessageJson); void ProjectionFree(nint projection); string CopyAndFreeString(nint value); } internal sealed class PInvokeNativeProtocol : INativeProtocol { public static PInvokeNativeProtocol Instance { get; } = new(); private PInvokeNativeProtocol() { } public nint ClientCreate(string json) => NativeMethods.np_client_create(json); public void ClientSetCallbacks( nint handle, NativeProtocolCallback? eventCallback, NativeProtocolCallback? stateCallback, nint context) => NativeMethods.np_client_set_callbacks(handle, eventCallback, stateCallback, context); public int ClientConnectLocal(nint handle, string json) => NativeMethods.np_client_connect_local(handle, json); public int ClientConnectRemote(nint handle, string json) => NativeMethods.np_client_connect_remote(handle, json); public int ClientPair(nint handle, string code) => NativeMethods.np_client_pair(handle, code); public int ClientSendIntent(nint handle, string json) => NativeMethods.np_client_send_intent(handle, json); public void ClientClose(nint handle) => NativeMethods.np_client_close(handle); public nint ProjectionCreate() => NativeMethods.np_projection_create(); public nint ProjectionApply(nint projection, string json) => NativeMethods.np_projection_apply(projection, json); public void ProjectionFree(nint projection) => NativeMethods.np_projection_free(projection); public string CopyAndFreeString(nint value) { if (value == 0) throw new InvalidOperationException("native protocol returned NULL"); try { return Marshal.PtrToStringUTF8(value) ?? string.Empty; } finally { NativeMethods.np_free(value); } } private static class NativeMethods { private const string Dll = "NucleicProtocolC"; [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern nint np_client_create( [MarshalAs(UnmanagedType.LPUTF8Str)] string configurationJson); [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern void np_client_set_callbacks( nint handle, NativeProtocolCallback? eventCallback, NativeProtocolCallback? stateCallback, nint context); [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern int np_client_connect_local( nint handle, [MarshalAs(UnmanagedType.LPUTF8Str)] string rendezvousJson); [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern int np_client_connect_remote( nint handle, [MarshalAs(UnmanagedType.LPUTF8Str)] string endpointJson); [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern int np_client_pair( nint handle, [MarshalAs(UnmanagedType.LPUTF8Str)] string pairingCode); [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern int np_client_send_intent( nint handle, [MarshalAs(UnmanagedType.LPUTF8Str)] string clientMessageJson); [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern void np_client_close(nint handle); [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern nint np_projection_create(); [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern nint np_projection_apply( nint projection, [MarshalAs(UnmanagedType.LPUTF8Str)] string hostMessageJson); [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern void np_projection_free(nint projection); [DllImport(Dll, CallingConvention = CallingConvention.Cdecl)] internal static extern void np_free(nint value); } }