#if __GLASGOW_HASKELL__ >= 704
#endif
module Control.Monad.Trans.Resource
    ( 
      ResourceT
    , ResIO
    , ReleaseKey
      
    , runResourceT
      
    , resourceForkIO
      
    , transResourceT
    , joinResourceT
      
    , ExceptionT (..)
    , runExceptionT_
    , runException
    , runException_
      
    , allocate
    , register
    , release
    , unprotect
    , resourceMask
      
    , MonadResource (..)
    , MonadUnsafeIO (..)
    , MonadThrow (..)
    , MonadActive (..)
    , MonadResourceBase
      
    , InvalidAccess (..)
      
    , MonadBaseControl
      
      
    , InternalState
    , getInternalState
    , runInternalState
    , withInternalState
    , createInternalState
    , closeInternalState
      
    , Resource
    , mkResource
    , with
    , allocateResource
    ) where
import qualified Data.IntMap as IntMap
import Control.Exception (SomeException, throw)
import Control.Monad.Trans.Control
    ( MonadBaseControl (..), liftBaseDiscard, control )
import qualified Data.IORef as I
import Control.Monad.Base (MonadBase, liftBase)
import Control.Applicative (Applicative (..))
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad (liftM)
import qualified Control.Exception as E
import Data.Monoid (Monoid)
import qualified Control.Exception.Lifted as L
import Control.Monad.Trans.Identity ( IdentityT)
import Control.Monad.Trans.List     ( ListT    )
import Control.Monad.Trans.Maybe    ( MaybeT   )
import Control.Monad.Trans.Error    ( ErrorT, Error)
import Control.Monad.Trans.Reader   ( ReaderT  )
import Control.Monad.Trans.State    ( StateT   )
import Control.Monad.Trans.Writer   ( WriterT  )
import Control.Monad.Trans.Resource.Internal
import Control.Monad.Trans.RWS      ( RWST     )
import qualified Control.Monad.Trans.RWS.Strict    as Strict ( RWST   )
import qualified Control.Monad.Trans.State.Strict  as Strict ( StateT )
import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT )
import Control.Concurrent (ThreadId, forkIO)
import Control.Monad.ST (ST)
import qualified Control.Monad.ST.Lazy as Lazy
import Data.Functor.Identity (Identity, runIdentity)
import Control.Monad.Morph
register :: MonadResource m => IO () -> m ReleaseKey
register = liftResourceT . registerRIO
release :: MonadIO m => ReleaseKey -> m ()
release (ReleaseKey istate rk) = liftIO $ release' istate rk  
    (maybe (return ()) id)
unprotect :: MonadIO m => ReleaseKey -> m (Maybe (IO ()))
unprotect (ReleaseKey istate rk) = liftIO $ release' istate rk return
allocate :: MonadResource m
         => IO a 
         -> (a -> IO ()) 
         -> m (ReleaseKey, a)
