// bit-specific integer types
// @note(judah): unlike the intX_t types, these will not automagically promote
// so explicit casting is required (especially in format strings).

typedef unsigned _BitInt(1) bool1;
typedef unsigned _BitInt(2) bool2;
typedef unsigned _BitInt(4) bool4;
typedef unsigned _BitInt(8) bool8;

typedef unsigned _BitInt(1)   u1;
typedef unsigned _BitInt(2)   u2;
typedef unsigned _BitInt(4)   u4;
typedef unsigned _BitInt(8)   u8;
typedef unsigned _BitInt(16)  u16;
typedef unsigned _BitInt(32)  u32;
typedef unsigned _BitInt(64)  u64;
typedef unsigned _BitInt(128) u128;

typedef signed _BitInt(2)   s2;
typedef signed _BitInt(4)   s4;
typedef signed _BitInt(8)   s8;
typedef signed _BitInt(16)  s16;
typedef signed _BitInt(32)  s32;
typedef signed _BitInt(64)  s64;
typedef signed _BitInt(128) s128;

typedef float  f32;
typedef double f64;

#if ARCH_32
   typedef u32 uaddr;
   typedef s32 saddr;

   typedef u32 uword;
   typedef s32 sword;
#else
   typedef u64 uaddr;
   typedef s64 saddr;

   typedef u64 uword;
   typedef s64 sword;
#endif

static_assert(sizeof(uaddr) == sizeof(void*), "sizeof(uaddr) != sizeof(void*)");

#define auto __auto_type

typedef struct { u8* data; uword count; } string;

#define string_from(P)          (string){ .data = (P), .count = cast(uword, strlen((P))) }
#define string_from_const(S)    (string){ .data = (S), .count = count_of((S)) }
#define string_with_count(P, C) (string){ .data = (P), .count = (C) }

#define usize_of(T)  cast(uword, sizeof(T))
#define ssize_of(T)  cast(sword, sizeof(T))
#define ualign_of(T) cast(uword, alignof(T))
#define salign_of(T) cast(sword, alignof(T))
#define count_of(P)  (usize_of(P) / usize_of((P)[0]))

#define cast(to_type, expr) ((to_type)(expr))
// Thanks azmr
#define safecast(to_type, from_type, expr) _Generic(expr, from_type: cast(to_type, expr))
#define  ptrcast(to_type, from_type, expr) _Generic(expr, from_type: cast(to_type, cast(uaddr, expr)))
#define  bitcast(to_type, from_type, expr) (((union { from_type from; to_type to; }){_Generic(expr, from_type: expr)}).to)

#define procedure(ret_type, ...) typeof(ret_type(__VA_ARGS__))*
#define closure(ret_type, ...)   typeof(ret_type(__VA_ARGS__))^

#include <Block.h>

#define capture   __block       // allows a variable to be mutably captured by a closure (will be moved to the heap if needed)
#define persist   Block_copy    // moves a closure to the heap (reference counted) so it can persist outside of its local stack frame
#define unpersist Block_release // frees a closure (or decrements its reference count)

typedef closure(void, void) __scope_exit;
static inline void __scope_exit_run(__scope_exit *blk) { (*blk)(); }

#define __concat__2(a, b) a##b
#define __concat(a, b) __concat__2(a, b)

#define scope_exit \
    __attribute__((cleanup(__scope_exit_run), unused)) \
    __scope_exit __concat(_defer_, __LINE__) = ^void(void)
