//
// This file was autogenerated.
//



RMT_ENABLED :: 1;

RMT_ASSUME_LITTLE_ENDIAN :: 0;

RMT_USE_TINYCRT :: 0;

RMT_USE_CUDA :: 0;

RMT_USE_D3D11 :: 0;

RMT_USE_D3D12 :: 0;

RMT_USE_OPENGL :: 0;

RMT_USE_METAL :: 0;

RMT_USE_VULKAN :: 0;

RMT_USE_POSIX_THREADNAMES :: 0;

RMT_GPU_CPU_SYNC_NUM_ITERATIONS :: 16;

RMT_GPU_CPU_SYNC_SECONDS :: 30;

RMT_D3D11_RESYNC_ON_DISJOINT :: 1;

RMT_USE_INTERNAL_HASH_FUNCTION :: 1;

RMT_USE_LEGACY_ATOMICS :: 0;

RMT_TRUE :: cast(Bool) 1;
RMT_FALSE :: cast(Bool) 0;

// Boolean
Bool :: u32;

// Unsigned integer types
U8 :: u8;
U16 :: u16;
U32 :: u32;
U64 :: u64;

// Signed integer types
S8 :: u8;
S16 :: s16;
S32 :: s32;
S64 :: s64;

// Float types
F32 :: float;
F64 :: float64;

// Const, null-terminated string pointer
PStr :: *u8;

Msg_SampleTree :: struct {}
// Opaque pointer for a sample graph tree
SampleTree :: Msg_SampleTree;

Sample :: struct {}

Remotery :: struct {}

SampleType :: enum u32 {
    CPU    :: 0;
    CUDA   :: 1;
    D3D11  :: 2;
    D3D12  :: 3;
    OpenGL :: 4;
    Metal  :: 5;
    Vulkan :: 6;
    Count  :: 7;

    RMT_SampleType_CPU    :: CPU;
    RMT_SampleType_CUDA   :: CUDA;
    RMT_SampleType_D3D11  :: D3D11;
    RMT_SampleType_D3D12  :: D3D12;
    RMT_SampleType_OpenGL :: OpenGL;
    RMT_SampleType_Metal  :: Metal;
    RMT_SampleType_Vulkan :: Vulkan;
    RMT_SampleType_Count  :: Count;
}

