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); } }