#ifndef CODUO_ENGINE_NATIVE_VARARGS_H
#define CODUO_ENGINE_NATIVE_VARARGS_H

/*
 * NOT_FROM_ORIGINAL_SOURCE: i386 cdecl exposes VM varargs as contiguous
 * pointer-sized stack words. Native 64-bit ABIs do not, so vm_native.c needs
 * the promoted host type of each argument before copying it into the common
 * intptr_t vector. Each layout string has one promoted-type code per argument:
 * i = signed int, u = unsigned int, p = pointer, and z = size_t. The strings
 * and their lengths are both consumed by that adapter. Game-side boundary
 * calls explicitly cast enum and narrow integer arguments where necessary so
 * these promoted types do not depend on a compiler's enum-compatible type.
 */

#include <stddef.h>

typedef enum coduo_native_vararg_type_e {
    CODUO_NATIVE_VARARG_SIGNED_INT = 'i',
    CODUO_NATIVE_VARARG_UNSIGNED_INT = 'u',
    CODUO_NATIVE_VARARG_POINTER = 'p',
    CODUO_NATIVE_VARARG_SIZE = 'z'
} coduo_native_vararg_type_t;

typedef struct coduo_native_vararg_layout_s {
    const char *argumentTypes;
    size_t argumentCount;
} coduo_native_vararg_layout_t;

#define CODUO_NATIVE_VARARG_TYPE_AT(layout, slot) \
    ((coduo_native_vararg_type_t)((layout).argumentTypes[(slot)]))