// All possible error codes
// clang-format off
Error :: enum u32 {
    NONE                            :: 0;
    RECURSIVE_SAMPLE                :: 1;
    UNKNOWN                         :: 2;
    INVALID_INPUT                   :: 3;
    RESOURCE_CREATE_FAIL            :: 4;
    RESOURCE_ACCESS_FAIL            :: 5;
    TIMEOUT                         :: 6;

    MALLOC_FAIL                     :: 7;
    TLS_ALLOC_FAIL                  :: 8;
    VIRTUAL_MEMORY_BUFFER_FAIL      :: 9;
    CREATE_THREAD_FAIL              :: 10;
    OPEN_THREAD_HANDLE_FAIL         :: 11;

    SOCKET_INVALID_POLL             :: 12;
    SOCKET_SELECT_FAIL              :: 13;
    SOCKET_POLL_ERRORS              :: 14;
    SOCKET_SEND_FAIL                :: 15;
    SOCKET_RECV_NO_DATA             :: 16;
    SOCKET_RECV_TIMEOUT             :: 17;
    SOCKET_RECV_FAILED              :: 18;

    WEBSOCKET_HANDSHAKE_NOT_GET     :: 19;
    WEBSOCKET_HANDSHAKE_NO_VERSION  :: 20;
    WEBSOCKET_HANDSHAKE_BAD_VERSION :: 21;
    WEBSOCKET_HANDSHAKE_NO_HOST     :: 22;
    WEBSOCKET_HANDSHAKE_BAD_HOST    :: 23;
    WEBSOCKET_HANDSHAKE_NO_KEY      :: 24;
    WEBSOCKET_HANDSHAKE_BAD_KEY     :: 25;
    WEBSOCKET_HANDSHAKE_STRING_FAIL :: 26;
    WEBSOCKET_DISCONNECTED          :: 27;
    WEBSOCKET_BAD_FRAME_HEADER      :: 28;
    WEBSOCKET_BAD_FRAME_HEADER_SIZE :: 29;
    WEBSOCKET_BAD_FRAME_HEADER_MASK :: 30;
    WEBSOCKET_RECEIVE_TIMEOUT       :: 31;

    REMOTERY_NOT_CREATED            :: 32;
    SEND_ON_INCOMPLETE_PROFILE      :: 33;

    CUDA_DEINITIALIZED              :: 34;
    CUDA_NOT_INITIALIZED            :: 35;
    CUDA_INVALID_CONTEXT            :: 36;
    CUDA_INVALID_VALUE              :: 37;
    CUDA_INVALID_HANDLE             :: 38;
    CUDA_OUT_OF_MEMORY              :: 39;
    ERROR_NOT_READY                 :: 40;

    D3D11_FAILED_TO_CREATE_QUERY    :: 41;

    OPENGL_ERROR                    :: 42;

    CUDA_UNKNOWN                    :: 43;

    RMT_ERROR_NONE                            :: NONE;
    RMT_ERROR_RECURSIVE_SAMPLE                :: RECURSIVE_SAMPLE;
    RMT_ERROR_UNKNOWN                         :: UNKNOWN;
    RMT_ERROR_INVALID_INPUT                   :: INVALID_INPUT;
    RMT_ERROR_RESOURCE_CREATE_FAIL            :: RESOURCE_CREATE_FAIL;
    RMT_ERROR_RESOURCE_ACCESS_FAIL            :: RESOURCE_ACCESS_FAIL;
    RMT_ERROR_TIMEOUT                         :: TIMEOUT;

    RMT_ERROR_MALLOC_FAIL                     :: MALLOC_FAIL;
    RMT_ERROR_TLS_ALLOC_FAIL                  :: TLS_ALLOC_FAIL;
    RMT_ERROR_VIRTUAL_MEMORY_BUFFER_FAIL      :: VIRTUAL_MEMORY_BUFFER_FAIL;
    RMT_ERROR_CREATE_THREAD_FAIL              :: CREATE_THREAD_FAIL;
    RMT_ERROR_OPEN_THREAD_HANDLE_FAIL         :: OPEN_THREAD_HANDLE_FAIL;

    RMT_ERROR_SOCKET_INVALID_POLL             :: SOCKET_INVALID_POLL;
    RMT_ERROR_SOCKET_SELECT_FAIL              :: SOCKET_SELECT_FAIL;
    RMT_ERROR_SOCKET_POLL_ERRORS              :: SOCKET_POLL_ERRORS;
    RMT_ERROR_SOCKET_SEND_FAIL                :: SOCKET_SEND_FAIL;
    RMT_ERROR_SOCKET_RECV_NO_DATA             :: SOCKET_RECV_NO_DATA;
    RMT_ERROR_SOCKET_RECV_TIMEOUT             :: SOCKET_RECV_TIMEOUT;
    RMT_ERROR_SOCKET_RECV_FAILED              :: SOCKET_RECV_FAILED;

    RMT_ERROR_WEBSOCKET_HANDSHAKE_NOT_GET     :: WEBSOCKET_HANDSHAKE_NOT_GET;
    RMT_ERROR_WEBSOCKET_HANDSHAKE_NO_VERSION  :: WEBSOCKET_HANDSHAKE_NO_VERSION;
    RMT_ERROR_WEBSOCKET_HANDSHAKE_BAD_VERSION :: WEBSOCKET_HANDSHAKE_BAD_VERSION;
    RMT_ERROR_WEBSOCKET_HANDSHAKE_NO_HOST     :: WEBSOCKET_HANDSHAKE_NO_HOST;
    RMT_ERROR_WEBSOCKET_HANDSHAKE_BAD_HOST    :: WEBSOCKET_HANDSHAKE_BAD_HOST;
    RMT_ERROR_WEBSOCKET_HANDSHAKE_NO_KEY      :: WEBSOCKET_HANDSHAKE_NO_KEY;
    RMT_ERROR_WEBSOCKET_HANDSHAKE_BAD_KEY     :: WEBSOCKET_HANDSHAKE_BAD_KEY;
    RMT_ERROR_WEBSOCKET_HANDSHAKE_STRING_FAIL :: WEBSOCKET_HANDSHAKE_STRING_FAIL;
    RMT_ERROR_WEBSOCKET_DISCONNECTED          :: WEBSOCKET_DISCONNECTED;
    RMT_ERROR_WEBSOCKET_BAD_FRAME_HEADER      :: WEBSOCKET_BAD_FRAME_HEADER;
    RMT_ERROR_WEBSOCKET_BAD_FRAME_HEADER_SIZE :: WEBSOCKET_BAD_FRAME_HEADER_SIZE;
    RMT_ERROR_WEBSOCKET_BAD_FRAME_HEADER_MASK :: WEBSOCKET_BAD_FRAME_HEADER_MASK;
    RMT_ERROR_WEBSOCKET_RECEIVE_TIMEOUT       :: WEBSOCKET_RECEIVE_TIMEOUT;

    RMT_ERROR_REMOTERY_NOT_CREATED            :: REMOTERY_NOT_CREATED;
    RMT_ERROR_SEND_ON_INCOMPLETE_PROFILE      :: SEND_ON_INCOMPLETE_PROFILE;

    RMT_ERROR_CUDA_DEINITIALIZED              :: CUDA_DEINITIALIZED;
    RMT_ERROR_CUDA_NOT_INITIALIZED            :: CUDA_NOT_INITIALIZED;
    RMT_ERROR_CUDA_INVALID_CONTEXT            :: CUDA_INVALID_CONTEXT;
    RMT_ERROR_CUDA_INVALID_VALUE              :: CUDA_INVALID_VALUE;
    RMT_ERROR_CUDA_INVALID_HANDLE             :: CUDA_INVALID_HANDLE;
    RMT_ERROR_CUDA_OUT_OF_MEMORY              :: CUDA_OUT_OF_MEMORY;
    RMT_ERROR_ERROR_NOT_READY                 :: ERROR_NOT_READY;

    RMT_ERROR_D3D11_FAILED_TO_CREATE_QUERY    :: D3D11_FAILED_TO_CREATE_QUERY;

    RMT_ERROR_OPENGL_ERROR                    :: OPENGL_ERROR;

    RMT_ERROR_CUDA_UNKNOWN                    :: CUDA_UNKNOWN;
}

