#define JS_GLOBAL_OBJECT (void*)0x0000000000000000ULL
#define IS_CALLBACK 1
// This file is part of Bun!
// You can find the original source:
// https://github.com/oven-sh/bun/blob/main/src/bun.js/api/FFI.h
//
// clang-format off
// This file is only compatible with 64 bit CPUs
// It must be kept in sync with JSCJSValue.h
// https://github.com/oven-sh/WebKit/blob/main/Source/JavaScriptCore/runtime/JSCJSValue.h
#ifdef IS_CALLBACK
#define INJECT_BEFORE int c = 500; // This is a callback, so we need to inject code before the call
#endif
#define IS_BIG_ENDIAN 0
#define USE_JSVALUE64 1
#define USE_JSVALUE32_64 0

#define ZIG_REPR_TYPE int64_t


// /* 7.18.1.1  Exact-width integer types */
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
typedef unsigned long long size_t;
typedef long intptr_t;
typedef uint64_t uintptr_t;
typedef _Bool bool;

#define true 1
#define false 0

#ifndef SRC_JS_NATIVE_API_TYPES_H_
typedef struct napi_env__ *napi_env;
typedef int64_t napi_value;
typedef enum {
  napi_ok,
  napi_invalid_arg,
  napi_object_expected,
  napi_string_expected,
  napi_name_expected,
  napi_function_expected,
  napi_number_expected,
  napi_boolean_expected,
  napi_array_expected,
  napi_generic_failure,
  napi_pending_exception,
  napi_cancelled,
  napi_escape_called_twice,
  napi_handle_scope_mismatch,
  napi_callback_scope_mismatch,
  napi_queue_full,
  napi_closing,
  napi_bigint_expected,
  napi_date_expected,
  napi_arraybuffer_expected,
  napi_detachable_arraybuffer_expected,
  napi_would_deadlock // unused
} napi_status;
void* NapiHandleScope__open(void* napi_env, bool detached);
void NapiHandleScope__close(void* napi_env, void* handleScope);
extern struct napi_env__ Bun__thisFFIModuleNapiEnv;
#endif


#ifdef INJECT_BEFORE
// #include <stdint.h>
#endif
// #include <tcclib.h>

// This value is 2^49, used to encode doubles such that the encoded value will
// begin with a 15-bit pattern within the range 0x0002..0xFFFC.
#define DoubleEncodeOffsetBit 49
#define DoubleEncodeOffset    (1ll << DoubleEncodeOffsetBit)
#define OtherTag              0x2ll
#define BoolTag               0x4ll
#define UndefinedTag          0x8ll
#define TagValueFalse            (OtherTag | BoolTag | false)
#define TagValueTrue             (OtherTag | BoolTag | true)
#define TagValueUndefined        (OtherTag | UndefinedTag)
#define TagValueNull             (OtherTag)
#define NotCellMask  (int64_t)(NumberTag | OtherTag)

#define MAX_INT32 2147483648
#define MAX_INT52 9007199254740991

// If all bits in the mask are set, this indicates an integer number,
// if any but not all are set this value is a double precision number.
#define NumberTag 0xfffe000000000000ll

typedef  void* JSCell;

typedef union EncodedJSValue {
  int64_t asInt64;

#if USE_JSVALUE64
  JSCell *ptr;
#endif

napi_value asNapiValue;

#if IS_BIG_ENDIAN
  struct {
    int32_t tag;
    int32_t payload;
  } asBits;
#else
  struct {
    int32_t payload;
    int32_t tag;
  } asBits;
#endif

  void* asPtr;
  double asDouble;

  ZIG_REPR_TYPE asZigRepr;
} EncodedJSValue;

EncodedJSValue ValueUndefined = { TagValueUndefined };
EncodedJSValue ValueTrue = { TagValueTrue };

typedef void* JSContext;

// Bun_FFI_PointerOffsetToArgumentsList is injected into the build 
// The value is generated in `make sizegen`
// The value is 6.
// On ARM64_32, the value is something else but it really doesn't matter for our case
// However, I don't want this to subtly break amidst future upgrades to JavaScriptCore
#define LOAD_ARGUMENTS_FROM_CALL_FRAME \
  int64_t *argsPtr = (int64_t*)((size_t*)callFrame + Bun_FFI_PointerOffsetToArgumentsList)


#ifdef IS_CALLBACK
void* callback_ctx;
ZIG_REPR_TYPE FFI_Callback_call(void* ctx, size_t argCount, ZIG_REPR_TYPE* args);
// We wrap 
static EncodedJSValue _FFI_Callback_call(void* ctx, size_t argCount, ZIG_REPR_TYPE* args)  __attribute__((__always_inline__));
static EncodedJSValue _FFI_Callback_call(void* ctx, size_t argCount, ZIG_REPR_TYPE* args) {
  EncodedJSValue return_value;
  return_value.asZigRepr = FFI_Callback_call(ctx, argCount, args);
  return return_value;
}
#endif

