    {-# LANGUAGE OverloadedStrings     #-}
    {-# LANGUAGE RankNTypes            #-}
    {-|
    Module      : HsLua.Class.Invokable
    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 : FlexibleInstances, ForeignFunctionInterface, ScopedTypeVariables

    Call Lua functions from Haskell.
    -}
    module HsLua.Class.Invokable
      ( Invokable (..)
      , invoke
      ) where

    import Data.ByteString (append)
    import HsLua.Core as Lua
    import HsLua.Class.Peekable
    import HsLua.Class.Pushable
    import HsLua.Class.Util (popValue)

    -- | Helper class used to make Lua functions useable from Haskell.
    class Invokable a where
      addArg :: Name -> (forall e. LuaError e => LuaE e ()) -> NumArgs -> a

    instance (LuaError e, Peekable a) => Invokable (LuaE e a) where
      addArg :: Name -> (forall e. LuaError e => LuaE e ()) -> NumArgs -> LuaE e a
    addArg Name
    fnName forall e. LuaError e => LuaE e ()
    pushArgs NumArgs
    nargs = do
        _ <- ByteString -> LuaE e Status
    forall e. ByteString -> LuaE e Status
    dostring (ByteString -> LuaE e Status) -> ByteString -> LuaE e Status
    forall a b. (a -> b) -> a -> b
    $ ByteString
    "return " ByteString -> ByteString -> ByteString
    `append` Name -> ByteString
    Lua.fromName Name
    fnName
        pushArgs
        call nargs 1
        popValue

    instance (Pushable a, Invokable b) => Invokable (a -> b) where
      addArg :: Name -> (forall e. LuaError e => LuaE e ()) -> NumArgs -> a -> b
    addArg Name
    fnName forall e. LuaError e => LuaE e ()
    pushArgs NumArgs
    nargs a
    x =
        Name -> (forall e. LuaError e => LuaE e ()) -> NumArgs -> b
    forall a.
    Invokable a =>
    Name -> (forall e. LuaError e => LuaE e ()) -> NumArgs -> a
    addArg Name
    fnName (LuaE e ()
    forall e. LuaError e => LuaE e ()
    pushArgs LuaE e () -> LuaE e () -> LuaE e ()
    forall a b. LuaE e a -> LuaE e b -> LuaE e b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> a -> LuaE e ()
    forall e. LuaError e => a -> LuaE e ()
    forall a e. (Pushable a, LuaError e) => a -> LuaE e ()
    push a
    x) (NumArgs
    nargs NumArgs -> NumArgs -> NumArgs
    forall a. Num a => a -> a -> a
    + NumArgs
    1)

    -- | Invoke a Lua function. Use as:
    --
    -- > v <- invoke "proc" "abc" (1::Int) (5.0::Double)
    invoke :: Invokable a => Name -> a
    invoke :: forall a. Invokable a => Name -> a
    invoke Name
    fname = Name -> (forall e. LuaError e => LuaE e ()) -> NumArgs -> a
    forall a.
    Invokable a =>
    Name -> (forall e. LuaError e => LuaE e ()) -> NumArgs -> a
    addArg Name
    fname (() -> LuaE e ()
    forall a. a -> LuaE e a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()) NumArgs
    0