using System.Reflection;
using System.Runtime.InteropServices;
namespace WhiteMagic;
///
/// Computes and caches marshal-related metadata for type
/// exactly once. and
/// branch on these cached flags to decide between blittable Span/MemoryMarshal
/// paths and the fallback marshal path.
///
/// The type to cache metadata for.
public static class MarshalCache
{
/// The unmanaged size of in bytes.
public static readonly int Size;
/// The unmanaged size of as an unsigned integer.
public static readonly uint SizeU;
///
/// when has at least one field
/// decorated with , meaning it cannot be copied
/// via a simple pointer dereference.
///
public static readonly bool TypeRequiresMarshal;
/// when is .
public static readonly bool IsIntPtr;
/// The underlying type code of .
public static readonly TypeCode TypeCode;
///
/// The effective type that the marshaler uses. For an enum this is the underlying
/// integer type; for all other types it is itself.
///
public static readonly Type RealType;
static MarshalCache()
{
TypeCode = Type.GetTypeCode(typeof(T));
if (typeof(T) == typeof(bool))
{
Size = 1;
RealType = typeof(T);
}
else if (typeof(T).IsEnum)
{
Type underlying = typeof(T).GetEnumUnderlyingType();
Size = Marshal.SizeOf(underlying);
RealType = underlying;
TypeCode = Type.GetTypeCode(underlying);
}
else
{
Size = Marshal.SizeOf(typeof(T));
RealType = typeof(T);
}
SizeU = (uint)Size;
IsIntPtr = RealType == typeof(IntPtr);
TypeRequiresMarshal =
RealType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Any(f => f.GetCustomAttributes(typeof(MarshalAsAttribute), true).Length != 0);
}
}