CPF/CPF.Mac/Mac/ObjCRuntime/Selector.cs
2023-11-21 23:05:03 +08:00

147 lines
3.7 KiB
C#

using System;
using System.Runtime.InteropServices;
namespace CPF.Mac.ObjCRuntime
{
[StructLayout(LayoutKind.Sequential)]
public class Selector : IEquatable<Selector>
{
[MonoNativeFunctionWrapper]
private delegate int getFrameLengthDelegate(IntPtr @this, IntPtr sel);
public static readonly IntPtr Init = GetHandle("init");
public static readonly IntPtr InitWithCoder = GetHandle("initWithCoder:");
private static IntPtr MethodSignatureForSelector = GetHandle("methodSignatureForSelector:");
private static IntPtr FrameLength = GetHandle("frameLength");
internal static IntPtr RetainCount = GetHandle("retainCount");
internal const string Alloc = "alloc";
internal const string Release = "release";
internal const string Retain = "retain";
internal const string Autorelease = "autorelease";
internal const string DoesNotRecognizeSelector = "doesNotRecognizeSelector:";
internal const string PerformSelectorOnMainThreadWithObjectWaitUntilDone = "performSelectorOnMainThread:withObject:waitUntilDone:";
internal const string PerformSelectorWithObjectAfterDelay = "performSelector:withObject:afterDelay:";
internal static IntPtr AllocHandle = GetHandle("alloc");
internal static IntPtr ReleaseHandle = GetHandle("release");
internal static IntPtr RetainHandle = GetHandle("retain");
internal static IntPtr AutoreleaseHandle = GetHandle("autorelease");
internal static IntPtr DoesNotRecognizeSelectorHandle = GetHandle("doesNotRecognizeSelector:");
internal static IntPtr PerformSelectorOnMainThreadWithObjectWaitUntilDoneHandle = GetHandle("performSelectorOnMainThread:withObject:waitUntilDone:");
internal static IntPtr PerformSelectorWithObjectAfterDelayHandle = GetHandle("performSelector:withObject:afterDelay:");
internal IntPtr handle;
public IntPtr Handle => handle;
public string Name => Messaging.StringFromNativeUtf8(sel_getName(handle));
public Selector(IntPtr sel)
: this(sel, check: true)
{
}
internal Selector(IntPtr sel, bool check)
{
if (check && !sel_isMapped(sel))
{
throw new ArgumentException("sel is not a selector handle.");
}
handle = sel;
}
public Selector(string name, bool alloc)
{
handle = GetHandle(name);
}
public Selector(string name)
: this(name, alloc: false)
{
}
[MonoPInvokeCallback(typeof(getFrameLengthDelegate))]
public static int GetFrameLength(IntPtr @this, IntPtr sel)
{
return Messaging.int_objc_msgSend(Messaging.IntPtr_objc_msgSend_IntPtr(@this, MethodSignatureForSelector, sel), FrameLength);
}
public static Selector Register(IntPtr handle)
{
return new Selector(handle);
}
public static bool operator !=(Selector left, Selector right)
{
return !(left == right);
}
public static bool operator ==(Selector left, Selector right)
{
if ((object)left == null)
{
return (object)right == null;
}
if ((object)right == null)
{
return false;
}
return left.handle == right.handle;
}
public override bool Equals(object right)
{
return Equals(right as Selector);
}
public bool Equals(Selector right)
{
if (right == null)
{
return false;
}
return handle == right.handle;
}
public override int GetHashCode()
{
return (int)handle;
}
public static Selector FromHandle(IntPtr sel)
{
if (!sel_isMapped(sel))
{
return null;
}
return new Selector(sel, check: false);
}
[DllImport("/usr/lib/libobjc.dylib")]
private static extern IntPtr sel_getName(IntPtr sel);
[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "sel_registerName")]
public static extern IntPtr GetHandle(string name);
[DllImport("/usr/lib/libobjc.dylib")]
private static extern bool sel_isMapped(IntPtr sel);
}
}