using System.Collections.Generic; namespace Facepunch.InteropGen; internal enum NativeSlotKind { /// Slot 0: the native error/abort callback. Error, /// A dynamic_cast from a base class to a derived class. CastFromTo, /// A dynamic_cast from a derived class back to a base class. CastToFrom, /// A native function exported to managed. Function, /// A native variable's getter. VariableGet, /// A native variable's setter. VariableSet, } /// /// One entry in the native export function-pointer table. /// internal sealed record NativeSlot( NativeSlotKind Kind, Class Class, Class BaseClass, Function Function, Variable Variable ); /// /// The single source of truth for the native export ("nativeFunctions") table layout. The C++ side /// (igen_ initializer) fills each slot with a pointer; the managed side reads each slot back into a /// delegate field; and the array size is just the slot count. Driving all three from this one ordered /// enumeration makes "size == order" true by construction, so the two emitters can never drift out of /// sync (which would silently misalign function pointers at runtime). /// internal static class NativeExportTable { public static IEnumerable Slots( Definition definition, SkipPolicy skip ) { yield return new NativeSlot( NativeSlotKind.Error, null, null, null, null ); foreach ( Class c in definition.NativeClasses ) { if ( skip.ShouldSkip( c ) ) { continue; } foreach ( Class bc in c.BaseClasses ) { yield return new NativeSlot( NativeSlotKind.CastFromTo, c, bc, null, null ); yield return new NativeSlot( NativeSlotKind.CastToFrom, c, bc, null, null ); } foreach ( Function f in c.Functions ) { yield return new NativeSlot( NativeSlotKind.Function, c, null, f, null ); } foreach ( Variable v in c.Variables ) { yield return new NativeSlot( NativeSlotKind.VariableGet, c, null, null, v ); yield return new NativeSlot( NativeSlotKind.VariableSet, c, null, null, v ); } } } }