{-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE EmptyDataDecls #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ImpredicativeTypes #-} module Clang.Internal.Monad ( ClangT , ClangBase , ClangValue(..) , ClangValueList(..) , Proxy , runClangT , clangScope , clangAllocate , mkProxy ) where import Control.Applicative import Control.Monad.Base import Control.Monad.Trans import Control.Monad.Trans.Resource import qualified Data.Vector.Storable as DVS import Unsafe.Coerce (unsafeCoerce) -- With GHC 7.8 we can use the safer 'coerce'. newtype ClangT s m a = ClangT { unClangT :: ResourceT m a } deriving (Applicative, Functor, Monad, MonadIO, MonadThrow, MonadTrans) instance MonadBase b m => MonadBase b (ClangT s m) where liftBase = lift . liftBase instance ClangBase m => MonadResource (ClangT s m) where liftResourceT = transClangT liftIO transClangT :: (m a -> n b) -> ResourceT m a -> ClangT s n b transClangT f rt = ClangT $ transResourceT f rt type ClangBase m = MonadResourceBase m data Proxy s runClangT :: ClangBase m => (forall s. ClangT s m a) -> m a runClangT f = runResourceT . unClangT $ f {-# INLINEABLE runClangT #-} -- | Runs a monadic computation with libclang and frees all the -- resources allocated by that computation immediately. clangScope :: ClangBase m => (forall s. ClangT s m a) -> ClangT s' m a clangScope = lift . runClangT {-# INLINEABLE clangScope #-} clangAllocate :: ClangBase m => IO a -> (a -> IO ()) -> ClangT s m (ReleaseKey, a) clangAllocate = allocate {-# INLINEABLE clangAllocate #-} mkProxy :: Proxy s mkProxy = undefined {-# INLINE mkProxy #-} class ClangValue v where -- | Promotes a value from an outer scope to the current inner scope. -- The value's lifetime remains that of the outer scope. -- This is never necessary, but it may allow you to write code more naturally in -- some situations, since it can occasionally be inconvenient that variables -- from different scopes are different types. fromOuterScope :: ClangBase m => v s' -> ClangT s m (v s) fromOuterScope = return . unsafeCoerce class ClangValueList v where -- | Promotes a list from an outer scope to the current inner scope. -- The list's lifetime remains that of the outer scope. -- This is never necessary, but it may allow you to write code more naturally in -- some situations, since it can occasionally be inconvenient that variables -- from different scopes are different types. listFromOuterScope :: ClangBase m => DVS.Vector (v s') -> ClangT s m (DVS.Vector (v s)) listFromOuterScope = return . unsafeCoerce