emacs-module-0.2: src/Data/Emacs/Module/Raw/Env.hsc
----------------------------------------------------------------------------
-- |
-- Module : Data.Emacs.Module.Raw.Env
-- Copyright : (c) Sergey Vinokurov 2018
-- License : Apache-2.0 (see LICENSE)
-- Maintainer : serg.foo@gmail.com
--
-- Low-level and, hopefully, low-overhead wrappers around @struct emacs_env@.
----------------------------------------------------------------------------
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UnliftedFFITypes #-}
{-# OPTIONS_HADDOCK not-home #-}
module Data.Emacs.Module.Raw.Env
( EnumFuncallExit(..)
, EnumProcessInputResult(..)
, Env
, CBoolean
, isTruthy
, isNonTruthy
, 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
, setFunctionFinalizer
, processInput
) where
import Control.Monad.IO.Class
import Data.Coerce
import Foreign
import Foreign.C
import Prettyprinter
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.Raw.Value.Internal
import Data.Emacs.Module.NonNullPtr.Internal
#include <emacs-module.h>
newtype EnumFuncallExit = EnumFuncallExit { unEnumFuncallExit :: CInt }
instance Pretty EnumFuncallExit where
pretty (EnumFuncallExit (CInt x)) = pretty x
newtype EnumProcessInputResult = EnumProcessInputResult { unEnumProcessInputResult :: CInt }
instance Pretty EnumProcessInputResult where
pretty (EnumProcessInputResult (CInt x)) = pretty x
-- | A wrapper around C value that denotes true or false.
newtype CBoolean = CBoolean (#type bool)
{-# INLINE isTruthy #-}
-- | Check whether a 'CBoolean' denotes true.
isTruthy :: CBoolean -> Bool
isTruthy (CBoolean a) = a /= 0
{-# INLINE isNonTruthy #-}
-- | Check whether a 'CBoolean' denotes false.
isNonTruthy :: CBoolean -> Bool
isNonTruthy (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 <- (#peek emacs_env, size) (Env.toPtr env)
pure $ expectedSize <= realSize
where
expectedSize :: CPtrdiff
expectedSize = (#size struct emacs_env_28)
$(wrapEmacsFunc "makeGlobalRefTH" Unsafe
[e| (#peek emacs_env, make_global_ref) |]
[t| forall p. Env -> RawValue p -> IO (RawValue 'Pinned) |])
{-# INLINE makeGlobalRef #-}
makeGlobalRef
:: forall m p. MonadIO m
=> Env
-> RawValue p
-> m (RawValue 'Pinned)
makeGlobalRef env x =
liftIO $ makeGlobalRefTH env x
$(wrapEmacsFunc "freeGlobalRefTH" Unsafe
[e| (#peek emacs_env, free_global_ref) |]
[t| Env -> RawValue 'Pinned -> IO () |])
{-# INLINE freeGlobalRef #-}
freeGlobalRef
:: forall m. MonadIO m
=> Env
-> RawValue 'Pinned
-> m ()
freeGlobalRef env x =
liftIO $ freeGlobalRefTH env x
$(wrapEmacsFunc "nonLocalExitCheckTH" Unsafe
[e| (#peek emacs_env, non_local_exit_check) |]
[t| Env -> IO EnumFuncallExit |])
{-# INLINE nonLocalExitCheck #-}
nonLocalExitCheck
:: MonadIO m
=> Env
-> m EnumFuncallExit
nonLocalExitCheck = nonLocalExitCheckTH
$(wrapEmacsFunc "nonLocalExitGetTH" Unsafe
[e| (#peek emacs_env, non_local_exit_get) |]
[t| Env -> NonNullPtr (RawValue 'Regular) -> NonNullPtr (RawValue 'Regular) -> IO EnumFuncallExit |])
{-# INLINE nonLocalExitGet #-}
nonLocalExitGet
:: MonadIO m
=> Env
-> NonNullPtr (RawValue 'Regular) -- ^ Symbol output
-> NonNullPtr (RawValue 'Regular) -- ^ Data output
-> m EnumFuncallExit
nonLocalExitGet = nonLocalExitGetTH
$(wrapEmacsFunc "nonLocalExitSignalTH" Unsafe
[e| (#peek emacs_env, non_local_exit_signal) |]
[t| forall p1 p2. Env -> RawValue p1 -> RawValue p2 -> IO () |])
{-# INLINE nonLocalExitSignal #-}
nonLocalExitSignal
:: MonadIO m
=> Env
-> RawValue p1 -- ^ Error symbol
-> RawValue p2 -- ^ Error data
-> m ()
nonLocalExitSignal = nonLocalExitSignalTH
$(wrapEmacsFunc "nonLocalExitThrowTH" Unsafe
[e| (#peek emacs_env, non_local_exit_throw) |]
[t| forall p1 p2. Env -> RawValue p1 -> RawValue p2 -> IO () |])
{-# INLINE nonLocalExitThrow #-}
nonLocalExitThrow
:: MonadIO m
=> Env
-> RawValue p1 -- ^ Tag, a symbol
-> RawValue p2 -- ^ Value
-> m ()
nonLocalExitThrow = nonLocalExitThrowTH
$(wrapEmacsFunc "nonLocalExitClearTH" Unsafe
[e| (#peek emacs_env, non_local_exit_clear) |]
[t| Env -> IO () |])
{-# INLINE nonLocalExitClear #-}
nonLocalExitClear
:: MonadIO m
=> Env
-> m ()
nonLocalExitClear = nonLocalExitClearTH
variadicFunctionArgs :: CPtrdiff
variadicFunctionArgs = (#const emacs_variadic_function)
$(wrapEmacsFunc "makeFunctionTH" Unsafe
[e| (#peek emacs_env, make_function) |]
[t| forall a o. Env -> CPtrdiff -> CPtrdiff -> FunPtr (RawFunctionType o a) -> CString -> Ptr a -> IO (RawValue 'Regular) |])
{-# INLINE makeFunction #-}
makeFunction
:: forall m o a. MonadIO m
=> Env
-> CPtrdiff -- ^ Minimum arity
-> CPtrdiff -- ^ Maximum arity
-> RawFunction o a -- ^ Implementation
-> CString -- ^ Documentation
-> Ptr a -- ^ Extra data
-> m (RawValue 'Regular)
makeFunction =
coerce
(makeFunctionTH ::
Env
-> CPtrdiff
-> CPtrdiff
-> FunPtr (RawFunctionType o a)
-> CString
-> Ptr a
-> m (RawValue 'Regular))
$(wrapEmacsFunc "funcallTH" Safe
[e| (#peek emacs_env, funcall) |]
[t| forall p1 p2. Env -> RawValue p1 -> CPtrdiff -> NonNullPtr (RawValue p2) -> IO (RawValue 'Regular) |])
{-# INLINE funcall #-}
funcall
:: MonadIO m
=> Env
-> RawValue p1 -- ^ Function
-> CPtrdiff -- ^ Number of arguments
-> NonNullPtr (RawValue p2) -- ^ Actual arguments
-> m (RawValue 'Regular)
funcall = funcallTH
$(wrapEmacsFunc "funcallPrimitiveTH" Unsafe
[e| (#peek emacs_env, funcall) |]
[t| forall p1 p2. Env -> RawValue p1 -> CPtrdiff -> NonNullPtr (RawValue p2) -> IO (RawValue 'Regular) |])
{-# INLINE funcallPrimitive #-}
funcallPrimitive
:: MonadIO m
=> Env
-> RawValue p1 -- ^ Function
-> CPtrdiff -- ^ Number of arguments
-> NonNullPtr (RawValue p2) -- ^ Actual arguments
-> m (RawValue 'Regular)
funcallPrimitive = funcallPrimitiveTH
$(wrapEmacsFunc "internTH" Unsafe
[e| (#peek emacs_env, intern) |]
[t| Env -> CString -> IO (RawValue 'Regular) |])
{-# INLINE intern #-}
intern
:: MonadIO m
=> Env
-> CString
-> m (RawValue 'Regular)
intern = internTH
$(wrapEmacsFunc "typeOfTH" Unsafe
[e| (#peek emacs_env, type_of) |]
[t| forall p. Env -> RawValue p -> IO (RawValue 'Regular) |])
{-# INLINE typeOf #-}
typeOf
:: MonadIO m
=> Env
-> RawValue p
-> m (RawValue 'Regular)
typeOf = typeOfTH
$(wrapEmacsFunc "isNotNilTH" Unsafe
[e| (#peek emacs_env, is_not_nil) |]
[t| forall p. Env -> RawValue p -> IO CBoolean |])
{-# INLINE isNotNil #-}
isNotNil
:: MonadIO m
=> Env
-> RawValue p
-> m CBoolean
isNotNil = isNotNilTH
$(wrapEmacsFunc "eqTH" Unsafe
[e| (#peek emacs_env, eq) |]
[t| forall p1 p2. Env -> RawValue p1 -> RawValue p2 -> IO CBoolean |])
{-# INLINE eq #-}
eq
:: MonadIO m
=> Env
-> RawValue p1
-> RawValue p2
-> m CBoolean
eq = eqTH
$(wrapEmacsFunc "extractIntegerTH" Unsafe
[e| (#peek emacs_env, extract_integer) |]
[t| forall p. Env -> RawValue p -> IO CIntMax |])
{-# INLINE extractInteger #-}
extractInteger
:: MonadIO m
=> Env
-> RawValue p
-> m CIntMax
extractInteger = extractIntegerTH
$(wrapEmacsFunc "makeIntegerTH" Unsafe
[e| (#peek emacs_env, make_integer) |]
[t| Env -> CIntMax -> IO (RawValue 'Regular) |])
{-# INLINE makeInteger #-}
makeInteger
:: MonadIO m
=> Env
-> CIntMax
-> m (RawValue 'Regular)
makeInteger = makeIntegerTH
$(wrapEmacsFunc "extractFloatTH" Unsafe
[e| (#peek emacs_env, extract_float) |]
[t| forall p. Env -> RawValue p -> IO CDouble |])
{-# INLINE extractFloat #-}
extractFloat
:: MonadIO m
=> Env
-> RawValue p
-> m CDouble
extractFloat = extractFloatTH
$(wrapEmacsFunc "makeFloatTH" Unsafe
[e| (#peek emacs_env, make_float) |]
[t| Env -> CDouble -> IO (RawValue 'Regular) |])
{-# INLINE makeFloat #-}
makeFloat
:: MonadIO m
=> Env
-> CDouble
-> m (RawValue 'Regular)
makeFloat = makeFloatTH
$(wrapEmacsFunc "copyStringContentsTH" Unsafe
[e| (#peek emacs_env, copy_string_contents) |]
[t| forall p. Env -> RawValue p -> 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 p -- ^ Emacs value that holds a string
-> CString -- ^ Destination, may be NULL
-> NonNullPtr CPtrdiff -- ^ SIZE pointer
-> m CBoolean
copyStringContents = copyStringContentsTH
$(wrapEmacsFunc "makeStringTH" Unsafe
[e| (#peek emacs_env, make_string) |]
[t| Env -> CString -> CPtrdiff -> IO (RawValue 'Regular) |])
{-# INLINE makeString #-}
makeString
:: MonadIO m
=> Env
-> CString -- ^ Utf8-encoded string, may contain null bytes and is
-- not required to be terminated with one.
-> CPtrdiff -- ^ Length.
-> m (RawValue 'Regular)
makeString = makeStringTH
$(wrapEmacsFunc "makeUserPtrTH" Unsafe
[e| (#peek emacs_env, make_user_ptr) |]
[t| forall a. Env -> FinalizerPtr a -> Ptr a -> IO (RawValue 'Regular) |])
{-# INLINE makeUserPtr #-}
makeUserPtr
:: forall m a. MonadIO m
=> Env
-> FinalizerPtr a
-> Ptr a
-> m (RawValue 'Regular)
makeUserPtr = makeUserPtrTH
$(wrapEmacsFunc "getUserPtrTH" Unsafe
[e| (#peek emacs_env, get_user_ptr) |]
[t| forall p a. Env -> RawValue p -> IO (Ptr a) |])
{-# INLINE getUserPtr #-}
getUserPtr
:: MonadIO m
=> Env
-> RawValue p
-> m (Ptr a)
getUserPtr = getUserPtrTH
$(wrapEmacsFunc "setUserPtrTH" Unsafe
[e| (#peek emacs_env, set_user_ptr) |]
[t| forall p a. Env -> RawValue p -> Ptr a -> IO () |])
{-# INLINE setUserPtr #-}
setUserPtr
:: MonadIO m
=> Env
-> RawValue p
-> Ptr a
-> m ()
setUserPtr = setUserPtrTH
$(wrapEmacsFunc "getUserFinaliserTH" Unsafe
[e| (#peek emacs_env, get_user_finalizer) |]
[t| forall p a. Env -> RawValue p -> IO (FinalizerPtr a) |])
{-# INLINE getUserFinaliser #-}
getUserFinaliser
:: MonadIO m
=> Env
-> RawValue p
-> m (FinalizerPtr a)
getUserFinaliser = getUserFinaliserTH
$(wrapEmacsFunc "setUserFinaliserTH" Unsafe
[e| (#peek emacs_env, set_user_finalizer) |]
[t| forall p a. Env -> RawValue p -> FinalizerPtr a -> IO () |])
{-# INLINE setUserFinaliser #-}
setUserFinaliser
:: MonadIO m
=> Env
-> RawValue p
-> FinalizerPtr a
-> m ()
setUserFinaliser = setUserFinaliserTH
$(wrapEmacsFunc "vecGetTH" Unsafe
[e| (#peek emacs_env, vec_get) |]
[t| forall p. Env -> RawValue p -> CPtrdiff -> IO (RawValue 'Regular) |])
{-# INLINE vecGet #-}
vecGet
:: MonadIO m
=> Env
-> RawValue p
-> CPtrdiff
-> m (RawValue 'Regular)
vecGet = vecGetTH
$(wrapEmacsFunc "vecSetTH" Unsafe
[e| (#peek emacs_env, vec_set) |]
[t| forall p1 p2. Env -> RawValue p1 -> CPtrdiff -> RawValue p2 -> IO () |])
{-# INLINE vecSet #-}
vecSet
:: MonadIO m
=> Env
-> RawValue p1
-> CPtrdiff
-> RawValue p2
-> m ()
vecSet = vecSetTH
$(wrapEmacsFunc "vecSizeTH" Unsafe
[e| (#peek emacs_env, vec_size) |]
[t| forall p. Env -> RawValue p -> IO CPtrdiff |])
{-# INLINE vecSize #-}
vecSize
:: MonadIO m
=> Env
-> RawValue p
-> m CPtrdiff
vecSize = vecSizeTH
-- These are mostly of administrative interest.
$(wrapEmacsFunc "setFunctionFinalizerTH" Unsafe
[e| (#peek emacs_env, set_function_finalizer) |]
[t| forall p a. Env -> RawValue p -> FinalizerPtr a -> IO () |])
{-# INLINE setFunctionFinalizer #-}
setFunctionFinalizer
:: MonadIO m
=> Env
-> RawValue p
-> FinalizerPtr a
-> m ()
setFunctionFinalizer = setFunctionFinalizerTH
$(wrapEmacsFunc "processInputTH" Unsafe
[e| (#peek emacs_env, process_input) |]
[t| Env -> IO EnumProcessInputResult |])
{-# INLINE processInput #-}
-- | Processes pending input events and returns whether the module
-- function should quit.
processInput
:: MonadIO m
=> Env
-> m EnumProcessInputResult
processInput = processInputTH