    {-# LANGUAGE DeriveDataTypeable #-}
    module SDL.Raw.Error (
      -- * Error Handling
      SDLError(..),
      throwError,

      -- * Manual Error Handling
      clearError,
      getError,
      setError
    ) where

    import Control.Exception
    import Control.Monad.Catch
    import Control.Monad.IO.Class
    import Data.Typeable
    import Foreign.C.String
    import Foreign.C.Types

    -- | Note: the 'CString' is only valid until the next SDL function call. If you
    -- need to preserve the error message, make a copy of it.
    newtype SDLError = SDLError CString
      deriving (Eq, Show, Typeable)

    instance Exception SDLError

    foreign import ccall "SDL.h SDL_ClearError" clearErrorFFI :: IO ()
    foreign import ccall "SDL.h SDL_GetError" getErrorFFI :: IO CString
    foreign import ccall "sdlhelper.c SDLHelper_SetError" setErrorFFI :: CString -> IO CInt

    throwError :: (MonadThrow m, MonadIO m) => m ()
    throwError = getError >>= throwM . SDLError

    clearError :: MonadIO m => m ()
    clearError = liftIO clearErrorFFI
    {-# INLINE clearError #-}

    getError :: MonadIO m => m CString
    getError = liftIO getErrorFFI
    {-# INLINE getError #-}

    setError :: MonadIO m => CString -> m CInt
    setError v1 = liftIO $ setErrorFFI v1
    {-# INLINE setError #-}