resourcet 1.1.11 → 1.2.0
raw patch · 7 files changed
+83/−256 lines, 7 filesdep +primitivedep −lifted-basedep −mmorphdep −monad-controldep ~basedep ~exceptionsdep ~transformersPVP ok
version bump matches the API change (PVP)
Dependencies added: primitive
Dependencies removed: lifted-base, mmorph, monad-control, transformers-base, transformers-compat
Dependency ranges changed: base, exceptions, transformers
API changes (from Hackage documentation)
- Control.Monad.Trans.Resource: class MonadBase b m => MonadBaseControl (b :: * -> *) (m :: * -> *) | m -> b
- Control.Monad.Trans.Resource: monadThrow :: (Exception e, MonadThrow m) => e -> m a
- Control.Monad.Trans.Resource: runException :: ExceptionT Identity a -> Either SomeException a
- Control.Monad.Trans.Resource: runExceptionT :: ExceptionT m a -> m (Either SomeException a)
- Control.Monad.Trans.Resource: runExceptionT_ :: Monad m => ExceptionT m a -> m a
- Control.Monad.Trans.Resource: runException_ :: ExceptionT Identity a -> a
- Control.Monad.Trans.Resource: type ExceptionT = CatchT
- Control.Monad.Trans.Resource.Internal: instance (Control.Monad.Catch.MonadThrow m, Control.Monad.Base.MonadBase GHC.Types.IO m, Control.Monad.IO.Class.MonadIO m, GHC.Base.Applicative m) => Control.Monad.Trans.Resource.Internal.MonadResource (Control.Monad.Trans.Resource.Internal.ResourceT m)
- Control.Monad.Trans.Resource.Internal: instance (Control.Monad.Trans.Error.Error e, Control.Monad.Trans.Resource.Internal.MonadResource m) => Control.Monad.Trans.Resource.Internal.MonadResource (Control.Monad.Trans.Error.ErrorT e m)
- Control.Monad.Trans.Resource.Internal: instance Control.Monad.Base.MonadBase b m => Control.Monad.Base.MonadBase b (Control.Monad.Trans.Resource.Internal.ResourceT m)
- Control.Monad.Trans.Resource.Internal: instance Control.Monad.Morph.MFunctor Control.Monad.Trans.Resource.Internal.ResourceT
- Control.Monad.Trans.Resource.Internal: instance Control.Monad.Morph.MMonad Control.Monad.Trans.Resource.Internal.ResourceT
- Control.Monad.Trans.Resource.Internal: instance Control.Monad.Trans.Control.MonadBaseControl b m => Control.Monad.Trans.Control.MonadBaseControl b (Control.Monad.Trans.Resource.Internal.ResourceT m)
- Control.Monad.Trans.Resource.Internal: instance Control.Monad.Trans.Control.MonadTransControl Control.Monad.Trans.Resource.Internal.ResourceT
- Data.Acquire: withEx :: (MonadMask m, MonadIO m) => Acquire a -> (a -> m b) -> m b
- Data.Acquire.Internal: instance Control.Monad.Base.MonadBase GHC.Types.IO Data.Acquire.Internal.Acquire
- Data.Acquire.Internal: withEx :: (MonadMask m, MonadIO m) => Acquire a -> (a -> m b) -> m b
+ Control.Monad.Trans.Resource: class MonadIO m => MonadUnliftIO (m :: * -> *)
+ Control.Monad.Trans.Resource.Internal: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.Trans.Resource.Internal.MonadResource (Control.Monad.Trans.Resource.Internal.ResourceT m)
+ Control.Monad.Trans.Resource.Internal: instance Control.Monad.Primitive.PrimMonad m => Control.Monad.Primitive.PrimMonad (Control.Monad.Trans.Resource.Internal.ResourceT m)
+ Data.Acquire: withAcquire :: MonadUnliftIO m => Acquire a -> (a -> m b) -> m b
- Control.Monad.Trans.Resource: class (MonadThrow m, MonadIO m, Applicative m, MonadBase IO m) => MonadResource m
+ Control.Monad.Trans.Resource: class MonadIO m => MonadResource m
- Control.Monad.Trans.Resource: closeInternalState :: MonadBase IO m => InternalState -> m ()
+ Control.Monad.Trans.Resource: closeInternalState :: MonadIO m => InternalState -> m ()
- Control.Monad.Trans.Resource: createInternalState :: MonadBase IO m => m InternalState
+ Control.Monad.Trans.Resource: createInternalState :: MonadIO m => m InternalState
- Control.Monad.Trans.Resource: resourceForkIO :: MonadBaseControl IO m => ResourceT m () -> ResourceT m ThreadId
+ Control.Monad.Trans.Resource: resourceForkIO :: MonadUnliftIO m => ResourceT m () -> ResourceT m ThreadId
- Control.Monad.Trans.Resource: resourceForkWith :: MonadBaseControl IO m => (IO () -> IO a) -> ResourceT m () -> ResourceT m a
+ Control.Monad.Trans.Resource: resourceForkWith :: MonadUnliftIO m => (IO () -> IO a) -> ResourceT m () -> ResourceT m a
- Control.Monad.Trans.Resource: runResourceT :: MonadBaseControl IO m => ResourceT m a -> m a
+ Control.Monad.Trans.Resource: runResourceT :: MonadUnliftIO m => ResourceT m a -> m a
- Control.Monad.Trans.Resource: type MonadResourceBase m = (MonadBaseControl IO m, MonadThrow m, MonadBase IO m, MonadIO m, Applicative m)
+ Control.Monad.Trans.Resource: type MonadResourceBase = MonadUnliftIO
- Control.Monad.Trans.Resource.Internal: class (MonadThrow m, MonadIO m, Applicative m, MonadBase IO m) => MonadResource m
+ Control.Monad.Trans.Resource.Internal: class MonadIO m => MonadResource m
- Data.Acquire: with :: MonadBaseControl IO m => Acquire a -> (a -> m b) -> m b
+ Data.Acquire: with :: MonadUnliftIO m => Acquire a -> (a -> m b) -> m b
- Data.Acquire.Internal: with :: MonadBaseControl IO m => Acquire a -> (a -> m b) -> m b
+ Data.Acquire.Internal: with :: MonadUnliftIO m => Acquire a -> (a -> m b) -> m b
Files
- ChangeLog.md +5/−0
- Control/Monad/Trans/Resource.hs +38/−104
- Control/Monad/Trans/Resource/Internal.hs +12/−72
- Data/Acquire.hs +10/−10
- Data/Acquire/Internal.hs +5/−40
- resourcet.cabal +5/−10
- test/main.hs +8/−20
ChangeLog.md view
@@ -1,3 +1,8 @@+## 1.2.0++* Drop `monad-control` and `mmorph` dependencies+* Change behavior of `runResourceT` to match `runResourceTChecked`+ ## 1.1.11 * `runResourceTChecked`, which checks if any of the cleanup actions
Control/Monad/Trans/Resource.hs view
@@ -6,10 +6,7 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveDataTypeable #-}-#if __GLASGOW_HASKELL__ >= 704 {-# LANGUAGE ConstraintKinds #-}-#endif-{-# LANGUAGE Safe #-} -- | Allocate resources which are guaranteed to be released. -- -- For more information, see <https://www.fpcomplete.com/user/snoyberg/library-documentation/resourcet>.@@ -45,7 +42,7 @@ -- ** Low-level , InvalidAccess (..) -- * Re-exports- , MonadBaseControl+ , MonadUnliftIO -- * Internal state -- $internalState , InternalState@@ -54,36 +51,20 @@ , withInternalState , createInternalState , closeInternalState- -- * Backwards compatibility- , ExceptionT (..)- , runExceptionT- , runExceptionT_- , runException- , runException_+ -- * Reexport , MonadThrow (..)- , monadThrow ) 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.Unlift (MonadIO (..), MonadUnliftIO, withRunInIO)-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.Resource.Internal import Control.Concurrent (ThreadId, forkIO) -import Data.Functor.Identity (Identity, runIdentity) import Control.Monad.Catch (MonadThrow, throwM)-import Control.Monad.Catch.Pure (CatchT, runCatchT) import Data.Acquire.Internal (ReleaseType (..)) @@ -183,28 +164,13 @@ -- If multiple threads are sharing the same collection of resources, only the -- last call to @runResourceT@ will deallocate the resources. ----- /NOTE/ Since version 1.1.11, this module has also provided--- `runResourceTChecked`, which is a safer version of this--- function. In the next major release of this library, it will become--- the behavior of this function.------ Since 0.3.0-runResourceT :: MonadBaseControl IO m => ResourceT m a -> m a-runResourceT (ResourceT r) = control $ \run -> do- istate <- createInternalState- E.mask $ \restore -> do- res <- restore (run (r istate)) `E.onException`- stateCleanup ReleaseException istate- stateCleanup ReleaseNormal istate- return res---- | Like 'runResourceT', but checks whether the cleanup functions--- throw any exceptions. If they do, they are rethrown inside a--- 'ResourceCleanupException'.+-- /NOTE/ Since version 1.2.0, this function will throw a+-- 'ResourceCleanupException' if any of the cleanup functions throw an+-- exception. ----- @since 1.1.11-runResourceTChecked :: MonadUnliftIO m => ResourceT m a -> m a-runResourceTChecked (ResourceT r) = withRunInIO $ \run -> do+-- @since 0.3.0+runResourceT :: MonadUnliftIO m => ResourceT m a -> m a+runResourceT (ResourceT r) = withRunInIO $ \run -> do istate <- createInternalState E.mask $ \restore -> do res <- restore (run (r istate)) `E.catch` \e -> do@@ -213,23 +179,26 @@ stateCleanupChecked Nothing istate return res -bracket_ :: MonadBaseControl IO m+-- | Backwards compatible alias for 'runResourceT'.+--+-- @since 1.1.11+runResourceTChecked :: MonadUnliftIO m => ResourceT m a -> m a+runResourceTChecked = runResourceT+{-# INLINE runResourceTChecked #-}++bracket_ :: MonadUnliftIO m => IO () -- ^ allocate -> IO () -- ^ normal cleanup -> IO () -- ^ exceptional cleanup -> m a -> m a bracket_ alloc cleanupNormal cleanupExc inside =- control $ \run -> E.mask $ \restore -> do+ withRunInIO $ \run -> E.mask $ \restore -> do alloc res <- restore (run inside) `E.onException` cleanupExc cleanupNormal return res -finally :: MonadBaseControl IO m => m a -> IO () -> m a-finally action cleanup =- control $ \run -> E.finally (run action) cleanup- -- | This function mirrors @join@ at the transformer level: it will collapse -- two levels of @ResourceT@ into a single @ResourceT@. --@@ -238,31 +207,6 @@ -> ResourceT m a joinResourceT (ResourceT f) = ResourceT $ \r -> unResourceT (f r) r --- | For backwards compatibility.-type ExceptionT = CatchT---- | For backwards compatibility.-runExceptionT :: ExceptionT m a -> m (Either SomeException a)-runExceptionT = runCatchT---- | Same as 'runExceptionT', but immediately 'E.throw' any exception returned.------ Since 0.3.0-runExceptionT_ :: Monad m => ExceptionT m a -> m a-runExceptionT_ = liftM (either E.throw id) . runExceptionT---- | Run an @ExceptionT Identity@ stack.------ Since 0.4.2-runException :: ExceptionT Identity a -> Either SomeException a-runException = runIdentity . runExceptionT---- | Run an @ExceptionT Identity@ stack, but immediately 'E.throw' any exception returned.------ Since 0.4.2-runException_ :: ExceptionT Identity a -> a-runException_ = runIdentity . runExceptionT_- -- | Introduce a reference-counting scheme to allow a resource context to be -- shared by multiple threads. Once the last thread exits, all remaining -- resources will be released.@@ -279,8 +223,13 @@ -- a new @ResourceT@ block and then call @resourceForkWith@ from there. -- -- @since 1.1.9-resourceForkWith :: MonadBaseControl IO m => (IO () -> IO a) -> ResourceT m () -> ResourceT m a-resourceForkWith g (ResourceT f) = ResourceT $ \r -> L.mask $ \restore ->+resourceForkWith+ :: MonadUnliftIO m+ => (IO () -> IO a)+ -> ResourceT m ()+ -> ResourceT m a+resourceForkWith g (ResourceT f) =+ ResourceT $ \r -> withRunInIO $ \run -> E.mask $ \restore -> -- We need to make sure the counter is incremented before this call -- returns. Otherwise, the parent thread may call runResourceT before -- the child thread increments, and all resources will be freed@@ -289,46 +238,35 @@ (stateAlloc r) (return ()) (return ())- (liftBaseDiscard g $ bracket_+ (g $ bracket_ (return ()) (stateCleanup ReleaseNormal r) (stateCleanup ReleaseException r)- (restore $ f r))+ (restore $ run $ f r)) -- | Launch a new reference counted resource context using @forkIO@. -- -- This is defined as @resourceForkWith forkIO@. -- -- @since 0.3.0-resourceForkIO :: MonadBaseControl IO m => ResourceT m () -> ResourceT m ThreadId+resourceForkIO :: MonadUnliftIO m => ResourceT m () -> ResourceT m ThreadId resourceForkIO = resourceForkWith forkIO --- | A @Monad@ which can be used as a base for a @ResourceT@.------ A @ResourceT@ has some restrictions on its base monad:+-- | Just use 'MonadUnliftIO' directly now, legacy explanation continues: ----- * @runResourceT@ requires an instance of @MonadBaseControl IO@.--- * @MonadResource@ requires an instance of @MonadThrow@, @MonadIO@, and @Applicative@.+-- A @Monad@ which can be used as a base for a @ResourceT@. ----- While any instance of @MonadBaseControl IO@ should be an instance of the--- other classes, this is not guaranteed by the type system (e.g., you may have--- a transformer in your stack with does not implement @MonadThrow@). Ideally,--- we would like to simply create an alias for the five type classes listed,--- but this is not possible with GHC currently.+-- A @ResourceT@ has some restrictions on its base monad: ----- Instead, this typeclass acts as a proxy for the other five. Its only purpose--- is to make your type signatures shorter.+-- * @runResourceT@ requires an instance of @MonadUnliftIO@.+-- * @MonadResource@ requires an instance of @MonadIO@ -- -- Note that earlier versions of @conduit@ had a typeclass @ResourceIO@. This -- fulfills much the same role. -- -- Since 0.3.2-#if __GLASGOW_HASKELL__ >= 704-type MonadResourceBase m = (MonadBaseControl IO m, MonadThrow m, MonadBase IO m, MonadIO m, Applicative m)-#else-class (MonadBaseControl IO m, MonadThrow m, MonadIO m, Applicative m) => MonadResourceBase m-instance (MonadBaseControl IO m, MonadThrow m, MonadIO m, Applicative m) => MonadResourceBase m-#endif+type MonadResourceBase = MonadUnliftIO+{-# DEPRECATED MonadResourceBase "Use MonadUnliftIO directly instead" #-} -- $internalState --@@ -344,16 +282,16 @@ -- Caveat emptor! -- -- Since 0.4.9-createInternalState :: MonadBase IO m => m InternalState-createInternalState = liftBase+createInternalState :: MonadIO m => m InternalState+createInternalState = liftIO $ I.newIORef $ ReleaseMap maxBound (minBound + 1) IntMap.empty -- | Close an internal state created by @createInternalState@. -- -- Since 0.4.9-closeInternalState :: MonadBase IO m => InternalState -> m ()-closeInternalState = liftBase . stateCleanup ReleaseNormal+closeInternalState :: MonadIO m => InternalState -> m ()+closeInternalState = liftIO . stateCleanup ReleaseNormal -- | Get the internal state of the current @ResourceT@. --@@ -377,7 +315,3 @@ -- Since 0.4.6 withInternalState :: (InternalState -> m a) -> ResourceT m a withInternalState = ResourceT---- | Backwards compatibility-monadThrow :: (E.Exception e, MonadThrow m) => e -> m a-monadThrow = throwM
Control/Monad/Trans/Resource/Internal.hs view
@@ -7,13 +7,6 @@ {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE RankNTypes #-}--- Can only mark as Safe when using a newer GHC, otherwise we get build--- failures due to the manual Typeable instance below.-#if __GLASGOW_HASKELL__ >= 707-{-# LANGUAGE Safe #-}-#else-{-# LANGUAGE Trustworthy #-}-#endif module Control.Monad.Trans.Resource.Internal( InvalidAccess(..)@@ -36,9 +29,7 @@ import Control.Monad (MonadPlus(..)) import Control.Monad.Fix (MonadFix(..)) import Control.Monad.IO.Unlift-import Control.Monad.Trans.Control- ( MonadTransControl (..), MonadBaseControl (..) )-import Control.Monad.Base (MonadBase, liftBase)+import Control.Monad.Trans.Class (MonadTrans (..)) import Control.Monad.Trans.Cont ( ContT ) import Control.Monad.Cont.Class ( MonadCont (..) ) import Control.Monad.Error.Class ( MonadError (..) )@@ -50,7 +41,6 @@ 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.Except ( ExceptT ) import Control.Monad.Trans.Reader ( ReaderT ) import Control.Monad.Trans.State ( StateT )@@ -62,38 +52,30 @@ import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT ) import Control.Monad.IO.Class (MonadIO (..))-#if !(MIN_VERSION_monad_control(1,0,0))-import Control.Monad (liftM)-#endif+import Control.Monad.Primitive (PrimMonad (..)) import qualified Control.Exception as E-import Control.Monad.Catch (MonadThrow (..), MonadCatch (..)-#if MIN_VERSION_exceptions(0,6,0)- , MonadMask (..)-#endif- )++-- FIXME Do we want to only support MonadThrow?+import Control.Monad.Catch (MonadThrow (..), MonadCatch (..), MonadMask (..)) import Data.IntMap (IntMap) import qualified Data.IntMap as IntMap import qualified Data.IORef as I-import Data.Monoid import Data.Typeable import Data.Word(Word)-import Prelude hiding (catch) import Data.Acquire.Internal (ReleaseType (..)) -import Control.Monad.Morph- -- | A @Monad@ which allows for safe resource allocation. In theory, any monad -- transformer stack which includes a @ResourceT@ can be an instance of -- @MonadResource@. ----- Note: @runResourceT@ has a requirement for a @MonadBaseControl IO m@ monad,+-- Note: @runResourceT@ has a requirement for a @MonadUnliftIO m@ monad, -- which allows control operations to be lifted. A @MonadResource@ does not -- have this requirement. This means that transformers such as @ContT@ can be -- an instance of @MonadResource@. However, the @ContT@ wrapper will need to be -- unwrapped before calling @runResourceT@. -- -- Since 0.3.0-class (MonadThrow m, MonadIO m, Applicative m, MonadBase IO m) => MonadResource m where+class MonadIO m => MonadResource m where -- | Lift a @ResourceT IO@ action into the current @Monad@. -- -- Since 0.4.0@@ -148,16 +130,17 @@ instance MonadCatch m => MonadCatch (ResourceT m) where catch (ResourceT m) c = ResourceT $ \r -> m r `catch` \e -> unResourceT (c e) r-#if MIN_VERSION_exceptions(0,6,0) instance MonadMask m => MonadMask (ResourceT m) where-#endif mask a = ResourceT $ \e -> mask $ \u -> unResourceT (a $ q u) e where q u (ResourceT b) = ResourceT (u . b) uninterruptibleMask a = ResourceT $ \e -> uninterruptibleMask $ \u -> unResourceT (a $ q u) e where q u (ResourceT b) = ResourceT (u . b)-instance (MonadThrow m, MonadBase IO m, MonadIO m, Applicative m) => MonadResource (ResourceT m) where+instance MonadIO m => MonadResource (ResourceT m) where liftResourceT = transResourceT liftIO+instance PrimMonad m => PrimMonad (ResourceT m) where+ type PrimState (ResourceT m) = PrimState m+ primitive = lift . primitive -- | Transform the monad a @ResourceT@ lives in. This is most often used to -- strip or add new transformers to a stack, e.g. to run a @ReaderT@.@@ -170,13 +153,6 @@ -> ResourceT n b transResourceT f (ResourceT mx) = ResourceT (\r -> f (mx r)) --- | Since 0.4.7-instance MFunctor ResourceT where- hoist f (ResourceT mx) = ResourceT (\r -> f (mx r))--- | Since 0.4.7-instance MMonad ResourceT where- embed f m = ResourceT (\i -> unResourceT (f (unResourceT m i)) i)- -- | The Resource transformer. This transformer keeps track of all registered -- actions, and calls them upon exit (via 'runResourceT'). Actions may be -- registered via 'register', or resources may be allocated atomically via@@ -243,9 +219,7 @@ (ResourceT mf) `mplus` (ResourceT ma) = ResourceT $ \r -> mf r `mplus` ma r instance Monad m => Monad (ResourceT m) where-#if !MIN_VERSION_base(4,8,0)- return = ResourceT . const . return-#endif+ return = pure ResourceT ma >>= f = ResourceT $ \r -> do a <- ma r let ResourceT f' = f a@@ -261,37 +235,6 @@ instance MonadIO m => MonadIO (ResourceT m) where liftIO = lift . liftIO -instance MonadBase b m => MonadBase b (ResourceT m) where- liftBase = lift . liftBase--instance MonadTransControl ResourceT where-#if MIN_VERSION_monad_control(1,0,0)- type StT ResourceT a = a- liftWith f = ResourceT $ \r -> f $ \(ResourceT t) -> t r- restoreT = ResourceT . const-#else- newtype StT ResourceT a = StReader {unStReader :: a}- liftWith f = ResourceT $ \r -> f $ \(ResourceT t) -> liftM StReader $ t r- restoreT = ResourceT . const . liftM unStReader-#endif- {-# INLINE liftWith #-}- {-# INLINE restoreT #-}--instance MonadBaseControl b m => MonadBaseControl b (ResourceT m) where-#if MIN_VERSION_monad_control(1,0,0)- type StM (ResourceT m) a = StM m a- liftBaseWith f = ResourceT $ \reader' ->- liftBaseWith $ \runInBase ->- f $ runInBase . (\(ResourceT r) -> r reader' )- restoreM = ResourceT . const . restoreM-#else- newtype StM (ResourceT m) a = StMT (StM m a)- liftBaseWith f = ResourceT $ \reader' ->- liftBaseWith $ \runInBase ->- f $ liftM StMT . runInBase . (\(ResourceT r) -> r reader' )- restoreM (StMT base) = ResourceT $ const $ restoreM base-#endif- -- | @since 1.1.10 instance MonadUnliftIO m => MonadUnliftIO (ResourceT m) where askUnliftIO = ResourceT $ \r ->@@ -303,10 +246,7 @@ GO(IdentityT) GO(ListT) GO(MaybeT)-GOX(Error e, ErrorT e)-#if MIN_VERSION_exceptions(0, 8, 0) GO(ExceptT e)-#endif GO(ReaderT r) GO(ContT r) GO(StateT s)
Data/Acquire.hs view
@@ -1,5 +1,4 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE Safe #-} -- | This was previously known as the Resource monad. However, that term is -- confusing next to the ResourceT transformer, so it has been renamed. @@ -61,7 +60,7 @@ -- > code.hs: divide by zero -- , with- , withEx+ , withAcquire , mkAcquire , mkAcquireType , allocateAcquire@@ -69,15 +68,9 @@ ) where import Control.Monad.Trans.Resource.Internal-import Control.Monad.Trans.Resource import Data.Acquire.Internal-import Control.Applicative (Applicative (..))-import Control.Monad.Base (MonadBase (..))-import Control.Monad.IO.Class (MonadIO (..))-import Control.Monad.Trans.Control (MonadBaseControl, control)-import qualified Control.Exception.Lifted as E-import Data.Typeable (Typeable)-import Control.Monad (liftM, ap)+import Control.Monad.IO.Unlift (MonadIO (..), MonadUnliftIO)+import qualified Control.Exception as E -- | Allocate a resource and register an action with the @MonadResource@ to -- free the resource.@@ -91,3 +84,10 @@ Allocated a free <- f restore key <- registerType istate free return (key, a)++-- | Longer name for 'with', in case @with@ is not obvious enough in context.+--+-- @since 1.2.0+withAcquire :: MonadUnliftIO m => Acquire a -> (a -> m b) -> m b+withAcquire = with+{-# INLINE withAcquire #-}
Data/Acquire/Internal.hs view
@@ -4,26 +4,21 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE Trustworthy #-} module Data.Acquire.Internal ( Acquire (..) , Allocated (..) , with- , withEx , mkAcquire , ReleaseType (..) , mkAcquireType ) where import Control.Applicative (Applicative (..))-import Control.Monad.Base (MonadBase (..))-import Control.Monad.IO.Class (MonadIO (..))-import Control.Monad.Trans.Control (MonadBaseControl, control)-import qualified Control.Exception.Lifted as E+import Control.Monad.IO.Unlift (MonadIO (..), MonadUnliftIO, withRunInIO)+import qualified Control.Exception as E import Data.Typeable (Typeable) import Control.Monad (liftM, ap)-import qualified Control.Monad.Catch as C-import GHC.IO (unsafeUnmask)+import qualified Control.Monad.Catch as C () -- | The way in which a release is called. --@@ -69,9 +64,6 @@ x <- restore f return $! Allocated x (const $ return ()) -instance MonadBase IO Acquire where- liftBase = liftIO- -- | Create an @Acquire@ value using the given allocate and free functions. -- -- @since 1.1.0@@ -101,39 +93,12 @@ -- @bracket@. -- -- @since 1.1.0-with :: MonadBaseControl IO m+with :: MonadUnliftIO m => Acquire a -> (a -> m b) -> m b-with (Acquire f) g = control $ \run -> E.mask $ \restore -> do+with (Acquire f) g = withRunInIO $ \run -> E.mask $ \restore -> do Allocated x free <- f restore res <- restore (run (g x)) `E.onException` free ReleaseException free ReleaseNormal return res---- | Same as @with@, but uses the @MonadMask@ typeclass from exceptions instead--- of @MonadBaseControl@ from exceptions.------ @since 1.1.3-#if MIN_VERSION_exceptions(0,6,0)-withEx :: (C.MonadMask m, MonadIO m)-#else-withEx :: (C.MonadCatch m, MonadIO m)-#endif- => Acquire a- -> (a -> m b)- -> m b-withEx (Acquire f) g = do- -- We need to do some funny business, since the restore we get below is- -- specialized to the m from the result, whereas we need a restore function- -- in IO. Checking the current masking state is exactly how mask is- -- implemented in base.- origMS <- liftIO E.getMaskingState-- C.mask $ \restore -> do- Allocated x free <- liftIO $ f $ case origMS of- E.Unmasked -> unsafeUnmask- _ -> id- res <- restore (g x) `C.onException` liftIO (free ReleaseException)- liftIO $ free ReleaseNormal- return res
resourcet.cabal view
@@ -1,5 +1,5 @@ Name: resourcet-Version: 1.1.11+Version: 1.2.0 Synopsis: Deterministic allocation and freeing of scarce resources. description: Hackage documentation generation is not reliable. For up to date documentation, please see: <http://www.stackage.org/package/resourcet>. License: BSD3@@ -18,17 +18,13 @@ Data.Acquire Data.Acquire.Internal UnliftIO.Resource- Build-depends: base >= 4.5 && < 5- , lifted-base >= 0.1- , transformers-base >= 0.4.4 && < 0.5- , monad-control >= 0.3.1 && < 1.1+ Build-depends: base >= 4.9 && < 5 , containers- , transformers >= 0.2.2- , transformers-compat >= 0.3 && < 0.6+ , transformers >= 0.4 , mtl >= 2.0 && < 2.3- , mmorph- , exceptions >= 0.5+ , exceptions >= 0.8 , unliftio-core+ , primitive ghc-options: -Wall test-suite test@@ -39,7 +35,6 @@ build-depends: resourcet , base , hspec >= 1.3- , lifted-base , transformers ghc-options: -Wall
test/main.hs view
@@ -2,7 +2,6 @@ {-# LANGUAGE ScopedTypeVariables #-} import Control.Concurrent-import Control.Concurrent.Lifted (fork) import Control.Exception (Exception, MaskingState (MaskedInterruptible), getMaskingState, throwIO, try, fromException) import Control.Exception (SomeException, handle)@@ -18,7 +17,7 @@ main = hspec $ do describe "general" $ do it "survives releasing bottom" $ do- x <- newIORef 0+ x <- newIORef (0 :: Int) handle (\(_ :: SomeException) -> return ()) $ runResourceT $ do _ <- register $ writeIORef x 1 release undefined@@ -26,7 +25,7 @@ x' `shouldBe` 1 describe "early release" $ do it "works from a different context" $ do- x <- newIORef 0+ x <- newIORef (0 :: Int) runResourceT $ do key <- register $ writeIORef x 1 runResourceT $ release key@@ -35,11 +34,11 @@ describe "resourceForkIO" $ do it "waits for all threads" $ do x <- newEmptyMVar- y <- newIORef 0+ y <- newIORef (0 :: Int) z <- newEmptyMVar w <- newEmptyMVar - runResourceT $ do+ _ <- runResourceT $ do _ <- register $ do writeIORef y 1 putMVar w ()@@ -62,8 +61,8 @@ Just y2 `shouldBe` Just 1 describe "unprotecting" $ do it "unprotect keeps resource from being cleared" $ do- x <- newIORef 0- runResourceT $ do+ x <- newIORef (0 :: Int)+ _ <- runResourceT $ do key <- register $ writeIORef x 1 unprotect key y <- readIORef x@@ -73,11 +72,11 @@ ms <- getMaskingState unless (ms == MaskedInterruptible) $ error $ show (name, ms)- runResourceT $ do+ _ <- runResourceT $ do register (checkMasked "release") >>= release register (checkMasked "normal") Left Dummy <- try $ runResourceT $ do- register (checkMasked "exception")+ _ <- register (checkMasked "exception") liftIO $ throwIO Dummy return () describe "mkAcquireType" $ do@@ -113,17 +112,6 @@ ref <- newIORef Nothing let acq = mkAcquireType (return ()) $ \() -> writeIORef ref . Just Left Dummy <- try $ with acq $ const $ throwIO Dummy- readIORef ref >>= (`shouldBe` Just ReleaseException)- describe "withEx" $ do- it "normal" $ do- ref <- newIORef Nothing- let acq = mkAcquireType (return ()) $ \() -> writeIORef ref . Just- withEx acq $ const $ return ()- readIORef ref >>= (`shouldBe` Just ReleaseNormal)- it "exception" $ do- ref <- newIORef Nothing- let acq = mkAcquireType (return ()) $ \() -> writeIORef ref . Just- Left Dummy <- try $ withEx acq $ const $ throwIO Dummy readIORef ref >>= (`shouldBe` Just ReleaseException) describe "runResourceTChecked" $ do it "catches exceptions" $ do