---@meta ffi

--------------------------------------------------------------------------------
-- cffi-lua FFI module
--------------------------------------------------------------------------------

---@alias ffi_ct string|ffi_ctype|ffi_cdata
---@alias ffi_finalizer any
---@alias ffi_cdef_param any
---@alias ffi_abi_param
---| '32bit'
---| '64bit'
---| 'be'
---| 'le'
---| 'win'
---| 'eabi'
---| 'uwp'
---| 'elfv2'
---| 'unionval'
---| 'fpu'
---| 'hardfp'
---| 'softfp'
---| string
---@alias ffi_os_name
---| 'Windows'
---| 'Linux'
---| 'OSX'
---| 'BSD'
---| 'POSIX'
---| 'Other'
---| string
---@alias ffi_arch_name
---| 'alpha'
---| 'arm'
---| 'armeb'
---| 'arm64'
---| 'arm64be'
---| 'hppa'
---| 'm68k'
---| 'microblaze'
---| 'microblazeel'
---| 'mips'
---| 'mipsel'
---| 'mips32r6'
---| 'mips32r6el'
---| 'mips64'
---| 'mips64el'
---| 'mips64r6'
---| 'mips64r6el'
---| 'or1k'
---| 'ppc'
---| 'ppcle'
---| 'ppc64le'
---| 'ppc64'
---| 'riscv32'
---| 'riscv64'
---| 's390'
---| 's390x'
---| 'sh4'
---| 'sh4eb'
---| 'sparc'
---| 'sparc64'
---| 'x64'
---| 'x86'
---| 'unknown'
---| string

---@class ffi_clib*
---@field [string] any Dynamic C symbols
local clib = {}

---@class ffi_ctype*
---@operator call(...): ffi_cdata
local ctype = {}

---@class ffi_cdata*
---@field [integer] any Pointer, reference, array, or aggregate type index
---@field [string] any Aggregate fields or dynamic members
---@operator add(any): ffi_cdata
---@operator sub(any): ffi_cdata|integer
---@operator mul(any): ffi_cdata
---@operator div(any): ffi_cdata
---@operator mod(any): ffi_cdata
---@operator pow(any): ffi_cdata
---@operator unm: ffi_cdata
---@operator len: integer
---@operator concat(any): string
---@operator eq(any): boolean
---@operator lt(any): boolean
---@operator le(any): boolean
local cdata = {}

--- Release callback resources.
---
--- This method is only supported by callback cdata.
function cdata:free() end

--- Bind a new Lua function to callback.
---
--- This method is only supported by callback cdata.
---@param func function New callback function
function cdata:set(func) end

---@class ffi_metatype*
---@field __add? fun(a:any, b:any):any
---@field __sub? fun(a:any, b:any):any
---@field __mul? fun(a:any, b:any):any
---@field __div? fun(a:any, b:any):any
---@field __mod? fun(a:any, b:any):any
---@field __pow? fun(a:any, b:any):any
---@field __unm? fun(a:any):any
---@field __concat? fun(a:any, b:any):any
---@field __len? fun(a:any):integer
---@field __eq? fun(a:any, b:any):boolean
---@field __lt? fun(a:any, b:any):boolean
---@field __le? fun(a:any, b:any):boolean
---@field __index? table|fun(self:any, key:any):any
---@field __newindex? table|fun(self:any, key:any, value:any)
---@field __call? fun(self:any, ...:any):any
---@field __new? fun(ct:ffi_ctype, ...:any):any
---@field __gc? fun(self:any)
---@field __tostring? fun(self:any):string
---@field __pairs? fun(self:any):function, any, any
---@field __ipairs? fun(self:any):function, any, any
---@field __idiv? fun(a:any, b:any):any
---@field __band? fun(a:any, b:any):any
---@field __bor? fun(a:any, b:any):any
---@field __bxor? fun(a:any, b:any):any
---@field __bnot? fun(a:any):any
---@field __shl? fun(a:any, b:any):any
---@field __shr? fun(a:any, b:any):any
---@field __name? string
---@field __close? fun(self:any, err:any)

---@class ffi*
---@field C ffi_clib Default C symbol namespace
---@field os ffi_os_name Target OS name
---@field arch ffi_arch_name target architecture name
---@field nullptr ffi_cdata Null pointer constant `(void *)0`
---@type ffi*
local M = {}

M.C = clib
M.os = "OSX"
M.arch = "arm64"
M.nullptr = cdata

