    {-# LANGUAGE CPP #-}
    {-|
    Module      : Lua.Auxiliary
    Copyright   : © 2007–2012 Gracjan Polak;
                  © 2012–2016 Ömer Sinan Ağacan;
                  © 2017-2024 Albert Krewinkel
    License     : MIT
    Maintainer  : Albert Krewinkel <tarleb@hslua.org>
    Stability   : beta
    Portability : non-portable (depends on GHC)

    Raw bindings to functions and constants of the auxiliary library.
    -}
    module Lua.Auxiliary
      ( -- * The Auxiliary Library
        luaL_getmetafield
      , luaL_getmetatable
      , luaL_loadbuffer
      , luaL_loadfile
      , luaL_loadfilex
      , luaL_openlibs
      , luaL_newmetatable
      , luaL_ref
      , luaL_testudata
      , luaL_traceback
      , luaL_unref
      , luaL_where
        -- ** Registry fields
      , loadedTableRegistryField
      , preloadTableRegistryField
        -- ** References
      , Reference (..)
      , fromReference
      , toReference
      ) where

    import Foreign.C (CChar, CInt (CInt), CSize (CSize), CString)
    import Lua.Types as Lua
    import Foreign.Ptr
    import System.IO.Unsafe (unsafePerformIO)
    import qualified GHC.Foreign as GHC
    import qualified GHC.IO.Encoding as GHC

    #ifdef ALLOW_UNSAFE_GC
    #define SAFTY unsafe
    #else
    #define SAFTY safe
    #endif

    -- * The Auxiliary Library

    -- | Key, in the registry, for table of loaded modules.
    loadedTableRegistryField :: String
    loadedTableRegistryField :: String
    loadedTableRegistryField = IO String -> String
    forall a. IO a -> a
    unsafePerformIO (IO String -> String) -> IO String -> String
    forall a b. (a -> b) -> a -> b
    $ do
      TextEncoding -> CString -> IO String
    GHC.peekCString TextEncoding
    GHC.char8 CString
    c_loaded_table
    {-# NOINLINE loadedTableRegistryField #-}

    foreign import capi unsafe "lauxlib.h value LUA_LOADED_TABLE"
      c_loaded_table :: CString

    -- | Key, in the registry, for table of preloaded loaders.
    preloadTableRegistryField :: String
    preloadTableRegistryField :: String
    preloadTableRegistryField = IO String -> String
    forall a. IO a -> a
    unsafePerformIO (IO String -> String) -> IO String -> String
    forall a b. (a -> b) -> a -> b
    $ do
      TextEncoding -> CString -> IO String
    GHC.peekCString TextEncoding
    GHC.char8 CString
    c_preload_table
    {-# NOINLINE preloadTableRegistryField #-}

    foreign import capi unsafe "lauxlib.h value LUA_PRELOAD_TABLE"
      c_preload_table :: CString

    -- | Pushes onto the stack the field @e@ from the metatable of the
    -- object at index @obj@ and returns the type of the pushed value. If
    -- the object does not have a metatable, or if the metatable does not
    -- have this field, pushes nothing and returns
    -- @'Lua.Constants.LUA_TNIL'@.
    foreign import capi SAFTY "lauxlib.h luaL_getmetafield"
      luaL_getmetafield :: Lua.State
                        -> StackIndex      -- ^ obj
                        -> CString         -- ^ e
                        -> IO TypeCode

    -- | Pushes onto the stack the metatable associated with name tname in
    -- the registry (see @'luaL_newmetatable'@) (__nil__ if there is no
    -- metatable associated with that name). Returns the type of the pushed
    -- value.
    foreign import capi SAFTY "lauxlib.h luaL_getmetatable"
      luaL_getmetatable :: Lua.State -> CString -> IO Lua.TypeCode

    -- | Loads a buffer as a Lua chunk. This function uses @lua_load@ to
    -- load the chunk in the buffer pointed to by @buff@ with size @sz@.
    --
    -- This function returns the same results as @lua_load@. @name@ is the
    -- chunk name, used for debug information and error messages.
    foreign import capi SAFTY "lauxlib.h luaL_loadbuffer"
      luaL_loadbuffer :: Lua.State
                      -> Ptr CChar         -- ^ buff
                      -> CSize             -- ^ sz
                      -> CString           -- ^ name
                      -> IO Lua.StatusCode

    -- | Equivalent to luaL_loadfilex with mode equal to @NULL@.
    foreign import capi SAFTY "lauxlib.h luaL_loadfile"
      luaL_loadfile :: Lua.State
                    -> Ptr CChar  -- ^ filename
                    -> IO Lua.StatusCode

    -- | Loads a file as a Lua chunk. This function uses @lua_load@ to load
    -- the chunk in the file named filename. If filename is @NULL@, then it
    -- loads from the standard input. The first line in the file is ignored
    -- if it starts with a @#@.
    --
    -- The string mode works as in function @lua_load@.
    --
    -- This function returns the same results as @lua_load@, but it has an
    -- extra error code LUA_ERRFILE for file-related errors (e.g., it cannot
    -- open or read the file).
    --
    -- As @lua_load@, this function only loads the chunk; it does not run
    -- it.
    foreign import capi SAFTY "lauxlib.h luaL_loadfilex"
      luaL_loadfilex :: Lua.State
                     -> Ptr CChar  -- ^ filename
                     -> Ptr CChar  -- ^ mode
                     -> IO Lua.StatusCode

    -- | If the registry already has the key @tname@, returns @0@.
    -- Otherwise, creates a new table to be used as a metatable for
    -- userdata, adds to this new table the pair @__name = tname@, adds to
    -- the registry the pair @[tname] = new table@, and returns @1@. (The
    -- entry @__name@ is used by some error-reporting functions.)
    --
    -- In both cases pushes onto the stack the final value associated with
    -- @tname@ in the registry.
    foreign import capi SAFTY "lauxlib.h luaL_newmetatable"
      luaL_newmetatable :: Lua.State -> CString {- ^ tname -} -> IO Lua.LuaBool

    -- | Opens all standard Lua libraries into the given state.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#luaL_openlibs>
    foreign import capi unsafe "lualib.h luaL_openlibs"
      luaL_openlibs :: Lua.State -> IO ()

    -- | Creates and returns a reference, in the table at index @t@, for the
    -- object at the top of the stack (and pops the object).
    --
    -- A reference is a unique integer key. As long as you do not manually
    -- add integer keys into table @t@, @luaL_ref@ ensures the uniqueness of
    -- the key it returns. You can retrieve an object referred by reference
    -- @r@ by calling @lua_rawgeti l t r@. Function @'luaL_unref'@ frees a
    -- reference and its associated object.
    --
    -- If the object at the top of the stack is nil, @luaL_ref@ returns the
    -- constant @'Lua.Constants.LUA_REFNIL'@. The constant
    -- @'Lua.Constants.LUA_NOREF'@ is guaranteed to be different
    -- from any reference returned by @luaL_ref@.
    foreign import capi SAFTY "lauxlib.h luaL_ref"
      luaL_ref :: Lua.State -> StackIndex {- ^ t -} -> IO CInt

    -- | Creates and pushes a traceback of the stack @l1@. If @msg@ is not
    -- @NULL@ it is appended at the beginning of the traceback. The level
    -- parameter tells at which level to start the traceback.
    foreign import capi SAFTY "lauxlib.h luaL_traceback"
      luaL_traceback :: Lua.State  -- ^ l
                     -> Lua.State  -- ^ l1
                     -> CString    -- ^ msg
                     -> CInt       -- ^ level
                     -> IO ()

    -- | Releases reference @ref@ from the table at index @t@ (see
    -- @'luaL_ref'@). The entry is removed from the table, so that the
    -- referred object can be collected. The reference @ref@ is also freed
    -- to be used again.
    foreign import capi SAFTY "lauxlib.h luaL_unref"
      luaL_unref :: Lua.State -> StackIndex {- ^ t -} -> CInt {- ^ ref -} -> IO ()

    -- | Checks whether the function argument @arg@ is a userdata of the
    -- type @tname@ (see @'luaL_newmetatable'@) and returns the userdata
    -- address (see @'Lua.lua_touserdata'@). Returns @NULL@ if the
    -- test fails.
    --
    -- <https://www.lua.org/manual/5.4/manual.html#luaL_testudata>
    foreign import capi SAFTY "lauxlib.h luaL_testudata"
      luaL_testudata :: Lua.State   -- ^ l
                     -> StackIndex  -- ^ arg
                     -> CString     -- ^ tname
                     -> IO (Ptr ())

    -- | Pushes onto the stack a string identifying the current position of
    -- the control at level @lvl@ in the call stack. Typically this string
    -- has the following format:
    --
    -- > chunkname:currentline:
    --
    -- Level 0 is the running function, level 1 is the function that called
    -- the running function, etc.
    --
    -- This function is used to build a prefix for error messages.
    foreign import capi SAFTY "lauxlib.h luaL_where"
      luaL_where :: Lua.State -- ^ l
                 -> CInt      -- ^ lvl
                 -> IO ()

    --
    -- References
    --

    -- | Reference to a stored value.
    data Reference =
        Reference CInt -- ^ Reference to a stored value
      | RefNil         -- ^ Reference to a nil value
      deriving (Reference -> Reference -> Bool
    (Reference -> Reference -> Bool)
    -> (Reference -> Reference -> Bool) -> Eq Reference
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: Reference -> Reference -> Bool
    == :: Reference -> Reference -> Bool
    $c/= :: Reference -> Reference -> Bool
    /= :: Reference -> Reference -> Bool
    Eq, Int -> Reference -> ShowS
    [Reference] -> ShowS
    Reference -> String
    (Int -> Reference -> ShowS)
    -> (Reference -> String)
    -> ([Reference] -> ShowS)
    -> Show Reference
    forall a.
    (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
    $cshowsPrec :: Int -> Reference -> ShowS
    showsPrec :: Int -> Reference -> ShowS
    $cshow :: Reference -> String
    show :: Reference -> String
    $cshowList :: [Reference] -> ShowS
    showList :: [Reference] -> ShowS
    Show)

    foreign import capi SAFTY "lauxlib.h value LUA_REFNIL"
      refnil :: CInt

    -- | Convert a reference to its C representation.
    fromReference :: Reference -> CInt
    fromReference :: Reference -> CInt
    fromReference = \case
      Reference CInt
    x -> CInt
    x
      Reference
    RefNil      -> CInt
    refnil

    -- | Create a reference from its C representation.
    toReference :: CInt -> Reference
    toReference :: CInt -> Reference
    toReference CInt
    x =
      if CInt
    x CInt -> CInt -> Bool
    forall a. Eq a => a -> a -> Bool
    == CInt
    refnil
      then Reference
    RefNil
      else CInt -> Reference
    Reference CInt
    x