// Gets the last error message issued on the calling thread
GetLastErrorMessage :: (__args: ..Any) -> PStr #foreign remotery "rmt_GetLastErrorMessage";

// Callback function pointer types
MallocPtr :: #type (mm_context: *void, size: U32) -> *void #c_call;
ReallocPtr :: #type (mm_context: *void, ptr: *void, size: U32) -> *void #c_call;
FreePtr :: #type (mm_context: *void, ptr: *void) -> void #c_call;
InputHandlerPtr :: #type (text: *u8, _context: *void) -> void #c_call;
SampleTreeHandlerPtr :: #type (cbk_context: *void, sample_tree: *SampleTree) -> void #c_call;
PropertyHandlerPtr :: #type (cbk_context: *void, root: *Property) -> void #c_call;

// Struture to fill in to modify Remotery default settings
Settings :: struct {
    // Which port to listen for incoming connections on
    port:                           U16;

    // When this server exits it can leave the port open in TIME_WAIT state for a while. This forces
    // subsequent server bind attempts to fail when restarting. If you find restarts fail repeatedly
    // with bind attempts, set this to true to forcibly reuse the open port.
    reuse_open_port:                Bool;

    // Only allow connections on localhost?
    // For dev builds you may want to access your game from other devices but if
    // you distribute a game to your players with Remotery active, probably best
    // to limit connections to localhost.
    limit_connections_to_localhost: Bool;

    // Whether to enable runtime thread sampling that discovers which processors a thread is running
    // on. This will suspend and resume threads from outside repeatdly and inject code into each
    // thread that automatically instruments the processor.
    // Default: Enabled
    enableThreadSampler:            Bool;

    // How long to sleep between server updates, hopefully trying to give
    // a little CPU back to other threads.
    msSleepBetweenServerUpdates:    U32;

    // Size of the internal message queues Remotery uses
    // Will be rounded to page granularity of 64k
    messageQueueSizeInBytes:        U32;

    // If the user continuously pushes to the message queue, the server network
    // code won't get a chance to update unless there's an upper-limit on how
    // many messages can be consumed per loop.
    maxNbMessagesPerUpdate:         U32;

    // Callback pointers for memory allocation
    malloc:                         MallocPtr;
    realloc:                        ReallocPtr;
    free:                           FreePtr;
    mm_context:                     *void;

    // Callback pointer for receiving input from the Remotery console
    input_handler:                  InputHandlerPtr;

    // Callback pointer for traversing the sample tree graph
    sampletree_handler:             SampleTreeHandlerPtr;
    sampletree_context:             *void;

    // Callback pointer for traversing the prpperty graph
    snapshot_callback:              PropertyHandlerPtr;
    snapshot_context:               *void;

    // Context pointer that gets sent to Remotery console callback function
    input_handler_context:          *void;

    logPath:                        PStr;
}

// Structure to fill in when binding CUDA to Remotery
CUDABind :: struct {
    // The main context that all driver functions apply before each call
    _context:         *void;

    // Driver API function pointers that need to be pointed to
    // Untyped so that the CUDA headers are not required in this file
    // NOTE: These are named differently to the CUDA functions because the CUDA API has a habit of using
    // macros to point function calls to different versions, e.g. cuEventDestroy is a macro for
    // cuEventDestroy_v2.
    CtxSetCurrent:    *void;
    CtxGetCurrent:    *void;
    EventCreate:      *void;
    EventDestroy:     *void;
    EventRecord:      *void;
    EventQuery:       *void;
    EventElapsedTime: *void;
}

D3D12Bind :: struct {
    // The main device shared by all threads
    device: *void;

    // The queue command lists are executed on for profiling
    queue:  *void;
}

VulkanFunctions :: struct {
    // Instance functions
    vkGetPhysicalDeviceProperties: *void;

    // Device functions
    vkQueueSubmit:                 *void;
    vkQueueWaitIdle:               *void;
    vkCreateQueryPool:             *void;
    vkDestroyQueryPool:            *void;
    vkResetQueryPool:              *void; // vkResetQueryPool (Vulkan 1.2+ with hostQueryReset) or vkResetQueryPoolEXT (VK_EXT_host_query_reset)
    vkGetQueryPoolResults:         *void;
    vkCmdWriteTimestamp:           *void;
    vkCreateSemaphore:             *void;
    vkDestroySemaphore:            *void;
    vkSignalSemaphore:             *void; // vkSignalSemaphore (Vulkan 1.2+ with timelineSemaphore) or vkSignalSemaphoreKHR (VK_KHR_timeline_semaphore)
    vkGetSemaphoreCounterValue:    *void; // vkGetSemaphoreCounterValue (Vulkan 1.2+ with timelineSemaphore) or vkGetSemaphoreCounterValueKHR (VK_KHR_timeline_semaphore)
    vkGetCalibratedTimestampsEXT:  *void; // vkGetCalibratedTimestampsKHR (VK_KHR_calibrated_timestamps) or vkGetCalibratedTimestampsEXT (VK_EXT_calibrated_timestamps)
}