--- Declare a C type, constant, or function.
---
--- Parameterized types are supported, and additional parameters are passed to the declaration parser.
---@param def string C Statement text
---@param ... ffi_cdef_param Parameterized declaration parameters
function M.cdef(def, ...) end

--- Loads the dynamic library and returns the symbol namespace.
---@param name string Dynamic library name or path
---@param global? boolean Whether to load globally
---@return ffi_clib clib C Symbol namespace
function M.load(name, global) end

--- Create a C data object.
---@param ct ffi_ct C Type
---@param ... any Initialization parameters; VLA/VLS types need to pass the number of elements first
---@return ffi_cdata cdata C data object
function M.new(ct, ...) end

--- Create C data objects according to C cast rules.
---@param ct ffi_ct C Type
---@param init any initial value
---@return ffi_cdata cdata C data object
function M.cast(ct, init) end

--- Create an object of type C.
---@param ct ffi_ct C Type
---@param ... ffi_cdef_param Parameterized type parameters
---@return ffi_ctype ctype C type object
function M.typeof(ct, ...) end

--- Set metatable for struct/union type and return corresponding ctype.
---@param ct ffi_ct struct or union type
---@param metatable ffi_metatype metatable
---@return ffi_ctype ctype C type object
function M.metatype(ct, metatable) end

--- Returns the address of cdata.
---@param cdata ffi_cdata C data object
---@return ffi_cdata ptr pointer cdata
function M.addressof(cdata) end

--- Set or clear GC finalizer for cdata.
---
--- Passing in nil will clear existing finalizers.
---@param cdata ffi_cdata C data object
---@param finalizer ffi_finalizer|nil finalizer
---@return ffi_cdata cdata original cdata
function M.gc(cdata, finalizer) end

--- Returns the size in bytes of type C or cdata.
---@param ct ffi_ct C type or cdata
---@param nelem? integer VLA/VLS Number of elements
---@return integer? size Size in bytes; nil if unknown
function M.sizeof(ct, nelem) end

--- Returns the minimum alignment of type C.
---@param ct ffi_ct C Type
---@return integer align Alignment bytes
function M.alignof(ct) end

--- Returns the aggregate type field offset.
---@param ct ffi_ct struct or union type
---@param field string Field name
---@return integer? offset Byte offset; nil if field does not exist
function M.offsetof(ct, field) end

--- Determine whether the object is of the specified C type.
---@param ct ffi_ct C Type
---@param obj any Object to be checked
---@return boolean ok Does it match
function M.istype(ct, obj) end

--- Get the current errno and set a new errno.
---@param newerr? integer new errno
---@return integer err errno before calling
function M.errno(newerr) end

--- Create a Lua string from a C string or memory area.
---@overload fun(str:string):string
---@overload fun(str:string, len:integer):string
---@param ptr ffi_cdata C string pointer, array, or cdata
---@param len? integer Length in bytes; when omitted, it is treated as a zero-terminated string
---@return string str Lua string
function M.string(ptr, len) end

--- Copy memory.
---@overload fun(dst:ffi_cdata|userdata, src:string)
---@overload fun(dst:ffi_cdata|userdata, src:string, len:integer)
---@param dst ffi_cdata|userdata target pointer
---@param src ffi_cdata|userdata source pointer
---@param len integer Byte length
function M.copy(dst, src, len) end

--- Fill memory.
---@param dst ffi_cdata|userdata target pointer
---@param len integer Byte length
---@param c? integer Fill value, default 0
function M.fill(dst, len, c) end

--- Convert cdata to Lua value or cdata according to C function return value rules.
---@param cdata ffi_cdata C data object
---@return any value converted value
function M.toretval(cdata) end

--- Parses a C constant expression and returns cdata.
---@param expr string C constant expression
---@return ffi_cdata value C data object
function M.eval(expr) end

--- Determine whether the target ABI meets the parameters.
---@param param ffi_abi_param ABI parameters
---@return boolean ok Are you satisfied?
function M.abi(param) end

--- Convert cdata or ordinary Lua values to Lua numbers.
---@param value any Value to be converted
---@param base? integer Hexadecimal; transparently passed to Lua `tonumber` when it is not cdata
---@return number? n Number; nil if conversion is not possible
function M.tonumber(value, base) end

--- Like Lua `type`, but cvalue returns `"cdata"`.
---@param value any Value to be checked
---@return string type Type name
function M.type(value) end

return M