#define CODUO_ENGINE_NATIVE_SYSCALL_LAYOUTS(X) \
    X(CODUO_SYSCALL_PRINTF, "p") \
    X(CODUO_SYSCALL_ERROR, "p") \
    X(CODUO_SYSCALL_ERROR_LOCALIZED, "p") \
    X(CODUO_SYSCALL_MILLISECONDS, "") \
    X(CODUO_SYSCALL_CVAR_REGISTER, "pppi") \
    X(CODUO_SYSCALL_CVAR_UPDATE, "p") \
    X(CODUO_SYSCALL_CVAR_SET, "pp") \
    X(CODUO_SYSCALL_CVAR_VARIABLE_INTEGER_VALUE, "p") \
    X(CODUO_SYSCALL_CVAR_VARIABLE_VALUE, "pp") \
    X(CODUO_SYSCALL_CVAR_VARIABLE_STRING_BUFFER, "ppi") \
    X(CODUO_SYSCALL_ARGC, "") \
    X(CODUO_SYSCALL_ARGV, "ipi") \
    X(CODUO_SYSCALL_HUNK_ALLOC, "z") \
    X(CODUO_SYSCALL_HUNK_ALLOC_LOW, "z") \
    X(CODUO_SYSCALL_HUNK_ALLOC_ALIGN, "zi") \
    X(CODUO_SYSCALL_HUNK_ALLOC_LOW_ALIGN, "zi") \
    X(CODUO_SYSCALL_HUNK_ALLOC_TEMP, "z") \
    X(CODUO_SYSCALL_HUNK_FREE_TEMP, "p") \
    X(CODUO_SYSCALL_FS_FOPEN_FILE, "ppi") \
    X(CODUO_SYSCALL_FS_READ, "pii") \
    X(CODUO_SYSCALL_FS_WRITE, "pii") \
    X(CODUO_SYSCALL_FS_RENAME, "pp") \
    X(CODUO_SYSCALL_FS_FCLOSE_FILE, "i") \
    X(CODUO_SYSCALL_SEND_CONSOLE_COMMAND, "ip") \
    X(CODUO_SYSCALL_LOCATE_GAME_DATA, "piipi") \
    X(CODUO_SYSCALL_GET_GUID, "i") \
    X(CODUO_SYSCALL_DROP_CLIENT, "ip") \
    X(CODUO_SYSCALL_SEND_SERVER_COMMAND, "iip") \
    X(CODUO_SYSCALL_SET_CONFIGSTRING, "ip") \
    X(CODUO_SYSCALL_GET_CONFIGSTRING, "ipi") \
    X(CODUO_SYSCALL_GET_CONFIGSTRING_CONST, "i") \
    X(CODUO_SYSCALL_IS_LOCAL_CLIENT, "i") \
    X(CODUO_SYSCALL_GET_CLIENT_PING, "i") \
    X(CODUO_SYSCALL_GET_USERINFO, "ipi") \
    X(CODUO_SYSCALL_SET_USERINFO, "ip") \
    X(CODUO_SYSCALL_GET_SERVERINFO, "pi") \
    X(CODUO_SYSCALL_SET_BRUSH_MODEL, "p") \
    X(CODUO_SYSCALL_TRACE, "pppppii") \
    X(CODUO_SYSCALL_TRACE_CAPSULE, "pppppii") \
    X(CODUO_SYSCALL_SIGHT_TRACE, "pppppiii") \
    X(CODUO_SYSCALL_SIGHT_TRACE_CAPSULE, "pppppiii") \
    X(CODUO_SYSCALL_SIGHT_TRACE_TO_ENTITY, "ppppii") \
    X(CODUO_SYSCALL_CM_BOX_TRACE, "pppppii") \
    X(CODUO_SYSCALL_CM_CAPSULE_TRACE, "pppppii") \
    X(CODUO_SYSCALL_CM_BOX_SIGHT_TRACE, "ppppii") \
    X(CODUO_SYSCALL_CM_CAPSULE_SIGHT_TRACE, "ppppii") \
    X(CODUO_SYSCALL_LOCATIONAL_TRACE, "pppiip") \
    X(CODUO_SYSCALL_POINT_CONTENTS, "pii") \
    X(CODUO_SYSCALL_IN_PVS, "pp") \
    X(CODUO_SYSCALL_IN_PVS_IGNORE_PORTALS, "pp") \
    X(CODUO_SYSCALL_IN_SNAPSHOT, "pi") \
    X(CODUO_SYSCALL_ADJUST_AREA_PORTAL_STATE, "pi") \
    X(CODUO_SYSCALL_AREAS_CONNECTED, "ii") \
    X(CODUO_SYSCALL_LINK_ENTITY, "p") \
    X(CODUO_SYSCALL_UNLINK_ENTITY, "p") \
    X(CODUO_SYSCALL_ENTITIES_IN_BOX, "pppii") \
    X(CODUO_SYSCALL_ENTITY_CONTACT, "ppp") \
    X(CODUO_SYSCALL_GET_USERCMD, "ip") \
    X(CODUO_SYSCALL_GET_ENTITY_TOKEN, "pi") \
    X(CODUO_SYSCALL_FS_GET_FILE_LIST, "pppi") \
    X(CODUO_SYSCALL_MAP_EXISTS, "p") \
    X(CODUO_SYSCALL_REAL_TIME, "p") \
    X(CODUO_SYSCALL_SNAP_VECTOR, "p") \
    X(CODUO_SYSCALL_ENTITY_CONTACT_CAPSULE, "ppp") \
    X(CODUO_SYSCALL_COM_SOUND_ALIAS_STRING, "p") \
    X(CODUO_SYSCALL_COM_PICK_SOUND_ALIAS, "pp") \
    X(CODUO_SYSCALL_COM_SOUND_ALIAS_INDEX, "p") \
    X(CODUO_SYSCALL_SURFACE_TYPE_FROM_NAME, "p") \
    X(CODUO_SYSCALL_SURFACE_TYPE_TO_NAME, "i") \
    X(CODUO_SYSCALL_ADD_TEST_CLIENT, "") \
    X(CODUO_SYSCALL_GET_ARCHIVED_CLIENT_INFO, "ippp") \
    X(CODUO_SYSCALL_ADD_DEBUG_STRING, "ppup") \
    X(CODUO_SYSCALL_ADD_DEBUG_LINE, "pppii") \
    X(CODUO_SYSCALL_SET_ARCHIVE, "i") \
    X(CODUO_SYSCALL_Z_MALLOC, "z") \
    X(CODUO_SYSCALL_Z_FREE, "p") \
    X(CODUO_SYSCALL_XANIM_CREATE_TREE, "p") \
    X(CODUO_SYSCALL_XANIM_CREATE_SMALL_TREE, "p") \
    X(CODUO_SYSCALL_XANIM_FREE_SMALL_TREE, "p") \
    X(CODUO_SYSCALL_XMODEL_EXISTS, "p") \
    X(CODUO_SYSCALL_XMODEL_GET, "p") \
    X(CODUO_SYSCALL_DOBJ_CREATE, "pupiu") \
    X(CODUO_SYSCALL_DOBJ_EXISTS, "i") \
    X(CODUO_SYSCALL_SAFE_DOBJ_FREE, "ii") \
    X(CODUO_SYSCALL_XANIM_GET_ANIMS, "p") \
    X(CODUO_SYSCALL_XANIM_CLEAR_TREE_GOAL_WEIGHTS, "piu") \
    X(CODUO_SYSCALL_XANIM_CLEAR_GOAL_WEIGHT, "piu") \
    X(CODUO_SYSCALL_XANIM_CLEAR_TREE_GOAL_WEIGHTS_STRICT, "piu") \
    X(CODUO_SYSCALL_XANIM_SET_COMPLETE_GOAL_WEIGHT_KNOB, "piuuuii") \
    X(CODUO_SYSCALL_XANIM_SET_COMPLETE_GOAL_WEIGHT_KNOB_ALL, "piuuuuii") \
    X(CODUO_SYSCALL_XANIM_SET_ANIM_RATE, "piu") \
    X(CODUO_SYSCALL_XANIM_SET_TIME, "piu") \
    X(CODUO_SYSCALL_XANIM_SET_GOAL_WEIGHT_KNOB, "piuuuii") \
    X(CODUO_SYSCALL_XANIM_CLEAR_TREE, "p") \
    X(CODUO_SYSCALL_XANIM_HAS_TIME, "ii") \
    X(CODUO_SYSCALL_XANIM_IS_PRIMITIVE, "ii") \
    X(CODUO_SYSCALL_XANIM_GET_LENGTH, "pi") \
    X(CODUO_SYSCALL_XANIM_GET_LENGTH_SECONDS, "ii") \
    X(CODUO_SYSCALL_XANIM_SET_COMPLETE_GOAL_WEIGHT, "piuuuii") \
    X(CODUO_SYSCALL_XANIM_SET_GOAL_WEIGHT, "piuuuii") \
    X(CODUO_SYSCALL_XANIM_CALC_ABS_DELTA, "pipp") \
    X(CODUO_SYSCALL_XANIM_CALC_DELTA, "pippi") \
    X(CODUO_SYSCALL_XANIM_GET_REL_DELTA, "iippuu") \
    X(CODUO_SYSCALL_XANIM_GET_ABS_DELTA, "iippu") \
    X(CODUO_SYSCALL_XANIM_IS_LOOPED, "ii") \
    X(CODUO_SYSCALL_XANIM_NOTETRACK_EXISTS, "iii") \
    X(CODUO_SYSCALL_XANIM_GET_TIME, "pi") \
    X(CODUO_SYSCALL_XANIM_GET_WEIGHT, "pi") \
    X(CODUO_SYSCALL_DOBJ_DUMP_INFO, "i") \
    X(CODUO_SYSCALL_DOBJ_CREATE_SKEL_FOR_BONE, "ii") \
    X(CODUO_SYSCALL_DOBJ_CREATE_SKEL_FOR_BONES, "ip") \
    X(CODUO_SYSCALL_DOBJ_UPDATE_SERVER_TIME, "iui") \
    X(CODUO_SYSCALL_DOBJ_INIT_SERVER_TIME, "iu") \
    X(CODUO_SYSCALL_DOBJ_GET_HIERARCHY_BITS, "iip") \
    X(CODUO_SYSCALL_DOBJ_CALC_ANIM, "ip") \
    X(CODUO_SYSCALL_DOBJ_CALC_SKEL, "ip") \
    X(CODUO_SYSCALL_XANIM_LOAD_ANIM_TREE, "p") \
    X(CODUO_SYSCALL_XANIM_SAVE_ANIM_TREE, "p") \
    X(CODUO_SYSCALL_XANIM_CLONE_ANIM_TREE, "pp") \
    X(CODUO_SYSCALL_DOBJ_NUM_BONES, "i") \
    X(CODUO_SYSCALL_DOBJ_GET_BONE_INDEX, "ip") \
    X(CODUO_SYSCALL_DOBJ_GET_MATRIX_ARRAY, "i") \
    X(CODUO_SYSCALL_DOBJ_DISPLAY_ANIM, "i") \
    X(CODUO_SYSCALL_XANIM_HAS_FINISHED, "pi") \
    X(CODUO_SYSCALL_XANIM_GET_NUM_CHILDREN, "ii") \
    X(CODUO_SYSCALL_XANIM_GET_CHILD_AT, "iii") \
    X(CODUO_SYSCALL_XMODEL_NUM_BONES, "p") \
    X(CODUO_SYSCALL_XMODEL_GET_BONE_NAMES, "p") \
    X(CODUO_SYSCALL_DOBJ_GET_ROT_TRANS_ARRAY, "i") \
    X(CODUO_SYSCALL_DOBJ_SET_ROT_TRANS_INDEX, "ipi") \
    X(CODUO_SYSCALL_DOBJ_SET_CONTROL_ROT_TRANS_INDEX, "ipi") \
    X(CODUO_SYSCALL_DOBJ_GET_BOUNDS, "ipp") \
    X(CODUO_SYSCALL_XANIM_GET_ANIM_NAME, "ii") \
    X(CODUO_SYSCALL_DOBJ_GET_TREE, "i") \
    X(CODUO_SYSCALL_XANIM_GET_ANIM_TREE_SIZE, "p") \
    X(CODUO_SYSCALL_XMODEL_DEBUG_BOXES, "i") \
    X(CODUO_SYSCALL_GET_WEAPON_INFO_MEMORY, "ip") \
    X(CODUO_SYSCALL_FREE_WEAPON_INFO_MEMORY, "i") \
    X(CODUO_SYSCALL_FREE_CLIENT_SCRIPT_PERS, "") \
    X(CODUO_SYSCALL_RESET_ENTITY_PARSE_POINT, "") \
    X(CODUO_SYSCALL_MEMSET, "piz") \
    X(CODUO_SYSCALL_MEMCPY, "ppz") \
    X(CODUO_SYSCALL_STRNCPY, "ppi") \
    X(CODUO_SYSCALL_SIN, "u") \
    X(CODUO_SYSCALL_COS, "u") \
    X(CODUO_SYSCALL_ATAN2, "uu") \
    X(CODUO_SYSCALL_SQRT, "u") \
    X(CODUO_SYSCALL_MATRIX_MULTIPLY, "ppp") \
    X(CODUO_SYSCALL_ANGLE_VECTORS, "pppp") \
    X(CODUO_SYSCALL_PERPENDICULAR_VECTOR, "pp") \
    X(CODUO_SYSCALL_FLOOR, "u") \
    X(CODUO_SYSCALL_CEIL, "u")

