{-|
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