packages feed

effectful-0.0.0.0: src/Effectful/Resource.hs

{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
-- | Resource management via 'R.MonadResource'.
module Effectful.Resource
  ( Resource
  , runResource

  -- * Registering and releasing resources
  , R.allocate
  , R.allocate_
  , R.register
  , R.release
  , R.unprotect
  ) where

import Control.Exception
import qualified Control.Monad.Trans.Resource as R
import qualified Control.Monad.Trans.Resource.Internal as RI

import Effectful.Internal.Env
import Effectful.Internal.Has
import Effectful.Internal.Monad

-- | Data tag for a resource effect.
newtype Resource = Resource R.InternalState

-- | Run the resource effect.
runResource :: Eff (Resource : es) a -> Eff es a
runResource (Eff m) = impureEff $ \es0 -> do
  size0 <- sizeEnv es0
  istate <- R.createInternalState
  mask $ \restore -> do
    es <- unsafeConsEnv (Resource istate) es0
    a <- restore (m es) `catch` \e -> do
      _ <- unsafeTrimEnv size0 es
      RI.stateCleanupChecked (Just e) istate
      throwIO e
    _ <- unsafeTrimEnv size0 es
    RI.stateCleanupChecked Nothing istate
    pure a

instance (IOE :> es, Resource :> es) => R.MonadResource (Eff es) where
  liftResourceT (RI.ResourceT m) = impureEff $ \es -> do
    getEnv es >>= \(Resource istate) -> m istate