{-# LANGUAGE ScopedTypeVariables #-} {-| Module : HsLua.Class.Util Copyright : © 2007–2012 Gracjan Polak; © 2012–2016 Ömer Sinan Ağacan; © 2017-2021 Albert Krewinkel License : MIT Maintainer : Albert Krewinkel Stability : beta Portability : non-portable (depends on GHC) HsLua utility functions. -} module HsLua.Class.Util ( raiseError , Optional (Optional, fromOptional) -- * getting values , peekEither , popValue ) where import HsLua.Core (LuaE, NumResults, StackIndex, top) import HsLua.Class.Peekable (Peekable (peek), PeekError) import HsLua.Class.Pushable (Pushable (push)) import qualified Control.Monad.Catch as Catch import qualified HsLua.Core as Lua -- | Raise a Lua error, using the given value as the error object. raiseError :: (PeekError e, Pushable a) => a -> LuaE e NumResults raiseError e = do push e Lua.error {-# INLINABLE raiseError #-} -- | Newtype wrapper intended to be used for optional Lua values. Nesting this -- type is strongly discouraged as missing values on inner levels are -- indistinguishable from missing values on an outer level; wrong values -- would be the likely result. newtype Optional a = Optional { fromOptional :: Maybe a } instance Peekable a => Peekable (Optional a) where peek idx = do noValue <- Lua.isnoneornil idx if noValue then return $ Optional Nothing else Optional . Just <$> peek idx instance Pushable a => Pushable (Optional a) where push (Optional Nothing) = Lua.pushnil push (Optional (Just x)) = push x -- -- Getting Values -- -- | Try to convert the value at the given stack index to a Haskell value. -- Returns 'Left' with the error on failure. peekEither :: (PeekError e, Peekable a) => StackIndex -> LuaE e (Either e a) peekEither = Lua.try . peek -- | Get, then pop the value at the top of the stack. The pop operation is -- executed even if the retrieval operation failed. popValue :: (PeekError e, Peekable a) => LuaE e a popValue = peek top `Catch.finally` Lua.pop 1 {-# INLINABLE popValue #-}