static bool JSVALUE_IS_CELL(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_IS_INT32(EncodedJSValue val) __attribute__((__always_inline__)); 
static bool JSVALUE_IS_NUMBER(EncodedJSValue val) __attribute__((__always_inline__));

static uint64_t JSVALUE_TO_UINT64(EncodedJSValue value) __attribute__((__always_inline__));
static int64_t  JSVALUE_TO_INT64(EncodedJSValue value) __attribute__((__always_inline__));
uint64_t JSVALUE_TO_UINT64_SLOW(EncodedJSValue value);
int64_t  JSVALUE_TO_INT64_SLOW(EncodedJSValue value);

EncodedJSValue UINT64_TO_JSVALUE_SLOW(void* jsGlobalObject, uint64_t val);
EncodedJSValue INT64_TO_JSVALUE_SLOW(void* jsGlobalObject, int64_t val);
static EncodedJSValue UINT64_TO_JSVALUE(void* jsGlobalObject, uint64_t val) __attribute__((__always_inline__));
static EncodedJSValue INT64_TO_JSVALUE(void* jsGlobalObject, int64_t val) __attribute__((__always_inline__));


static EncodedJSValue INT32_TO_JSVALUE(int32_t val) __attribute__((__always_inline__));
static EncodedJSValue DOUBLE_TO_JSVALUE(double val) __attribute__((__always_inline__));
static EncodedJSValue FLOAT_TO_JSVALUE(float val) __attribute__((__always_inline__));
static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) __attribute__((__always_inline__));
static EncodedJSValue PTR_TO_JSVALUE(void* ptr) __attribute__((__always_inline__));