#define CODUO_ENGINE_NATIVE_GAME_COMMAND_LAYOUTS(X) \
    X(CODUO_GAME_GET_API_VERSION, "") \
    X(CODUO_GAME_INIT, "iiii") \
    X(CODUO_GAME_SHUTDOWN, "i") \
    X(CODUO_GAME_CLIENT_CONNECT, "ii") \
    X(CODUO_GAME_CLIENT_BEGIN, "i") \
    X(CODUO_GAME_CLIENT_USERINFO_CHANGED, "i") \
    X(CODUO_GAME_CLIENT_DISCONNECT, "i") \
    X(CODUO_GAME_CLIENT_COMMAND, "i") \
    X(CODUO_GAME_CLIENT_THINK, "i") \
    X(CODUO_GAME_GET_FOLLOW_PLAYER_STATE, "ip") \
    X(CODUO_GAME_UPDATE_CVARS, "") \
    X(CODUO_GAME_RUN_FRAME, "i") \
    X(CODUO_GAME_CONSOLE_COMMAND, "") \
    X(CODUO_GAME_SCRIPT_FAR_HOOK, "p") \
    X(CODUO_GAME_DOBJ_CALC_POSE, "i") \
    X(CODUO_GAME_IS_VALID_WEAPON, "i") \
    X(CODUO_GAME_SET_MATCH_STATE, "i") \
    X(CODUO_GAME_GET_MATCH_STATE, "") \
    X(CODUO_GAME_GET_CLIENT_SESSION, "i") \
    X(CODUO_GAME_GET_CLIENT_ARCHIVE_TIME, "i") \
    X(CODUO_GAME_SET_CLIENT_ARCHIVE_TIME, "ii") \
    X(CODUO_GAME_GET_CLIENT_SCORE, "i") \
    X(CODUO_GAME_GET_FOG_OPAQUE_DIST_SQ_BITS, "")

#endif /* CODUO_ENGINE_NATIVE_VARARGS_H */