allocate a = liftResourceT . allocateRIO a
allocateResource :: MonadResource m => Resource a -> m (ReleaseKey, a)
allocateResource = liftResourceT . allocateResourceRIO
resourceMask :: MonadResource m => ((forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b) -> m b
resourceMask = liftResourceT . resourceMaskRIO
allocateRIO :: IO a -> (a -> IO ()) -> ResourceT IO (ReleaseKey, a)
allocateRIO acquire rel = ResourceT $ \istate -> liftIO $ E.mask $ \restore -> do
    a <- restore acquire
    key <- register' istate $ rel a
    return (key, a)
allocateResourceRIO :: Resource a -> ResourceT IO (ReleaseKey, a)
allocateResourceRIO (Resource f) = ResourceT $ \istate -> liftIO $ E.mask $ \restore -> do
    Allocated a free <- f restore
    key <- register' istate free
    return (key, a)
registerRIO :: IO () -> ResourceT IO ReleaseKey
registerRIO rel = ResourceT $ \istate -> liftIO $ register' istate rel
resourceMaskRIO :: ((forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b) -> ResourceT IO b
resourceMaskRIO f = ResourceT $ \istate -> liftIO $ E.mask $ \restore ->
    let ResourceT f' = f (go restore)
     in f' istate
  where
    go :: (forall a. IO a -> IO a) -> (forall a. ResourceT IO a -> ResourceT IO a)
    go r (ResourceT g) = ResourceT (\i -> r (g i))
register' :: I.IORef ReleaseMap
          -> IO ()
          -> IO ReleaseKey
register' istate rel = I.atomicModifyIORef istate $ \rm ->
    case rm of
        ReleaseMap key rf m ->
            ( ReleaseMap (key  1) rf (IntMap.insert key rel m)
            , ReleaseKey istate key
            )
        ReleaseMapClosed -> throw $ InvalidAccess "register'"
release' :: I.IORef ReleaseMap
         -> Int
         -> (Maybe (IO ()) -> IO a)
         -> IO a
release' istate key act = E.mask $ \restore -> do
    maction <- I.atomicModifyIORef istate lookupAction
    restore (act maction)
  where
    lookupAction rm@(ReleaseMap next rf m) =
        case IntMap.lookup key m of
            Nothing -> (rm, Nothing)
            Just action ->
                ( ReleaseMap next rf $ IntMap.delete key m
                , Just action
                )
    
    
    
    
    
    lookupAction ReleaseMapClosed = (ReleaseMapClosed, Nothing)
runResourceT :: MonadBaseControl IO m => ResourceT m a -> m a
runResourceT (ResourceT r) = do
    istate <- createInternalState
    r istate `finally` stateCleanup istate
bracket_ :: MonadBaseControl IO m => IO () -> IO () -> m a -> m a
bracket_ alloc cleanup inside =
    control $ \run -> E.bracket_ alloc cleanup (run inside)
finally :: MonadBaseControl IO m => m a -> IO () -> m a
finally action cleanup =
    control $ \run -> E.finally (run action) cleanup
joinResourceT :: ResourceT (ResourceT m) a
              -> ResourceT m a
joinResourceT (ResourceT f) = ResourceT $ \r -> unResourceT (f r) r
runExceptionT_ :: Monad m => ExceptionT m a -> m a
runExceptionT_ = liftM (either E.throw id) . runExceptionT
runException :: ExceptionT Identity a -> Either SomeException a
runException = runIdentity . runExceptionT
runException_ :: ExceptionT Identity a -> a
runException_ = runIdentity . runExceptionT_
resourceForkIO :: MonadBaseControl IO m => ResourceT m () -> ResourceT m ThreadId
resourceForkIO (ResourceT f) = ResourceT $ \r -> L.mask $ \restore ->
    
    
    
    
    bracket_
        (stateAlloc r)
        (return ())
        (liftBaseDiscard forkIO $ bracket_
            (return ())
            (stateCleanup r)
            (restore $ f r))
class Monad m => MonadActive m where
    monadActive :: m Bool
instance (MonadIO m, MonadActive m) => MonadActive (ResourceT m) where
    monadActive = ResourceT $ \rmMap -> do
        rm <- liftIO $ I.readIORef rmMap
        case rm of
            ReleaseMapClosed -> return False
            _ -> monadActive 
instance MonadActive Identity where
    monadActive = return True
instance MonadActive IO where
    monadActive = return True
instance MonadActive (ST s) where
    monadActive = return True
instance MonadActive (Lazy.ST s) where
    monadActive = return True
#define GO(T) instance MonadActive m => MonadActive (T m) where monadActive = lift monadActive
#define GOX(X, T) instance (X, MonadActive m) => MonadActive (T m) where monadActive = lift monadActive
GO(IdentityT)
GO(ListT)
GO(MaybeT)
GOX(Error e, ErrorT e)
GO(ReaderT r)
GO(StateT s)
GOX(Monoid w, WriterT w)
GOX(Monoid w, RWST r w s)
GOX(Monoid w, Strict.RWST r w s)
GO(Strict.StateT s)
GOX(Monoid w, Strict.WriterT w)
#undef GO
#undef GOX
#if __GLASGOW_HASKELL__ >= 704
type MonadResourceBase m = (MonadBaseControl IO m, MonadThrow m, MonadUnsafeIO m, MonadIO m, Applicative m)
#else
class (MonadBaseControl IO m, MonadThrow m, MonadUnsafeIO m, MonadIO m, Applicative m) => MonadResourceBase m
instance (MonadBaseControl IO m, MonadThrow m, MonadUnsafeIO m, MonadIO m, Applicative m) => MonadResourceBase m
#endif
createInternalState :: MonadBase IO m => m InternalState
createInternalState = liftBase
                    $ I.newIORef
                    $ ReleaseMap maxBound (minBound + 1) IntMap.empty
closeInternalState :: MonadBase IO m => InternalState -> m ()
closeInternalState = liftBase . stateCleanup
getInternalState :: Monad m => ResourceT m InternalState
getInternalState = ResourceT return
type InternalState = I.IORef ReleaseMap
runInternalState :: ResourceT m a -> InternalState -> m a
runInternalState = unResourceT
withInternalState :: (InternalState -> m a) -> ResourceT m a
withInternalState = ResourceT