VulkanBind :: struct {
    // The physical Vulkan device, of type VkPhysicalDevice
    physical_device: *void;

    // The logical Vulkan device, of type VkDevice
    device:          *void;

    // The queue command buffers are executed on for profiling, of type VkQueue
    queue:           *void;
}

// Flags that control property behaviour
PropertyFlags :: enum u32 {
    NoFlags    :: 0;

    FrameReset :: 1;

    RMT_PropertyFlags_NoFlags    :: NoFlags;

    RMT_PropertyFlags_FrameReset :: FrameReset;
}

// All possible property types that can be recorded and sent to the viewer
PropertyType :: enum u32 {
    rmtGroup :: 0;
    rmtBool  :: 1;
    rmtS32   :: 2;
    rmtU32   :: 3;
    rmtF32   :: 4;
    rmtS64   :: 5;
    rmtU64   :: 6;
    rmtF64   :: 7;

    RMT_PropertyType_rmtGroup :: rmtGroup;
    RMT_PropertyType_rmtBool  :: rmtBool;
    RMT_PropertyType_rmtS32   :: rmtS32;
    RMT_PropertyType_rmtU32   :: rmtU32;
    RMT_PropertyType_rmtF32   :: rmtF32;
    RMT_PropertyType_rmtS64   :: rmtS64;
    RMT_PropertyType_rmtU64   :: rmtU64;
    RMT_PropertyType_rmtF64   :: rmtF64;
}

// A property value as a union of all its possible types
PropertyValue :: union {
    Bool_: Bool;
    S32_:  S32;
    U32_:  U32;
    F32_:  F32;
    S64_:  S64;
    U64_:  U64;
    F64_:  F64;
}

// Forward declaration
Property :: struct {
    // Gets set to RMT_TRUE after a property has been modified, when it gets initialised for the first time
    initialised:    Bool;

    // Runtime description
    type:           PropertyType;
    flags:          PropertyFlags;

    // Current value
    value:          PropertyValue;

    // Last frame value to see if previous value needs to be updated
    lastFrameValue: PropertyValue;

    // Previous value only if it's different from the current value, and when it changed
    prevValue:      PropertyValue;
    prevValueFrame: U32;

    // Text description
    name:           *u8;
    description:    *u8;

    // Default value for Reset calls
    defaultValue:   PropertyValue;

    // Parent link specifically placed after default value so that variadic macro can initialise it
    parent:         *Property;

    // Links within the property tree
    firstChild:     *Property;
    lastChild:      *Property;
    nextSibling:    *Property;

    // Hash for efficient sending of properties to the viewer
    nameHash:       U32;

    // Unique, persistent ID among all properties
    uniqueID:       U32;
}

PropertySetValue :: (property: *Property) -> void #foreign remotery "_rmt_PropertySetValue";
PropertyAddValue :: (property: *Property, add_value: PropertyValue) -> void #foreign remotery "_rmt_PropertyAddValue";
PropertySnapshotAll :: (__args: ..Any) -> Error #foreign remotery "_rmt_PropertySnapshotAll";
PropertyFrameResetAll :: (__args: ..Any) -> void #foreign remotery "_rmt_PropertyFrameResetAll";
HashString32 :: (s: *u8, len: s32, seed: U32) -> U32 #foreign remotery "_rmt_HashString32";

/*--------------------------------------------------------------------------------------------------------------------------------
Sample Tree API for walking `rmtSampleTree` Objects in the Sample Tree Handler.
--------------------------------------------------------------------------------------------------------------------------------*/
SampleFlags :: enum u32 {
    None        :: 0;

    Aggregate   :: 1;

    Recursive   :: 2;

    Root        :: 4;

    SendOnClose :: 8;

    RMTSF_None        :: None;

    RMTSF_Aggregate   :: Aggregate;

    RMTSF_Recursive   :: Recursive;

    RMTSF_Root        :: Root;

    RMTSF_SendOnClose :: SendOnClose;
}

// Struct to hold iterator info
SampleIterator :: struct {
    // public
    sample:  *Sample;

    // private
    initial: *Sample;
}

// Struct to hold iterator info
PropertyIterator :: struct {
    // public
    property: *Property;

    // private
    initial:  *Property;
}

