    {-|
    Module      : HsLua.Core.Debug
    Copyright   : © 2023-2024 Albert Krewinkel
    License     : MIT
    Maintainer  : Albert Krewinkel <tarleb@hslua.org>

    Bindings to Lua's debug interface.
    -}
    module HsLua.Core.Debug
      ( getupvalue
      , setupvalue
      ) where

    import Control.Monad ((<$!>))
    import Foreign.C (CString)
    import Foreign.Ptr (nullPtr)
    import HsLua.Core.Types (LuaE, Name (Name), StackIndex, liftLua)
    import Lua.Debug (lua_getupvalue, lua_setupvalue)
    import qualified Data.ByteString as B

    -- | Gets information about the @n@-th upvalue of the closure at index
    -- @funcindex@. It pushes the upvalue's value onto the stack and returns
    -- its name. Returns 'Nothing' (and pushes nothing) when the index @n@
    -- is greater than the number of upvalues.
    --
    -- See
    -- <https://www.lua.org/manual/5.4/manual.html#pdf-debug.getupvalue debug.getupvalue>
    -- for more information about upvalues.
    --
    -- @[0, +(0|1), -]@
    --
    -- Wraps 'lua_getupvalue'.
    getupvalue :: StackIndex   -- ^ funcindex
               -> Int          -- ^ n
               -> LuaE e (Maybe Name)
    getupvalue :: forall e. StackIndex -> Int -> LuaE e (Maybe Name)
    getupvalue StackIndex
    idx Int
    n = (State -> IO (Maybe Name)) -> LuaE e (Maybe Name)
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO (Maybe Name)) -> LuaE e (Maybe Name))
    -> (State -> IO (Maybe Name)) -> LuaE e (Maybe Name)
    forall a b. (a -> b) -> a -> b
    $ \State
    l ->
      State -> StackIndex -> CInt -> IO CString
    lua_getupvalue State
    l StackIndex
    idx (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    n) IO CString -> (CString -> IO (Maybe Name)) -> IO (Maybe Name)
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= CString -> IO (Maybe Name)
    toMaybeName

    -- | Sets the value of a closure’s upvalue. It assigns the value on the
    -- top of the stack to the upvalue and returns its name. It also pops
    -- the value from the stack.
    --
    -- Returns 'Nothing' (and pops nothing) when the index @n@ is greater
    -- than the number of upvalues.
    --
    -- Parameters @funcindex@ and @n@ are as in the function 'getupvalue'.
    --
    -- @[-(0|1), +0, -]@
    --
    -- Wraps 'lua_setupvalue'.
    setupvalue :: StackIndex   -- ^ funcindex
               -> Int          -- ^ n
               -> LuaE e (Maybe Name)
    setupvalue :: forall e. StackIndex -> Int -> LuaE e (Maybe Name)
    setupvalue StackIndex
    idx Int
    n = (State -> IO (Maybe Name)) -> LuaE e (Maybe Name)
    forall a e. (State -> IO a) -> LuaE e a
    liftLua ((State -> IO (Maybe Name)) -> LuaE e (Maybe Name))
    -> (State -> IO (Maybe Name)) -> LuaE e (Maybe Name)
    forall a b. (a -> b) -> a -> b
    $ \State
    l ->
      State -> StackIndex -> CInt -> IO CString
    lua_setupvalue State
    l StackIndex
    idx (Int -> CInt
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    n) IO CString -> (CString -> IO (Maybe Name)) -> IO (Maybe Name)
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= CString -> IO (Maybe Name)
    toMaybeName

    -- | Convert a (possibly @NULL@) null-terminated C string to a name.
    toMaybeName :: CString -> IO (Maybe Name)
    toMaybeName :: CString -> IO (Maybe Name)
    toMaybeName CString
    cstr =
      if CString
    cstr CString -> CString -> Bool
    forall a. Eq a => a -> a -> Bool
    == CString
    forall a. Ptr a
    nullPtr
        then Maybe Name -> IO (Maybe Name)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe Name
    forall a. Maybe a
    Nothing
        else Name -> Maybe Name
    forall a. a -> Maybe a
    Just (Name -> Maybe Name)
    -> (ByteString -> Name) -> ByteString -> Maybe Name
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> Name
    Name (ByteString -> Maybe Name) -> IO ByteString -> IO (Maybe Name)
    forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
    <$!> CString -> IO ByteString
    B.packCString CString
    cstr