{-# LINE 1 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
----------------------------------------------------------------------------
-- |
-- Module      :  Data.Emacs.Module.Raw.Env
-- Copyright   :  (c) Sergey Vinokurov 2018
-- License     :  BSD3-style (see LICENSE)
-- Maintainer  :  serg.foo@gmail.com
--
-- Low-level and, hopefully, low-overhead wrappers around @struct emacs_env@.
----------------------------------------------------------------------------

{-# LANGUAGE FlexibleContexts         #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE ScopedTypeVariables      #-}
{-# LANGUAGE TemplateHaskell          #-}

{-# OPTIONS_HADDOCK not-home #-}

module Data.Emacs.Module.Raw.Env
  ( EnumFuncallExit(..)
  , UserPtrFinaliserType
  , UserPtrFinaliser
  , CBoolean
  , isTruthy
  , isValidEnv

  , makeGlobalRef
  , freeGlobalRef

  , nonLocalExitCheck
  , nonLocalExitGet
  , nonLocalExitSignal
  , nonLocalExitThrow
  , nonLocalExitClear

  , variadicFunctionArgs
  , makeFunction

  , funcall
  , funcallPrimitive
  , intern
  , typeOf
  , isNotNil
  , eq

  , extractInteger
  , makeInteger
  , extractFloat
  , makeFloat
  , copyStringContents
  , makeString
  , makeUserPtr
  , getUserPtr
  , setUserPtr
  , getUserFinaliser
  , setUserFinaliser
  , vecGet
  , vecSet
  , vecSize
  ) where

import Control.Monad.IO.Class

import Data.Coerce
import Foreign
import Foreign.C

import Data.Emacs.Module.NonNullPtr
import Data.Emacs.Module.Raw.Env.Internal as Env
import Data.Emacs.Module.Raw.Env.TH
import Data.Emacs.Module.Raw.Value

import Data.Emacs.Module.NonNullPtr.Internal



newtype EnumFuncallExit = EnumFuncallExit { unEnumFuncallExit :: CInt }

type UserPtrFinaliserType a = Ptr a -> IO ()
type UserPtrFinaliser a = FunPtr (UserPtrFinaliserType a)

-- | A wrapper around C value that denotes true or false.
newtype CBoolean = CBoolean (Word8)
{-# LINE 83 "src/Data/Emacs/Module/Raw/Env.hsc" #-}

{-# INLINE isTruthy #-}
-- | Check whether a 'CBoolean' denotes true.
isTruthy :: CBoolean -> Bool
isTruthy (CBoolean a) = a /= 0


{-# INLINE isValidEnv #-}
-- | Check wheter passed @emacs_env@ structure has expected size so that
-- we will be able to access all of its fields.
isValidEnv :: MonadIO m => Env -> m Bool
isValidEnv env = liftIO $ do
  realSize <- ((\hsc_ptr -> peekByteOff hsc_ptr 0)) (Env.toPtr env)
{-# LINE 96 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
  pure $ expectedSize <= realSize
  where
    expectedSize :: CPtrdiff
    expectedSize = ((232))
{-# LINE 100 "src/Data/Emacs/Module/Raw/Env.hsc" #-}

$(wrapEmacsFunc "makeGlobalRefTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 16)) |]
{-# LINE 103 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> IO RawValue |])

{-# INLINE makeGlobalRef #-}
makeGlobalRef
  :: forall m. MonadIO m
  => Env
  -> RawValue
  -> m GlobalRef
makeGlobalRef env x =
  liftIO $
    coerce
      (makeGlobalRefTH
        :: Env
        -> RawValue
        -> IO RawValue)
      env
      x


$(wrapEmacsFunc "freeGlobalRefTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 24)) |]
{-# LINE 124 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> IO () |])

{-# INLINE freeGlobalRef #-}
freeGlobalRef
  :: forall m. MonadIO m
  => Env
  -> GlobalRef
  -> m ()
freeGlobalRef env x =
  liftIO $
  coerce
    (freeGlobalRefTH :: Env -> RawValue -> IO ())
    env
    x


$(wrapEmacsFunc "nonLocalExitCheckTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 32)) |]
{-# LINE 142 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> IO EnumFuncallExit |])

{-# INLINE nonLocalExitCheck #-}
nonLocalExitCheck
  :: MonadIO m
  => Env
  -> m EnumFuncallExit
nonLocalExitCheck = nonLocalExitCheckTH


$(wrapEmacsFunc "nonLocalExitGetTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 48)) |]
{-# LINE 154 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> NonNullPtr RawValue -> NonNullPtr RawValue -> IO EnumFuncallExit |])

{-# INLINE nonLocalExitGet #-}
nonLocalExitGet
  :: MonadIO m
  => Env
  -> NonNullPtr RawValue -- ^ Symbol output
  -> NonNullPtr RawValue -- ^ Data output
  -> m EnumFuncallExit
nonLocalExitGet = nonLocalExitGetTH


$(wrapEmacsFunc "nonLocalExitSignalTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 56)) |]
{-# LINE 168 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> RawValue -> IO () |])

{-# INLINE nonLocalExitSignal #-}
nonLocalExitSignal
  :: MonadIO m
  => Env
  -> RawValue -- ^ Error symbol
  -> RawValue -- ^ Error data
  -> m ()
nonLocalExitSignal = nonLocalExitSignalTH


$(wrapEmacsFunc "nonLocalExitThrowTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 64)) |]
{-# LINE 182 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> RawValue -> IO () |])

{-# INLINE nonLocalExitThrow #-}
nonLocalExitThrow
  :: MonadIO m
  => Env
  -> RawValue -- ^ Tag, a symbol
  -> RawValue -- ^ Value
  -> m ()
nonLocalExitThrow = nonLocalExitThrowTH


$(wrapEmacsFunc "nonLocalExitClearTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 40)) |]
{-# LINE 196 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> IO () |])

{-# INLINE nonLocalExitClear #-}
nonLocalExitClear
  :: MonadIO m
  => Env
  -> m ()
nonLocalExitClear = nonLocalExitClearTH


variadicFunctionArgs :: CPtrdiff
variadicFunctionArgs = (-2)
{-# LINE 208 "src/Data/Emacs/Module/Raw/Env.hsc" #-}

$(wrapEmacsFunc "makeFunctionTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 72)) |]
{-# LINE 211 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| forall a. Env -> CPtrdiff -> CPtrdiff -> FunPtr (RawFunctionType a) -> CString -> Ptr a -> IO RawValue |])

{-# INLINE makeFunction #-}
makeFunction
  :: forall m a. MonadIO m
  => Env
  -> CPtrdiff      -- ^ Minimum arity
  -> CPtrdiff      -- ^ Maximum arity
  -> RawFunction a -- ^ Implementation
  -> CString       -- ^ Documentation
  -> Ptr a         -- ^ Extra data
  -> m RawValue
makeFunction =
  coerce
    (makeFunctionTH ::
         Env
      -> CPtrdiff
      -> CPtrdiff
      -> FunPtr (RawFunctionType a)
      -> CString
      -> Ptr a
      -> m RawValue)


$(wrapEmacsFunc "funcallTH" Safe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 80)) |]
{-# LINE 237 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> CPtrdiff -> NonNullPtr RawValue -> IO RawValue |])

{-# INLINE funcall #-}
funcall
  :: MonadIO m
  => Env
  -> RawValue            -- ^ Function
  -> CPtrdiff            -- ^ Number of arguments
  -> NonNullPtr RawValue -- ^ Actual arguments
  -> m RawValue
funcall = funcallTH


$(wrapEmacsFunc "funcallPrimitiveTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 80)) |]
{-# LINE 252 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> CPtrdiff -> NonNullPtr RawValue -> IO RawValue |])

{-# INLINE funcallPrimitive #-}
funcallPrimitive
  :: MonadIO m
  => Env
  -> RawValue            -- ^ Function
  -> CPtrdiff            -- ^ Number of arguments
  -> NonNullPtr RawValue -- ^ Actual arguments
  -> m RawValue
funcallPrimitive = funcallPrimitiveTH


$(wrapEmacsFunc "internTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 88)) |]
{-# LINE 267 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> CString -> IO RawValue |])

{-# INLINE intern #-}
intern
  :: MonadIO m
  => Env
  -> CString
  -> m RawValue
intern = internTH


$(wrapEmacsFunc "typeOfTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 96)) |]
{-# LINE 280 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> IO RawValue |])

{-# INLINE typeOf #-}
typeOf
  :: MonadIO m
  => Env
  -> RawValue
  -> m RawValue
typeOf = typeOfTH


$(wrapEmacsFunc "isNotNilTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 104)) |]
{-# LINE 293 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> IO CBoolean |])

{-# INLINE isNotNil #-}
isNotNil
  :: MonadIO m
  => Env
  -> RawValue
  -> m CBoolean
isNotNil = isNotNilTH


$(wrapEmacsFunc "eqTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 112)) |]
{-# LINE 306 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> RawValue -> IO CBoolean |])

{-# INLINE eq #-}
eq
  :: MonadIO m
  => Env
  -> RawValue
  -> RawValue
  -> m CBoolean
eq = eqTH


$(wrapEmacsFunc "extractIntegerTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 120)) |]
{-# LINE 320 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> IO CIntMax |])

{-# INLINE extractInteger #-}
extractInteger
  :: MonadIO m
  => Env
  -> RawValue
  -> m CIntMax
extractInteger = extractIntegerTH


$(wrapEmacsFunc "makeIntegerTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 128)) |]
{-# LINE 333 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> CIntMax -> IO RawValue |])

{-# INLINE makeInteger #-}
makeInteger
  :: MonadIO m
  => Env
  -> CIntMax
  -> m RawValue
makeInteger = makeIntegerTH


$(wrapEmacsFunc "extractFloatTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 136)) |]
{-# LINE 346 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> IO CDouble |])

{-# INLINE extractFloat #-}
extractFloat
  :: MonadIO m
  => Env
  -> RawValue
  -> m CDouble
extractFloat = extractFloatTH


$(wrapEmacsFunc "makeFloatTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 144)) |]
{-# LINE 359 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> CDouble -> IO RawValue |])

{-# INLINE makeFloat #-}
makeFloat
  :: MonadIO m
  => Env
  -> CDouble
  -> m RawValue
makeFloat = makeFloatTH


$(wrapEmacsFunc "copyStringContentsTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 152)) |]
{-# LINE 372 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> CString -> NonNullPtr CPtrdiff -> IO CBoolean |])

{-# INLINE copyStringContents #-}
-- |  Copy the content of the Lisp string VALUE to BUFFER as an utf8
-- null-terminated string.
--
-- SIZE must point to the total size of the buffer.  If BUFFER is
-- NULL or if SIZE is not big enough, write the required buffer size
-- to SIZE and return true.
--
-- Note that SIZE must include the last null byte (e.g. "abc" needs
-- a buffer of size 4).
--
-- Return true if the string was successfully copied.
copyStringContents
  :: MonadIO m
  => Env
  -> RawValue         -- ^ Emacs value that holds a string
  -> CString             -- ^ Destination, may be NULL
  -> NonNullPtr CPtrdiff -- ^ SIZE pointer
  -> m CBoolean
copyStringContents = copyStringContentsTH


$(wrapEmacsFunc "makeStringTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 160)) |]
{-# LINE 398 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> CString -> CPtrdiff -> IO RawValue |])

{-# INLINE makeString #-}
makeString
  :: MonadIO m
  => Env
  -> CString  -- ^ 0-terminated utf8-encoded string.
  -> CPtrdiff -- ^ Length.
  -> m RawValue
makeString = makeStringTH


$(wrapEmacsFunc "makeUserPtrTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 168)) |]
{-# LINE 412 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| forall a. Env -> UserPtrFinaliser a -> Ptr a -> IO RawValue |])

{-# INLINE makeUserPtr #-}
makeUserPtr
  :: forall m a. MonadIO m
  => Env
  -> UserPtrFinaliser a
  -> Ptr a
  -> m RawValue
makeUserPtr = makeUserPtrTH


$(wrapEmacsFunc "getUserPtrTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 176)) |]
{-# LINE 426 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| forall a. Env -> RawValue -> IO (Ptr a) |])

{-# INLINE getUserPtr #-}
getUserPtr
  :: MonadIO m
  => Env
  -> RawValue
  -> m (Ptr a)
getUserPtr = getUserPtrTH


$(wrapEmacsFunc "setUserPtrTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 184)) |]
{-# LINE 439 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| forall a. Env -> RawValue -> Ptr a -> IO () |])

{-# INLINE setUserPtr #-}
setUserPtr
  :: MonadIO m
  => Env
  -> RawValue
  -> Ptr a
  -> m ()
setUserPtr = setUserPtrTH


$(wrapEmacsFunc "getUserFinaliserTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 192)) |]
{-# LINE 453 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| forall a. Env -> RawValue -> IO (UserPtrFinaliser a) |])

{-# INLINE getUserFinaliser #-}
getUserFinaliser
  :: MonadIO m
  => Env
  -> RawValue
  -> m (UserPtrFinaliser a)
getUserFinaliser = getUserFinaliserTH


$(wrapEmacsFunc "setUserFinaliserTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 200)) |]
{-# LINE 466 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| forall a. Env -> RawValue -> UserPtrFinaliser a -> IO () |])

{-# INLINE setUserFinaliser #-}
setUserFinaliser
  :: MonadIO m
  => Env
  -> RawValue
  -> UserPtrFinaliser a
  -> m ()
setUserFinaliser = setUserFinaliserTH


$(wrapEmacsFunc "vecGetTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 208)) |]
{-# LINE 480 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> CPtrdiff -> IO RawValue |])

{-# INLINE vecGet #-}
vecGet
  :: MonadIO m
  => Env
  -> RawValue
  -> CPtrdiff
  -> m RawValue
vecGet = vecGetTH


$(wrapEmacsFunc "vecSetTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 216)) |]
{-# LINE 494 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> CPtrdiff -> RawValue -> IO () |])

{-# INLINE vecSet #-}
vecSet
  :: MonadIO m
  => Env
  -> RawValue
  -> CPtrdiff
  -> RawValue
  -> m ()
vecSet = vecSetTH


$(wrapEmacsFunc "vecSizeTH" Unsafe
   [e| ((\hsc_ptr -> peekByteOff hsc_ptr 224)) |]
{-# LINE 509 "src/Data/Emacs/Module/Raw/Env.hsc" #-}
   [t| Env -> RawValue -> IO CPtrdiff |])

{-# INLINE vecSize #-}
vecSize
  :: MonadIO m
  => Env
  -> RawValue
  -> m CPtrdiff
vecSize = vecSizeTH