Settings_ :: () -> *Settings #foreign remotery "_rmt_Settings";
CreateGlobalInstance :: (remotery: **Remotery) -> Error #foreign remotery "_rmt_CreateGlobalInstance";
DestroyGlobalInstance :: (remotery: *Remotery) -> void #foreign remotery "_rmt_DestroyGlobalInstance";
SetGlobalInstance :: (remotery: *Remotery) -> void #foreign remotery "_rmt_SetGlobalInstance";
GetGlobalInstance :: () -> *Remotery #foreign remotery "_rmt_GetGlobalInstance";
SetCurrentThreadName :: (thread_name: PStr) -> void #foreign remotery "_rmt_SetCurrentThreadName";
LogText :: (text: PStr) -> void #foreign remotery "_rmt_LogText";
BeginCPUSample :: (name: PStr, flags: U32, hash_cache: *U32) -> void #foreign remotery "_rmt_BeginCPUSample";
EndCPUSample :: () -> void #foreign remotery "_rmt_EndCPUSample";
MarkFrame :: () -> Error #foreign remotery "_rmt_MarkFrame";

// Sample iterator
IterateChildren :: (iter: *SampleIterator, sample: *Sample) -> void #foreign remotery "_rmt_IterateChildren";
IterateNext :: (iter: *SampleIterator) -> Bool #foreign remotery "_rmt_IterateNext";

// SampleTree accessors
SampleTreeGetThreadName :: (sample_tree: *SampleTree) -> *u8 #foreign remotery "_rmt_SampleTreeGetThreadName";
SampleTreeGetRootSample :: (sample_tree: *SampleTree) -> *Sample #foreign remotery "_rmt_SampleTreeGetRootSample";

// Sample accessors
SampleGetName :: (sample: *Sample) -> *u8 #foreign remotery "_rmt_SampleGetName";
SampleGetNameHash :: (sample: *Sample) -> U32 #foreign remotery "_rmt_SampleGetNameHash";
SampleGetCallCount :: (sample: *Sample) -> U32 #foreign remotery "_rmt_SampleGetCallCount";
SampleGetStart :: (sample: *Sample) -> U64 #foreign remotery "_rmt_SampleGetStart";
SampleGetTime :: (sample: *Sample) -> U64 #foreign remotery "_rmt_SampleGetTime";
SampleGetSelfTime :: (sample: *Sample) -> U64 #foreign remotery "_rmt_SampleGetSelfTime";
SampleGetColour :: (sample: *Sample, r: *U8, g: *U8, b: *U8) -> void #foreign remotery "_rmt_SampleGetColour";
SampleGetType :: (sample: *Sample) -> SampleType #foreign remotery "_rmt_SampleGetType";

// Property iterator
PropertyIterateChildren :: (iter: *PropertyIterator, property: *Property) -> void #foreign remotery "_rmt_PropertyIterateChildren";
PropertyIterateNext :: (iter: *PropertyIterator) -> Bool #foreign remotery "_rmt_PropertyIterateNext";

// Property accessors
PropertyGetType :: (property: *Property) -> PropertyType #foreign remotery "_rmt_PropertyGetType";
PropertyGetNameHash :: (property: *Property) -> U32 #foreign remotery "_rmt_PropertyGetNameHash";
PropertyGetName :: (property: *Property) -> *u8 #foreign remotery "_rmt_PropertyGetName";
PropertyGetDescription :: (property: *Property) -> *u8 #foreign remotery "_rmt_PropertyGetDescription";
PropertyGetValue :: (property: *Property) -> PropertyValue #foreign remotery "_rmt_PropertyGetValue";

#scope_file

#import "Basic"; // For assert


