    {-# LANGUAGE CPP                 #-}
    {-# LANGUAGE OverloadedStrings   #-}
    {-# LANGUAGE ScopedTypeVariables #-}
    {-# LANGUAGE TypeApplications    #-}
    {-|
    Module      : HsLua.Core.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)

    Wrappers for the auxiliary library.
    -}
    module HsLua.Core.Auxiliary
      ( -- * The Auxiliary Library
        checkstack'
      , dostring
      , dofile
      , getmetafield
      , getmetatable'
      , getsubtable
      , loadbuffer
      , loadfile
      , loadstring
      , newmetatable
      , newstate
      , requiref
      , tostring'
      , traceback
      , where'
        -- ** References
      , getref
      , ref
      , unref
        -- ** Registry fields
      , loaded
      , preload
      ) where

    import Control.Monad ((<$!>))
    import Data.ByteString (ByteString)
    import Data.String (IsString (fromString))
    import HsLua.Core.Error
    import HsLua.Core.Types
      (LuaE, Name (Name), Status, StackIndex, liftLua, multret, runWith)
    import Lua (top)
    import Lua.Auxiliary
    import Lua.Ersatz.Auxiliary
    import Foreign.Marshal.Alloc (alloca)
    import Foreign.Ptr

    import qualified Data.ByteString as B
    import qualified GHC.Foreign as GHC
    import qualified GHC.IO.Encoding as GHC
    import qualified HsLua.Core.Primary as Lua
    import qualified HsLua.Core.Types as Lua
    import qualified Foreign.Storable as Storable

    -- | Grows the stack size to @top + sz@ elements, raising an error if
    -- the stack cannot grow to that size. @msg@ is an additional text to go
    -- into the error message (or the empty string for no additional text).
    checkstack' :: LuaError e
                => Int    -- ^ sz (requested additional size)
                -> String -- ^ msg
                -> LuaE e ()
    checkstack' :: forall e. LuaError e => Int -> String -> LuaE e ()
    checkstack' Int
    sz String
    msg =
      Int -> LuaE e Bool
    forall e. Int -> LuaE e Bool
    Lua.checkstack Int
    sz LuaE e Bool -> (Bool -> LuaE e ()) -> LuaE e ()
    forall a b. LuaE e a -> (a -> LuaE e b) -> LuaE e b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \case
        Bool
    True  -> () -> LuaE e ()
    forall a. a -> LuaE e a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure ()
        Bool
    False -> String -> LuaE e ()
    forall e a. LuaError e => String -> LuaE e a
    failLua (String -> LuaE e ()) -> String -> LuaE e ()
    forall a b. (a -> b) -> a -> b
    $
          if String
    msg String -> String -> Bool
    forall a. Eq a => a -> a -> Bool
    == String
    ""
          then String
    "stack overflow"
          else String
    "stack overflow (" String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    msg String -> String -> String
    forall a. [a] -> [a] -> [a]
    ++ String
    ")"

    -- | Loads and runs the given string.
    --
    -- Returns 'Lua.OK' on success, or an error if either loading of the
    -- string or calling of the thunk failed.
    dostring :: ByteString -> LuaE e Status
    dostring :: forall e. ByteString -> LuaE e Status
    dostring ByteString
    s = ByteString -> LuaE e Status
    forall e. ByteString -> LuaE e Status
    loadstring ByteString
    s LuaE e Status -> (Status -> LuaE e Status) -> LuaE e Status
    forall a b. LuaE e a -> (a -> LuaE e b) -> LuaE e b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \case
      Status
    Lua.OK -> NumArgs -> NumResults -> Maybe StackIndex -> LuaE e Status
    forall e.
    NumArgs -> NumResults -> Maybe StackIndex -> LuaE e Status
    Lua.pcall NumArgs
    0 NumResults
    multret Maybe StackIndex
    forall a. Maybe a
    Nothing
      Status
    err    -> Status -> LuaE e Status
    forall a. a -> LuaE e a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Status
    err
    {-# INLINABLE dostring #-}

    -- | Loads and runs the given file. Note that the filepath is
    -- interpreted by Lua, not Haskell. The resulting chunk is named using
    -- the UTF8 encoded filepath.
    dofile :: Maybe FilePath -> LuaE e Status
    dofile :: forall e. Maybe String -> LuaE e Status
    dofile Maybe String
    mfp = Maybe String -> LuaE e Status
    forall e. Maybe String -> LuaE e Status
    loadfile Maybe String
    mfp LuaE e Status -> (Status -> LuaE e Status) -> LuaE e Status
    forall a b. LuaE e a -> (a -> LuaE e b) -> LuaE e b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= \case
      Status
    Lua.OK -> NumArgs -> NumResults -> Maybe StackIndex -> LuaE e Status
    forall e.
    NumArgs -> NumResults -> Maybe StackIndex -> LuaE e Status
    Lua.pcall NumArgs
    0 NumResults
    multret Maybe StackIndex
    forall a. Maybe a
    Nothing
      Status
    err    -> Status -> LuaE e Status
    forall a. a -> LuaE e a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Status
    err
    {-# INLINABLE dofile #-}

    -- | 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.TypeNil'.
    --
    -- Wraps 'luaL_getmetafield'.
    getmetafield :: StackIndex -- ^ obj
                 -> Name       -- ^ e
                 -> LuaE e Lua.Type
    getmetafield :: forall e. StackIndex -> Name -> LuaE e Type
    getmetafield StackIndex
    obj (Name ByteString
    name) = (State -> IO Type) -> LuaE e Type
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO Type) -> LuaE e Type)
    -> (State -> IO Type) -> LuaE e Type
    forall a b. (a -> b) -> a -> b
    $ \State
    l ->
      ByteString -> (CString -> IO Type) -> IO Type
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    name ((CString -> IO Type) -> IO Type)
    -> (CString -> IO Type) -> IO Type
    forall a b. (a -> b) -> a -> b
    $! (TypeCode -> Type) -> IO TypeCode -> IO Type
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap TypeCode -> Type
    Lua.toType (IO TypeCode -> IO Type)
    -> (CString -> IO TypeCode) -> CString -> IO Type
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . State -> StackIndex -> CString -> IO TypeCode
    luaL_getmetafield State
    l StackIndex
    obj
    {-# INLINABLE getmetafield #-}

    -- | Pushes onto the stack the metatable associated with name @tname@ in
    -- the registry (see 'newmetatable') (@nil@ if there is no metatable
    -- associated with that name). Returns the type of the pushed value.
    --
    -- Wraps 'luaL_getmetatable'.
    getmetatable' :: Name      -- ^ tname
                  -> LuaE e Lua.Type
    getmetatable' :: forall e. Name -> LuaE e Type
    getmetatable' (Name ByteString
    tname) = (State -> IO Type) -> LuaE e Type
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO Type) -> LuaE e Type)
    -> (State -> IO Type) -> LuaE e Type
    forall a b. (a -> b) -> a -> b
    $ \State
    l ->
      ByteString -> (CString -> IO Type) -> IO Type
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    tname ((CString -> IO Type) -> IO Type)
    -> (CString -> IO Type) -> IO Type
    forall a b. (a -> b) -> a -> b
    $ (TypeCode -> Type) -> IO TypeCode -> IO Type
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap TypeCode -> Type
    Lua.toType (IO TypeCode -> IO Type)
    -> (CString -> IO TypeCode) -> CString -> IO Type
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . State -> CString -> IO TypeCode
    luaL_getmetatable State
    l
    {-# INLINABLE getmetatable' #-}

    -- | Push referenced value from the table at the given index.
    getref :: LuaError e => StackIndex -> Reference -> LuaE e Lua.Type
    getref :: forall e. LuaError e => StackIndex -> Reference -> LuaE e Type
    getref StackIndex
    idx Reference
    ref' = StackIndex -> Integer -> LuaE e Type
    forall e. LuaError e => StackIndex -> Integer -> LuaE e Type
    Lua.rawgeti StackIndex
    idx (CInt -> Integer
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Reference -> CInt
    Lua.fromReference Reference
    ref'))
    {-# INLINABLE getref #-}

    -- | Ensures that the value @t[fname]@, where @t@ is the value at index
    -- @idx@, is a table, and pushes that table onto the stack. Returns True
    -- if it finds a previous table there and False if it creates a new
    -- table.
    getsubtable :: LuaError e
                => StackIndex   -- ^ idx
                -> Name         -- ^ fname
                -> LuaE e Bool
    getsubtable :: forall e. LuaError e => StackIndex -> Name -> LuaE e Bool
    getsubtable StackIndex
    idx fname :: Name
    fname@(Name ByteString
    namestr) = do
      -- This is a reimplementation of luaL_getsubtable from lauxlib.c.
      idx' <- StackIndex -> LuaE e StackIndex
    forall e. StackIndex -> LuaE e StackIndex
    Lua.absindex StackIndex
    idx
      Lua.pushstring namestr
      Lua.gettable idx' >>= \case
        Type
    Lua.TypeTable -> Bool -> LuaE e Bool
    forall a. a -> LuaE e a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    True
        Type
    _ -> do
          Int -> LuaE e ()
    forall e. Int -> LuaE e ()
    Lua.pop Int
    1
          LuaE e ()
    forall e. LuaE e ()
    Lua.newtable
          StackIndex -> LuaE e ()
    forall e. StackIndex -> LuaE e ()
    Lua.pushvalue StackIndex
    top -- copy to be left at top
          StackIndex -> Name -> LuaE e ()
    forall e. LuaError e => StackIndex -> Name -> LuaE e ()
    Lua.setfield StackIndex
    idx' Name
    fname
          Bool -> LuaE e Bool
    forall a. a -> LuaE e a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    False
    {-# INLINABLE getsubtable #-}

    -- | Loads a ByteString as a Lua chunk.
    --
    -- This function returns the same results as @'Lua.load'@. @name@ is the
    -- chunk name, used for debug information and error messages. Note that
    -- @name@ is used as a C string, so it may not contain null-bytes.
    --
    -- Wraps 'luaL_loadbuffer'.
    loadbuffer :: ByteString -- ^ Program to load
               -> Name       -- ^ chunk name
               -> LuaE e Status
    loadbuffer :: forall e. ByteString -> Name -> LuaE e Status
    loadbuffer ByteString
    bs (Name ByteString
    name) = (State -> IO Status) -> LuaE e Status
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO Status) -> LuaE e Status)
    -> (State -> IO Status) -> LuaE e Status
    forall a b. (a -> b) -> a -> b
    $ \State
    l ->
      ByteString -> (CStringLen -> IO Status) -> IO Status
    forall a. ByteString -> (CStringLen -> IO a) -> IO a
    B.useAsCStringLen ByteString
    bs ((CStringLen -> IO Status) -> IO Status)
    -> (CStringLen -> IO Status) -> IO Status
    forall a b. (a -> b) -> a -> b
    $ \(CString
    str, Int
    len) ->
      ByteString -> (CString -> IO Status) -> IO Status
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    name ((CString -> IO Status) -> IO Status)
    -> (CString -> IO Status) -> IO Status
    forall a b. (a -> b) -> a -> b
    $!
        (StatusCode -> Status) -> IO StatusCode -> IO Status
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap StatusCode -> Status
    Lua.toStatus (IO StatusCode -> IO Status)
    -> (CString -> IO StatusCode) -> CString -> IO Status
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . State -> CString -> CSize -> CString -> IO StatusCode
    luaL_loadbuffer State
    l CString
    str (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    len)
    {-# INLINABLE loadbuffer #-}

    -- | Loads a file as a Lua chunk. This function uses @lua_load@ (see
    -- @'Lua.load'@) to load the chunk in the file named @filename@. If
    -- filename is @Nothing@, 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.
    --
    -- See <https://www.lua.org/manual/5.4/manual.html#luaL_loadfile luaL_loadfile>.
    loadfile :: Maybe FilePath -- ^ filename
             -> LuaE e Status
    loadfile :: forall e. Maybe String -> LuaE e Status
    loadfile Maybe String
    mfp = (State -> IO Status) -> LuaE e Status
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO Status) -> LuaE e Status)
    -> (State -> IO Status) -> LuaE e Status
    forall a b. (a -> b) -> a -> b
    $ \State
    l -> do
    #if defined(mingw32_HOST_OS)
      fsEncoding <- GHC.mkTextEncoding "CP0"  -- a.k.a CP_ACP
    #else
      fsEncoding <- IO TextEncoding
    GHC.getFileSystemEncoding
    #endif
      case mfp of
        Just String
    fp ->
          TextEncoding -> String -> (CString -> IO Status) -> IO Status
    forall a. TextEncoding -> String -> (CString -> IO a) -> IO a
    GHC.withCString TextEncoding
    fsEncoding String
    fp ((CString -> IO Status) -> IO Status)
    -> (CString -> IO Status) -> IO Status
    forall a b. (a -> b) -> a -> b
    $! (StatusCode -> Status) -> IO StatusCode -> IO Status
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap StatusCode -> Status
    Lua.toStatus (IO StatusCode -> IO Status)
    -> (CString -> IO StatusCode) -> CString -> IO Status
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . State -> CString -> IO StatusCode
    luaL_loadfile State
    l
        Maybe String
    Nothing ->
          StatusCode -> Status
    Lua.toStatus (StatusCode -> Status) -> IO StatusCode -> IO Status
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> State -> CString -> IO StatusCode
    luaL_loadfile State
    l CString
    forall a. Ptr a
    nullPtr
    {-# INLINABLE loadfile #-}

    -- | Loads a string as a Lua chunk. This function uses @lua_load@ to
    -- load the chunk in the given ByteString. The given string may not
    -- contain any NUL characters.
    --
    -- This function returns the same results as @lua_load@ (see
    -- @'Lua.load'@).
    --
    -- Also as @'Lua.load'@, this function only loads the chunk; it does not
    -- run it.
    --
    -- See
    -- <https://www.lua.org/manual/5.4/manual.html#luaL_loadstring luaL_loadstring>.
    loadstring :: ByteString -> LuaE e Status
    loadstring :: forall e. ByteString -> LuaE e Status
    loadstring ByteString
    s = ByteString -> Name -> LuaE e Status
    forall e. ByteString -> Name -> LuaE e Status
    loadbuffer ByteString
    s (ByteString -> Name
    Name ByteString
    s)
    {-# INLINE loadstring #-}

    -- | If the registry already has the key tname, returns @False@.
    -- 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 @True@. (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.
    --
    -- The value of @tname@ is used as a C string and hence must not contain
    -- null bytes.
    --
    -- Wraps 'luaL_newmetatable'.
    newmetatable :: Name -> LuaE e Bool
    newmetatable :: forall e. Name -> LuaE e Bool
    newmetatable (Name ByteString
    tname) = (State -> IO Bool) -> LuaE e Bool
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO Bool) -> LuaE e Bool)
    -> (State -> IO Bool) -> LuaE e Bool
    forall a b. (a -> b) -> a -> b
    $ \State
    l ->
      LuaBool -> Bool
    Lua.fromLuaBool (LuaBool -> Bool) -> IO LuaBool -> IO Bool
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> ByteString -> (CString -> IO LuaBool) -> IO LuaBool
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    tname (State -> CString -> IO LuaBool
    luaL_newmetatable State
    l)
    {-# INLINABLE newmetatable #-}

    -- | Creates a new Lua state. It calls @lua_newstate@ with an allocator
    -- based on the standard C @realloc@ function and then sets a panic
    -- function (see <https://www.lua.org/manual/5.4/manual.html#4.4 §4.4>
    -- of the Lua 5.4 Reference Manual) that prints an error message to the
    -- standard error output in case of fatal errors.
    --
    -- Wraps 'hsluaL_newstate'. See also:
    -- <https://www.lua.org/manual/5.4/manual.html#luaL_newstate luaL_newstate>.
    newstate :: IO Lua.State
    newstate :: IO State
    newstate = IO State
    hsluaL_newstate
    {-# INLINE newstate #-}

    -- | 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@, @ref@ ensures the uniqueness of the
    -- key it returns. You can retrieve an object referred by reference @r@
    -- by calling @rawgeti t r@. Function @'unref'@ frees a reference and
    -- its associated object.
    --
    -- If the object at the top of the stack is nil, @'ref'@ returns the
    -- constant @'Lua.refnil'@. The constant @'Lua.noref'@ is guaranteed to
    -- be different from any reference returned by @'ref'@.
    --
    -- Wraps 'luaL_ref'.
    ref :: StackIndex -> LuaE e Reference
    ref :: forall e. StackIndex -> LuaE e Reference
    ref StackIndex
    t = (State -> IO Reference) -> LuaE e Reference
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO Reference) -> LuaE e Reference)
    -> (State -> IO Reference) -> LuaE e Reference
    forall a b. (a -> b) -> a -> b
    $ \State
    l -> CInt -> Reference
    Lua.toReference (CInt -> Reference) -> IO CInt -> IO Reference
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> State -> StackIndex -> IO CInt
    luaL_ref State
    l StackIndex
    t
    {-# INLINABLE ref #-}

    -- | If @modname@ is not already present in @package.loaded@. calls
    -- function @openf@ with string @modname@ as an argument and sets the
    -- call result in @package.loaded[modname]@, as if that function has
    -- been called through
    -- <https://www.lua.org/manual/5.4/manual.html#pdf-require require>.
    --
    -- If @glb@ is true, also stores the module into global @modname@.
    --
    -- Leaves a copy of the module on the stack.
    --
    -- See 'requirehs' for a version intended to be used with Haskell
    -- actions.
    requiref :: LuaError e
             => Name          -- ^ modname
             -> Lua.CFunction -- ^ openf
             -> Bool          -- ^ glb
             -> LuaE e ()
    requiref :: forall e. LuaError e => Name -> CFunction -> Bool -> LuaE e ()
    requiref (Name ByteString
    name) CFunction
    openf Bool
    glb = (State -> Ptr StatusCode -> IO ()) -> LuaE e ()
    forall e a.
    LuaError e =>
    (State -> Ptr StatusCode -> IO a) -> LuaE e a
    liftLuaThrow ((State -> Ptr StatusCode -> IO ()) -> LuaE e ())
    -> (State -> Ptr StatusCode -> IO ()) -> LuaE e ()
    forall a b. (a -> b) -> a -> b
    $ \State
    l Ptr StatusCode
    status' ->
      ByteString -> (CString -> IO ()) -> IO ()
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    name ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \CString
    namePtr ->
        State -> CString -> CFunction -> LuaBool -> Ptr StatusCode -> IO ()
    hsluaL_requiref State
    l CString
    namePtr CFunction
    openf (Bool -> LuaBool
    Lua.toLuaBool Bool
    glb) Ptr StatusCode
    status'

    -- | Converts any Lua value at the given index to a 'ByteString' in a
    -- reasonable format. The resulting string is pushed onto the stack and
    -- also returned by the function.
    --
    -- If the value has a metatable with a @__tostring@ field, then
    -- @tolstring'@ calls the corresponding metamethod with the value as
    -- argument, and uses the result of the call as its result.
    --
    -- Wraps 'hsluaL_tolstring'.
    tostring' :: forall e. LuaError e => StackIndex -> LuaE e B.ByteString
    tostring' :: forall e. LuaError e => StackIndex -> LuaE e ByteString
    tostring' StackIndex
    n = do
      l <- LuaE e State
    forall e. LuaE e State
    Lua.state
      Lua.liftIO $ alloca $ \Ptr CSize
    lenPtr -> do
        cstr <- State -> StackIndex -> Ptr CSize -> IO CString
    hsluaL_tolstring State
    l StackIndex
    n Ptr CSize
    lenPtr
        if cstr == nullPtr
          then runWith @e l throwErrorAsException
          else do
            cstrLen <- Storable.peek lenPtr
            B.packCStringLen (cstr, fromIntegral cstrLen)
    {-# INLINABLE tostring' #-}

    -- | Creates and pushes a traceback of the stack L1. If a message is
    -- given it is appended at the beginning of the traceback. The level
    -- parameter tells at which level to start the traceback.
    --
    -- Wraps 'luaL_traceback'.
    traceback :: Lua.State -> Maybe ByteString -> Int -> LuaE e ()
    traceback :: forall e. State -> Maybe ByteString -> Int -> LuaE e ()
    traceback State
    l1 Maybe ByteString
    msg Int
    level = (State -> IO ()) -> LuaE e ()
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO ()) -> LuaE e ()) -> (State -> IO ()) -> LuaE e ()
    forall a b. (a -> b) -> a -> b
    $ \State
    l ->
      case Maybe ByteString
    msg of
        Maybe ByteString
    Nothing -> State -> State -> CString -> CInt -> IO ()
    luaL_traceback State
    l State
    l1 CString
    forall a. Ptr a
    nullPtr (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    level)
        Just ByteString
    msg' -> ByteString -> (CString -> IO ()) -> IO ()
    forall a. ByteString -> (CString -> IO a) -> IO a
    B.useAsCString ByteString
    msg' ((CString -> IO ()) -> IO ()) -> (CString -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \CString
    cstr ->
          State -> State -> CString -> CInt -> IO ()
    luaL_traceback State
    l State
    l1 CString
    cstr (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    level)
    {-# INLINABLE traceback #-}

    -- | Releases reference @'ref'@ from the table at index @idx@ (see
    -- @'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.
    --
    -- Wraps 'luaL_unref'. See also:
    -- <https://www.lua.org/manual/5.4/manual.html#luaL_unref luaL_unref>.
    unref :: StackIndex -- ^ idx
          -> Reference  -- ^ ref
          -> LuaE e ()
    unref :: forall e. StackIndex -> Reference -> LuaE e ()
    unref StackIndex
    idx Reference
    r = (State -> IO ()) -> LuaE e ()
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO ()) -> LuaE e ()) -> (State -> IO ()) -> LuaE e ()
    forall a b. (a -> b) -> a -> b
    $ \State
    l ->
      State -> StackIndex -> CInt -> IO ()
    luaL_unref State
    l StackIndex
    idx (Reference -> CInt
    Lua.fromReference Reference
    r)
    {-# INLINABLE unref #-}

    -- | 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.
    where' :: Int        -- ^ lvl
           -> LuaE e ()
    where' :: forall e. Int -> LuaE e ()
    where' Int
    lvl = (State -> IO ()) -> LuaE e ()
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO ()) -> LuaE e ()) -> (State -> IO ()) -> LuaE e ()
    forall a b. (a -> b) -> a -> b
    $ \State
    l -> State -> CInt -> IO ()
    luaL_where State
    l (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    lvl)
    {-# INLINABLE where' #-}

    --
    -- Registry fields
    --

    -- | Key to the registry field that holds the table of loaded modules.
    loaded :: Name
    loaded :: Name
    loaded = String -> Name
    forall a. IsString a => String -> a
    fromString String
    loadedTableRegistryField

    -- | Key to the registry field that holds the table of loader functions.
    preload :: Name
    preload :: Name
    preload = String -> Name
    forall a. IsString a => String -> a
    fromString String
    preloadTableRegistryField