    {-|
    Module      : HsLua.Module.SystemUtils
    Copyright   : © 2019-2025 Albert Krewinkel
    License     : MIT
    Maintainer  : Albert Krewinkel <tarleb@hslua.org>

    Utility functions and types for HsLua's system module.
    -}
    module HsLua.Module.SystemUtils
      ( Callback (..)
      , peekCallback
      , invoke
      , invokeWithFilePath
      , ioToLua
      )
    where

    import Control.Exception (IOException, try)
    import HsLua.Core hiding (try)
    import HsLua.Marshalling

    -- | Lua callback function. This type is similar to @'AnyValue'@, and
    -- the same caveats apply.
    newtype Callback = Callback StackIndex

    peekCallback :: Peeker e Callback
    peekCallback :: forall e. Peeker e Callback
    peekCallback = Name
    -> (StackIndex -> LuaE e (Maybe Callback)) -> Peeker e Callback
    forall e a. Name -> (StackIndex -> LuaE e (Maybe a)) -> Peeker e a
    reportValueOnFailure Name
    "function" ((StackIndex -> LuaE e (Maybe Callback)) -> Peeker e Callback)
    -> (StackIndex -> LuaE e (Maybe Callback)) -> Peeker e Callback
    forall a b. (a -> b) -> a -> b
    $ \StackIndex
    idx -> do
      idx' <- StackIndex -> LuaE e StackIndex
    forall e. StackIndex -> LuaE e StackIndex
    absindex StackIndex
    idx
      isFn <- isfunction idx'
      return $ if isFn
               then Just $ Callback idx'
               else Nothing

    pushCallback :: Pusher e Callback
    pushCallback :: forall e. Pusher e Callback
    pushCallback (Callback StackIndex
    idx) = StackIndex -> LuaE e ()
    forall e. StackIndex -> LuaE e ()
    pushvalue StackIndex
    idx

    -- | Call Lua callback function and return all of its results.
    invoke :: LuaError e
           => Callback -> LuaE e NumResults
    invoke :: forall e. LuaError e => Callback -> LuaE e NumResults
    invoke Callback
    callback = do
      oldTop <- LuaE e StackIndex
    forall e. LuaE e StackIndex
    gettop
      pushCallback callback
      call 0 multret
      newTop <- gettop
      return . NumResults . fromStackIndex $
        newTop - oldTop

    -- | Call Lua callback function with the given filename as its argument.
    invokeWithFilePath :: LuaError e
                       => Callback -> FilePath -> LuaE e NumResults
    invokeWithFilePath :: forall e. LuaError e => Callback -> String -> LuaE e NumResults
    invokeWithFilePath Callback
    callback String
    filename = do
      oldTop <- LuaE e StackIndex
    forall e. LuaE e StackIndex
    gettop
      pushCallback callback
      pushString filename
      call (NumArgs 1) multret
      newTop <- gettop
      return . NumResults . fromStackIndex $
        newTop - oldTop

    -- | Convert a System IO operation to a Lua operation.
    ioToLua :: LuaError e => IO a -> LuaE e a
    ioToLua :: forall e a. LuaError e => IO a -> LuaE e a
    ioToLua IO a
    action = do
      result <- IO (Either IOException a) -> LuaE e (Either IOException a)
    forall a. IO a -> LuaE e a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IO a -> IO (Either IOException a)
    forall e a. Exception e => IO a -> IO (Either e a)
    try IO a
    action)
      case result of
        Right a
    result' -> a -> LuaE e a
    forall a. a -> LuaE e a
    forall (m :: * -> *) a. Monad m => a -> m a
    return a
    result'
        Left IOException
    err      -> String -> LuaE e a
    forall e a. LuaError e => String -> LuaE e a
    failLua (IOException -> String
    forall a. Show a => a -> String
    show (IOException
    err :: IOException))