#run {
    {
        info := type_info(Settings);
        for info.members {
            if it.name == {
                case "port";
                    assert(it.offset_in_bytes == 0, "Settings.port has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 2, "Settings.port has unexpected size % instead of 2", it.type.runtime_size);
                case "reuse_open_port";
                    assert(it.offset_in_bytes == 4, "Settings.reuse_open_port has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Settings.reuse_open_port has unexpected size % instead of 4", it.type.runtime_size);
                case "limit_connections_to_localhost";
                    assert(it.offset_in_bytes == 8, "Settings.limit_connections_to_localhost has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Settings.limit_connections_to_localhost has unexpected size % instead of 4", it.type.runtime_size);
                case "enableThreadSampler";
                    assert(it.offset_in_bytes == 12, "Settings.enableThreadSampler has unexpected offset % instead of 12", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Settings.enableThreadSampler has unexpected size % instead of 4", it.type.runtime_size);
                case "msSleepBetweenServerUpdates";
                    assert(it.offset_in_bytes == 16, "Settings.msSleepBetweenServerUpdates has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Settings.msSleepBetweenServerUpdates has unexpected size % instead of 4", it.type.runtime_size);
                case "messageQueueSizeInBytes";
                    assert(it.offset_in_bytes == 20, "Settings.messageQueueSizeInBytes has unexpected offset % instead of 20", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Settings.messageQueueSizeInBytes has unexpected size % instead of 4", it.type.runtime_size);
                case "maxNbMessagesPerUpdate";
                    assert(it.offset_in_bytes == 24, "Settings.maxNbMessagesPerUpdate has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Settings.maxNbMessagesPerUpdate has unexpected size % instead of 4", it.type.runtime_size);
                case "malloc";
                    assert(it.offset_in_bytes == 32, "Settings.malloc has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.malloc has unexpected size % instead of 8", it.type.runtime_size);
                case "realloc";
                    assert(it.offset_in_bytes == 40, "Settings.realloc has unexpected offset % instead of 40", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.realloc has unexpected size % instead of 8", it.type.runtime_size);
                case "free";
                    assert(it.offset_in_bytes == 48, "Settings.free has unexpected offset % instead of 48", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.free has unexpected size % instead of 8", it.type.runtime_size);
                case "mm_context";
                    assert(it.offset_in_bytes == 56, "Settings.mm_context has unexpected offset % instead of 56", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.mm_context has unexpected size % instead of 8", it.type.runtime_size);
                case "input_handler";
                    assert(it.offset_in_bytes == 64, "Settings.input_handler has unexpected offset % instead of 64", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.input_handler has unexpected size % instead of 8", it.type.runtime_size);
                case "sampletree_handler";
                    assert(it.offset_in_bytes == 72, "Settings.sampletree_handler has unexpected offset % instead of 72", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.sampletree_handler has unexpected size % instead of 8", it.type.runtime_size);
                case "sampletree_context";
                    assert(it.offset_in_bytes == 80, "Settings.sampletree_context has unexpected offset % instead of 80", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.sampletree_context has unexpected size % instead of 8", it.type.runtime_size);
                case "snapshot_callback";
                    assert(it.offset_in_bytes == 88, "Settings.snapshot_callback has unexpected offset % instead of 88", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.snapshot_callback has unexpected size % instead of 8", it.type.runtime_size);
                case "snapshot_context";
                    assert(it.offset_in_bytes == 96, "Settings.snapshot_context has unexpected offset % instead of 96", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.snapshot_context has unexpected size % instead of 8", it.type.runtime_size);
                case "input_handler_context";
                    assert(it.offset_in_bytes == 104, "Settings.input_handler_context has unexpected offset % instead of 104", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.input_handler_context has unexpected size % instead of 8", it.type.runtime_size);
                case "logPath";
                    assert(it.offset_in_bytes == 112, "Settings.logPath has unexpected offset % instead of 112", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Settings.logPath has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(Settings) == 120, "Settings has size % instead of 120", size_of(Settings));
    }

    {
        info := type_info(CUDABind);
        for info.members {
            if it.name == {
                case "_context";
                    assert(it.offset_in_bytes == 0, "CUDABind._context has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "CUDABind._context has unexpected size % instead of 8", it.type.runtime_size);
                case "CtxSetCurrent";
                    assert(it.offset_in_bytes == 8, "CUDABind.CtxSetCurrent has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "CUDABind.CtxSetCurrent has unexpected size % instead of 8", it.type.runtime_size);
                case "CtxGetCurrent";
                    assert(it.offset_in_bytes == 16, "CUDABind.CtxGetCurrent has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "CUDABind.CtxGetCurrent has unexpected size % instead of 8", it.type.runtime_size);
                case "EventCreate";
                    assert(it.offset_in_bytes == 24, "CUDABind.EventCreate has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "CUDABind.EventCreate has unexpected size % instead of 8", it.type.runtime_size);
                case "EventDestroy";
                    assert(it.offset_in_bytes == 32, "CUDABind.EventDestroy has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "CUDABind.EventDestroy has unexpected size % instead of 8", it.type.runtime_size);
                case "EventRecord";
                    assert(it.offset_in_bytes == 40, "CUDABind.EventRecord has unexpected offset % instead of 40", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "CUDABind.EventRecord has unexpected size % instead of 8", it.type.runtime_size);
                case "EventQuery";
                    assert(it.offset_in_bytes == 48, "CUDABind.EventQuery has unexpected offset % instead of 48", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "CUDABind.EventQuery has unexpected size % instead of 8", it.type.runtime_size);
                case "EventElapsedTime";
                    assert(it.offset_in_bytes == 56, "CUDABind.EventElapsedTime has unexpected offset % instead of 56", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "CUDABind.EventElapsedTime has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(CUDABind) == 64, "CUDABind has size % instead of 64", size_of(CUDABind));
    }

    {
        info := type_info(D3D12Bind);
        for info.members {
            if it.name == {
                case "device";
                    assert(it.offset_in_bytes == 0, "D3D12Bind.device has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "D3D12Bind.device has unexpected size % instead of 8", it.type.runtime_size);
                case "queue";
                    assert(it.offset_in_bytes == 8, "D3D12Bind.queue has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "D3D12Bind.queue has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(D3D12Bind) == 16, "D3D12Bind has size % instead of 16", size_of(D3D12Bind));
    }

    {
        info := type_info(VulkanFunctions);
        for info.members {
            if it.name == {
                case "vkGetPhysicalDeviceProperties";
                    assert(it.offset_in_bytes == 0, "VulkanFunctions.vkGetPhysicalDeviceProperties has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkGetPhysicalDeviceProperties has unexpected size % instead of 8", it.type.runtime_size);
                case "vkQueueSubmit";
                    assert(it.offset_in_bytes == 8, "VulkanFunctions.vkQueueSubmit has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkQueueSubmit has unexpected size % instead of 8", it.type.runtime_size);
                case "vkQueueWaitIdle";
                    assert(it.offset_in_bytes == 16, "VulkanFunctions.vkQueueWaitIdle has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkQueueWaitIdle has unexpected size % instead of 8", it.type.runtime_size);
                case "vkCreateQueryPool";
                    assert(it.offset_in_bytes == 24, "VulkanFunctions.vkCreateQueryPool has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkCreateQueryPool has unexpected size % instead of 8", it.type.runtime_size);
                case "vkDestroyQueryPool";
                    assert(it.offset_in_bytes == 32, "VulkanFunctions.vkDestroyQueryPool has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkDestroyQueryPool has unexpected size % instead of 8", it.type.runtime_size);
                case "vkResetQueryPool";
                    assert(it.offset_in_bytes == 40, "VulkanFunctions.vkResetQueryPool has unexpected offset % instead of 40", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkResetQueryPool has unexpected size % instead of 8", it.type.runtime_size);
                case "vkGetQueryPoolResults";
                    assert(it.offset_in_bytes == 48, "VulkanFunctions.vkGetQueryPoolResults has unexpected offset % instead of 48", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkGetQueryPoolResults has unexpected size % instead of 8", it.type.runtime_size);
                case "vkCmdWriteTimestamp";
                    assert(it.offset_in_bytes == 56, "VulkanFunctions.vkCmdWriteTimestamp has unexpected offset % instead of 56", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkCmdWriteTimestamp has unexpected size % instead of 8", it.type.runtime_size);
                case "vkCreateSemaphore";
                    assert(it.offset_in_bytes == 64, "VulkanFunctions.vkCreateSemaphore has unexpected offset % instead of 64", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkCreateSemaphore has unexpected size % instead of 8", it.type.runtime_size);
                case "vkDestroySemaphore";
                    assert(it.offset_in_bytes == 72, "VulkanFunctions.vkDestroySemaphore has unexpected offset % instead of 72", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkDestroySemaphore has unexpected size % instead of 8", it.type.runtime_size);
                case "vkSignalSemaphore";
                    assert(it.offset_in_bytes == 80, "VulkanFunctions.vkSignalSemaphore has unexpected offset % instead of 80", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkSignalSemaphore has unexpected size % instead of 8", it.type.runtime_size);
                case "vkGetSemaphoreCounterValue";
                    assert(it.offset_in_bytes == 88, "VulkanFunctions.vkGetSemaphoreCounterValue has unexpected offset % instead of 88", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkGetSemaphoreCounterValue has unexpected size % instead of 8", it.type.runtime_size);
                case "vkGetCalibratedTimestampsEXT";
                    assert(it.offset_in_bytes == 96, "VulkanFunctions.vkGetCalibratedTimestampsEXT has unexpected offset % instead of 96", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanFunctions.vkGetCalibratedTimestampsEXT has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(VulkanFunctions) == 104, "VulkanFunctions has size % instead of 104", size_of(VulkanFunctions));
    }

    {
        info := type_info(VulkanBind);
        for info.members {
            if it.name == {
                case "physical_device";
                    assert(it.offset_in_bytes == 0, "VulkanBind.physical_device has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanBind.physical_device has unexpected size % instead of 8", it.type.runtime_size);
                case "device";
                    assert(it.offset_in_bytes == 8, "VulkanBind.device has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanBind.device has unexpected size % instead of 8", it.type.runtime_size);
                case "queue";
                    assert(it.offset_in_bytes == 16, "VulkanBind.queue has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "VulkanBind.queue has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(VulkanBind) == 24, "VulkanBind has size % instead of 24", size_of(VulkanBind));
    }

    {
        info := type_info(PropertyValue);
        for info.members {
            if it.name == {
                case "Bool_";
                    assert(it.offset_in_bytes == 0, "PropertyValue.Bool_ has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "PropertyValue.Bool_ has unexpected size % instead of 4", it.type.runtime_size);
                case "S32_";
                    assert(it.offset_in_bytes == 0, "PropertyValue.S32_ has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "PropertyValue.S32_ has unexpected size % instead of 4", it.type.runtime_size);
                case "U32_";
                    assert(it.offset_in_bytes == 0, "PropertyValue.U32_ has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "PropertyValue.U32_ has unexpected size % instead of 4", it.type.runtime_size);
                case "F32_";
                    assert(it.offset_in_bytes == 0, "PropertyValue.F32_ has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "PropertyValue.F32_ has unexpected size % instead of 4", it.type.runtime_size);
                case "S64_";
                    assert(it.offset_in_bytes == 0, "PropertyValue.S64_ has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "PropertyValue.S64_ has unexpected size % instead of 8", it.type.runtime_size);
                case "U64_";
                    assert(it.offset_in_bytes == 0, "PropertyValue.U64_ has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "PropertyValue.U64_ has unexpected size % instead of 8", it.type.runtime_size);
                case "F64_";
                    assert(it.offset_in_bytes == 0, "PropertyValue.F64_ has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "PropertyValue.F64_ has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(PropertyValue) == 8, "PropertyValue has size % instead of 8", size_of(PropertyValue));
    }

    {
        info := type_info(Property);
        for info.members {
            if it.name == {
                case "initialised";
                    assert(it.offset_in_bytes == 0, "Property.initialised has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Property.initialised has unexpected size % instead of 4", it.type.runtime_size);
                case "type";
                    assert(it.offset_in_bytes == 4, "Property.type has unexpected offset % instead of 4", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Property.type has unexpected size % instead of 4", it.type.runtime_size);
                case "flags";
                    assert(it.offset_in_bytes == 8, "Property.flags has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Property.flags has unexpected size % instead of 4", it.type.runtime_size);
                case "value";
                    assert(it.offset_in_bytes == 16, "Property.value has unexpected offset % instead of 16", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Property.value has unexpected size % instead of 8", it.type.runtime_size);
                case "lastFrameValue";
                    assert(it.offset_in_bytes == 24, "Property.lastFrameValue has unexpected offset % instead of 24", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Property.lastFrameValue has unexpected size % instead of 8", it.type.runtime_size);
                case "prevValue";
                    assert(it.offset_in_bytes == 32, "Property.prevValue has unexpected offset % instead of 32", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Property.prevValue has unexpected size % instead of 8", it.type.runtime_size);
                case "prevValueFrame";
                    assert(it.offset_in_bytes == 40, "Property.prevValueFrame has unexpected offset % instead of 40", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Property.prevValueFrame has unexpected size % instead of 4", it.type.runtime_size);
                case "name";
                    assert(it.offset_in_bytes == 48, "Property.name has unexpected offset % instead of 48", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Property.name has unexpected size % instead of 8", it.type.runtime_size);
                case "description";
                    assert(it.offset_in_bytes == 56, "Property.description has unexpected offset % instead of 56", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Property.description has unexpected size % instead of 8", it.type.runtime_size);
                case "defaultValue";
                    assert(it.offset_in_bytes == 64, "Property.defaultValue has unexpected offset % instead of 64", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Property.defaultValue has unexpected size % instead of 8", it.type.runtime_size);
                case "parent";
                    assert(it.offset_in_bytes == 72, "Property.parent has unexpected offset % instead of 72", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Property.parent has unexpected size % instead of 8", it.type.runtime_size);
                case "firstChild";
                    assert(it.offset_in_bytes == 80, "Property.firstChild has unexpected offset % instead of 80", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Property.firstChild has unexpected size % instead of 8", it.type.runtime_size);
                case "lastChild";
                    assert(it.offset_in_bytes == 88, "Property.lastChild has unexpected offset % instead of 88", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Property.lastChild has unexpected size % instead of 8", it.type.runtime_size);
                case "nextSibling";
                    assert(it.offset_in_bytes == 96, "Property.nextSibling has unexpected offset % instead of 96", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "Property.nextSibling has unexpected size % instead of 8", it.type.runtime_size);
                case "nameHash";
                    assert(it.offset_in_bytes == 104, "Property.nameHash has unexpected offset % instead of 104", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Property.nameHash has unexpected size % instead of 4", it.type.runtime_size);
                case "uniqueID";
                    assert(it.offset_in_bytes == 108, "Property.uniqueID has unexpected offset % instead of 108", it.offset_in_bytes);
                    assert(it.type.runtime_size == 4, "Property.uniqueID has unexpected size % instead of 4", it.type.runtime_size);
            }
        }
        assert(size_of(Property) == 112, "Property has size % instead of 112", size_of(Property));
    }

    {
        info := type_info(SampleIterator);
        for info.members {
            if it.name == {
                case "sample";
                    assert(it.offset_in_bytes == 0, "SampleIterator.sample has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "SampleIterator.sample has unexpected size % instead of 8", it.type.runtime_size);
                case "initial";
                    assert(it.offset_in_bytes == 8, "SampleIterator.initial has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "SampleIterator.initial has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(SampleIterator) == 16, "SampleIterator has size % instead of 16", size_of(SampleIterator));
    }

    {
        info := type_info(PropertyIterator);
        for info.members {
            if it.name == {
                case "property";
                    assert(it.offset_in_bytes == 0, "PropertyIterator.property has unexpected offset % instead of 0", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "PropertyIterator.property has unexpected size % instead of 8", it.type.runtime_size);
                case "initial";
                    assert(it.offset_in_bytes == 8, "PropertyIterator.initial has unexpected offset % instead of 8", it.offset_in_bytes);
                    assert(it.type.runtime_size == 8, "PropertyIterator.initial has unexpected size % instead of 8", it.type.runtime_size);
            }
        }
        assert(size_of(PropertyIterator) == 16, "PropertyIterator has size % instead of 16", size_of(PropertyIterator));
    }
}