static void* JSVALUE_TO_PTR(EncodedJSValue val) __attribute__((__always_inline__));
static int32_t JSVALUE_TO_INT32(EncodedJSValue val) __attribute__((__always_inline__));
static float JSVALUE_TO_FLOAT(EncodedJSValue val) __attribute__((__always_inline__));
static double JSVALUE_TO_DOUBLE(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSVALUE_TO_BOOL(EncodedJSValue val) __attribute__((__always_inline__));
static uint8_t GET_JSTYPE(EncodedJSValue val) __attribute__((__always_inline__));
static bool JSTYPE_IS_TYPED_ARRAY(uint8_t type) __attribute__((__always_inline__));
static bool JSCELL_IS_TYPED_ARRAY(EncodedJSValue val) __attribute__((__always_inline__));
static void* JSVALUE_TO_TYPED_ARRAY_VECTOR(EncodedJSValue val) __attribute__((__always_inline__));
static uint64_t JSVALUE_TO_TYPED_ARRAY_LENGTH(EncodedJSValue val) __attribute__((__always_inline__));

static bool JSVALUE_IS_CELL(EncodedJSValue val) {
  return !(val.asInt64 & NotCellMask);
}

static bool JSVALUE_IS_INT32(EncodedJSValue val) {
  return (val.asInt64 & NumberTag) == NumberTag;
}

static bool JSVALUE_IS_NUMBER(EncodedJSValue val) {
  return val.asInt64 & NumberTag;
}

static uint8_t GET_JSTYPE(EncodedJSValue val) {
  return *(uint8_t*)((uint8_t*)val.asPtr + JSCell__offsetOfType);
}

static bool JSTYPE_IS_TYPED_ARRAY(uint8_t type) {
  return type >= JSTypeArrayBufferViewMin && type <= JSTypeArrayBufferViewMax;
}

static bool JSCELL_IS_TYPED_ARRAY(EncodedJSValue val) {
  return JSVALUE_IS_CELL(val) && JSTYPE_IS_TYPED_ARRAY(GET_JSTYPE(val));
}

static void* JSVALUE_TO_TYPED_ARRAY_VECTOR(EncodedJSValue val) {
  return *(void**)((char*)val.asPtr + JSArrayBufferView__offsetOfVector);
}

static uint64_t JSVALUE_TO_TYPED_ARRAY_LENGTH(EncodedJSValue val) {
  return *(uint64_t*)((char*)val.asPtr + JSArrayBufferView__offsetOfLength);
}

// JSValue numbers-as-pointers are represented as a 52-bit integer
// Previously, the pointer was stored at the end of the 64-bit value
// Now, they're stored at the beginning of the 64-bit value
// This behavior change enables the JIT to handle it better
// It also is better readability when console.log(myPtr)
static void* JSVALUE_TO_PTR(EncodedJSValue val) {
  if (val.asInt64 == TagValueNull)
    return 0;

  if (JSCELL_IS_TYPED_ARRAY(val)) {
      return JSVALUE_TO_TYPED_ARRAY_VECTOR(val);
  }

  val.asInt64 -= DoubleEncodeOffset;
  size_t ptr = (size_t)val.asDouble;
  return (void*)ptr;
}

static EncodedJSValue PTR_TO_JSVALUE(void* ptr) {
  EncodedJSValue val;
  if (ptr == 0)
  {
      val.asInt64 = TagValueNull;
      return val;
  }

  val.asDouble = (double)(size_t)ptr;
  val.asInt64 += DoubleEncodeOffset;
  return val;
}

static EncodedJSValue DOUBLE_TO_JSVALUE(double val) {
   EncodedJSValue res;
   res.asDouble = val;
   res.asInt64 += DoubleEncodeOffset;
   return res;
}

static int32_t JSVALUE_TO_INT32(EncodedJSValue val) {
  return val.asInt64;
}

static EncodedJSValue INT32_TO_JSVALUE(int32_t val) {
   EncodedJSValue res;
   res.asInt64 = NumberTag | (uint32_t)val;
   return res;
}

static EncodedJSValue UINT32_TO_JSVALUE(uint32_t val) {
  EncodedJSValue res;
  if(val <= MAX_INT32) {
    res.asInt64 = NumberTag | val;
    return res;
  } else {
    EncodedJSValue res;
    res.asDouble = val;
    res.asInt64 += DoubleEncodeOffset;
    return res;
  }
}

static EncodedJSValue FLOAT_TO_JSVALUE(float val) {
  return DOUBLE_TO_JSVALUE((double)val);
}

static EncodedJSValue BOOLEAN_TO_JSVALUE(bool val) {
  EncodedJSValue res;
  res.asInt64 = val ? TagValueTrue : TagValueFalse;
  return res;
}


static double JSVALUE_TO_DOUBLE(EncodedJSValue val) {
  val.asInt64 -= DoubleEncodeOffset;
  return val.asDouble;
}

static float JSVALUE_TO_FLOAT(EncodedJSValue val) {
  return (float)JSVALUE_TO_DOUBLE(val);
}

static bool JSVALUE_TO_BOOL(EncodedJSValue val) {
  return val.asInt64 == TagValueTrue;
}


static uint64_t JSVALUE_TO_UINT64(EncodedJSValue value) {
  if (JSVALUE_IS_INT32(value)) {
    return (uint64_t)JSVALUE_TO_INT32(value);
  }

  if (JSVALUE_IS_NUMBER(value)) {
    return (uint64_t)JSVALUE_TO_DOUBLE(value);
  }

  if (JSCELL_IS_TYPED_ARRAY(value)) {
    return (uint64_t)JSVALUE_TO_TYPED_ARRAY_LENGTH(value);
  }

  return JSVALUE_TO_UINT64_SLOW(value);
}
static int64_t JSVALUE_TO_INT64(EncodedJSValue value) {
  if (JSVALUE_IS_INT32(value)) {
    return (int64_t)JSVALUE_TO_INT32(value);
  }

  if (JSVALUE_IS_NUMBER(value)) {
    return (int64_t)JSVALUE_TO_DOUBLE(value);
  }

  return JSVALUE_TO_INT64_SLOW(value);
}

static EncodedJSValue UINT64_TO_JSVALUE(void* jsGlobalObject, uint64_t val) {
  if (val < MAX_INT32) {
    return INT32_TO_JSVALUE((int32_t)val);
  }

  if (val < MAX_INT52) {
    return DOUBLE_TO_JSVALUE((double)val);
  }

  return UINT64_TO_JSVALUE_SLOW(jsGlobalObject, val);
}

static EncodedJSValue INT64_TO_JSVALUE(void* jsGlobalObject, int64_t val) {
  if (val >= -MAX_INT32 && val <= MAX_INT32) {
    return INT32_TO_JSVALUE((int32_t)val);
  }

  if (val >= -MAX_INT52 && val <= MAX_INT52) {
    return DOUBLE_TO_JSVALUE((double)val);
  }

  return INT64_TO_JSVALUE_SLOW(jsGlobalObject, val);
}

#ifndef IS_CALLBACK
ZIG_REPR_TYPE JSFunctionCall(void* jsGlobalObject, void* callFrame);

#endif


// --- Generated Code ---

 
/* --- The Callback Function */
bool my_callback_function(void* arg0) {
#ifdef INJECT_BEFORE
INJECT_BEFORE;
#endif
 ZIG_REPR_TYPE arguments[1];
arguments[0] = PTR_TO_JSVALUE(arg0).asZigRepr;
  return (bool)JSVALUE_TO_BOOL(_FFI_Callback_call((void*)0x0000000000000000ULL, 1, arguments));
}

