packages feed

pipes-safe 2.2.3 → 2.2.4

raw patch · 7 files changed

+657/−643 lines, 7 filesdep ~pipesdep ~transformerssetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: pipes, transformers

API changes (from Hackage documentation)

- Pipes.Safe: instance (MonadIO m, MonadCatch m, MonadMask m) => MonadSafe (SafeT m)
- Pipes.Safe: instance (MonadMask m, MonadIO m) => MonadMask (Proxy a' a b' b m)
- Pipes.Safe: instance (MonadSafe m, Monoid w) => MonadSafe (RWST i w s m)
- Pipes.Safe: instance (MonadSafe m, Monoid w) => MonadSafe (WriterT w m)
- Pipes.Safe: instance Alternative m => Alternative (SafeT m)
- Pipes.Safe: instance Applicative m => Applicative (SafeT m)
- Pipes.Safe: instance Functor m => Functor (SafeT m)
- Pipes.Safe: instance Monad m => Monad (SafeT m)
- Pipes.Safe: instance MonadBase b m => MonadBase b (SafeT m)
- Pipes.Safe: instance MonadBaseControl b m => MonadBaseControl b (SafeT m)
- Pipes.Safe: instance MonadCatch m => MonadCatch (Proxy a' a b' b m)
- Pipes.Safe: instance MonadCatch m => MonadCatch (SafeT m)
- Pipes.Safe: instance MonadCont m => MonadCont (SafeT m)
- Pipes.Safe: instance MonadError e m => MonadError e (SafeT m)
- Pipes.Safe: instance MonadIO m => MonadIO (SafeT m)
- Pipes.Safe: instance MonadMask m => MonadMask (SafeT m)
- Pipes.Safe: instance MonadPlus m => MonadPlus (SafeT m)
- Pipes.Safe: instance MonadSafe m => MonadSafe (CatchT m)
- Pipes.Safe: instance MonadSafe m => MonadSafe (IdentityT m)
- Pipes.Safe: instance MonadSafe m => MonadSafe (Proxy a' a b' b m)
- Pipes.Safe: instance MonadSafe m => MonadSafe (ReaderT i m)
- Pipes.Safe: instance MonadSafe m => MonadSafe (StateT s m)
- Pipes.Safe: instance MonadState s m => MonadState s (SafeT m)
- Pipes.Safe: instance MonadThrow m => MonadThrow (Proxy a' a b' b m)
- Pipes.Safe: instance MonadThrow m => MonadThrow (SafeT m)
- Pipes.Safe: instance MonadTrans SafeT
- Pipes.Safe: instance MonadWriter w m => MonadWriter w (SafeT m)
+ Pipes.Safe: instance (Control.Monad.Catch.MonadMask m, Control.Monad.IO.Class.MonadIO m) => Control.Monad.Catch.MonadMask (Pipes.Internal.Proxy a' a b' b m)
+ Pipes.Safe: instance (Control.Monad.IO.Class.MonadIO m, Control.Monad.Catch.MonadCatch m, Control.Monad.Catch.MonadMask m) => Pipes.Safe.MonadSafe (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance (Pipes.Safe.MonadSafe m, GHC.Base.Monoid w) => Pipes.Safe.MonadSafe (Control.Monad.Trans.RWS.Lazy.RWST i w s m)
+ Pipes.Safe: instance (Pipes.Safe.MonadSafe m, GHC.Base.Monoid w) => Pipes.Safe.MonadSafe (Control.Monad.Trans.RWS.Strict.RWST i w s m)
+ Pipes.Safe: instance (Pipes.Safe.MonadSafe m, GHC.Base.Monoid w) => Pipes.Safe.MonadSafe (Control.Monad.Trans.Writer.Lazy.WriterT w m)
+ Pipes.Safe: instance (Pipes.Safe.MonadSafe m, GHC.Base.Monoid w) => Pipes.Safe.MonadSafe (Control.Monad.Trans.Writer.Strict.WriterT w m)
+ Pipes.Safe: instance Control.Monad.Base.MonadBase b m => Control.Monad.Base.MonadBase b (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Pipes.Internal.Proxy a' a b' b m)
+ Pipes.Safe: instance Control.Monad.Catch.MonadCatch m => Control.Monad.Catch.MonadCatch (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance Control.Monad.Catch.MonadMask m => Control.Monad.Catch.MonadMask (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Pipes.Internal.Proxy a' a b' b m)
+ Pipes.Safe: instance Control.Monad.Catch.MonadThrow m => Control.Monad.Catch.MonadThrow (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance Control.Monad.Cont.Class.MonadCont m => Control.Monad.Cont.Class.MonadCont (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance Control.Monad.Error.Class.MonadError e m => Control.Monad.Error.Class.MonadError e (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance Control.Monad.IO.Class.MonadIO m => Control.Monad.IO.Class.MonadIO (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance Control.Monad.State.Class.MonadState s m => Control.Monad.State.Class.MonadState s (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance Control.Monad.Trans.Class.MonadTrans Pipes.Safe.SafeT
+ Pipes.Safe: instance Control.Monad.Trans.Control.MonadBaseControl b m => Control.Monad.Trans.Control.MonadBaseControl b (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance Control.Monad.Writer.Class.MonadWriter w m => Control.Monad.Writer.Class.MonadWriter w (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance GHC.Base.Alternative m => GHC.Base.Alternative (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance GHC.Base.Applicative m => GHC.Base.Applicative (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance GHC.Base.Functor m => GHC.Base.Functor (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance GHC.Base.Monad m => GHC.Base.Monad (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance GHC.Base.MonadPlus m => GHC.Base.MonadPlus (Pipes.Safe.SafeT m)
+ Pipes.Safe: instance Pipes.Safe.MonadSafe m => Pipes.Safe.MonadSafe (Control.Monad.Catch.Pure.CatchT m)
+ Pipes.Safe: instance Pipes.Safe.MonadSafe m => Pipes.Safe.MonadSafe (Control.Monad.Trans.Identity.IdentityT m)
+ Pipes.Safe: instance Pipes.Safe.MonadSafe m => Pipes.Safe.MonadSafe (Control.Monad.Trans.Reader.ReaderT i m)
+ Pipes.Safe: instance Pipes.Safe.MonadSafe m => Pipes.Safe.MonadSafe (Control.Monad.Trans.State.Lazy.StateT s m)
+ Pipes.Safe: instance Pipes.Safe.MonadSafe m => Pipes.Safe.MonadSafe (Control.Monad.Trans.State.Strict.StateT s m)
+ Pipes.Safe: instance Pipes.Safe.MonadSafe m => Pipes.Safe.MonadSafe (Pipes.Internal.Proxy a' a b' b m)
- Pipes.Safe: bracket :: MonadSafe m => Base m a -> (a -> Base m b) -> (a -> m c) -> m c
+ Pipes.Safe: bracket :: (MonadSafe m) => Base m a -> (a -> Base m b) -> (a -> m c) -> m c
- Pipes.Safe: bracketOnError :: MonadSafe m => Base m a -> (a -> Base m b) -> (a -> m c) -> m c
+ Pipes.Safe: bracketOnError :: (MonadSafe m) => Base m a -> (a -> Base m b) -> (a -> m c) -> m c
- Pipes.Safe: bracket_ :: MonadSafe m => Base m a -> Base m b -> m c -> m c
+ Pipes.Safe: bracket_ :: (MonadSafe m) => Base m a -> Base m b -> m c -> m c
- Pipes.Safe: finally :: MonadSafe m => m a -> Base m b -> m a
+ Pipes.Safe: finally :: (MonadSafe m) => m a -> Base m b -> m a
- Pipes.Safe: onException :: MonadSafe m => m a -> Base m b -> m a
+ Pipes.Safe: onException :: (MonadSafe m) => m a -> Base m b -> m a
- Pipes.Safe.Prelude: readFile :: MonadSafe m => FilePath -> Producer' String m ()
+ Pipes.Safe.Prelude: readFile :: (MonadSafe m) => FilePath -> Producer' String m ()
- Pipes.Safe.Prelude: withFile :: MonadSafe m => FilePath -> IOMode -> (Handle -> m r) -> m r
+ Pipes.Safe.Prelude: withFile :: (MonadSafe m) => FilePath -> IOMode -> (Handle -> m r) -> m r
- Pipes.Safe.Prelude: writeFile :: MonadSafe m => FilePath -> Consumer' String m r
+ Pipes.Safe.Prelude: writeFile :: (MonadSafe m) => FilePath -> Consumer' String m r

Files

LICENSE view
@@ -1,24 +1,24 @@-Copyright (c) 2013, 2014 Gabriel Gonzalez
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-    * Redistributions of source code must retain the above copyright notice,
-      this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright notice,
-      this list of conditions and the following disclaimer in the documentation
-      and/or other materials provided with the distribution.
-    * Neither the name of Gabriel Gonzalez nor the names of other contributors
-      may be used to endorse or promote products derived from this software
-      without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+Copyright (c) 2013, 2014 Gabriel Gonzalez+All rights reserved.++Redistribution and use in source and binary forms, with or without modification,+are permitted provided that the following conditions are met:+    * Redistributions of source code must retain the above copyright notice,+      this list of conditions and the following disclaimer.+    * Redistributions in binary form must reproduce the above copyright notice,+      this list of conditions and the following disclaimer in the documentation+      and/or other materials provided with the distribution.+    * Neither the name of Gabriel Gonzalez nor the names of other contributors+      may be used to endorse or promote products derived from this software+      without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
README.md view
@@ -1,84 +1,84 @@-# Pipes-Safe v2.2.3
-
-`pipes-safe` builds upon
-[the `pipes` library](https://github.com/Gabriel439/Haskell-Pipes-Library) to
-provide exception safety and resource management.
-
-## Quick start
-
-* Install the [Haskell Platform](http://www.haskell.org/platform/)
-* `cabal install pipes-safe`
-
-The official tutorial is on
-[Hackage](http://hackage.haskell.org/package/pipes-safe).
-
-## Features
-
-* *Resource Safety*: Guarantee finalization using `finally`, `bracket`, and more
-
-* *Exception Safety*: Even against asynchronous exceptions!
-
-* *Laziness*: Only acquire resources when you need them
-
-* *Promptness*: Finalize resources early when you are done with them
-
-* *Native Exception Handling*: Catch and resume from exceptions inside pipes
-
-* *No Buy-in*: Mix resource-safe pipes with unmanaged pipes using `hoist`
-
-## Outline
-
-Use `pipes-safe` for production code where you need deterministic and prompt
-release of resources in the fact of exceptions or premature pipe termination.
-`pipes-safe` lets you safely acquire resources and handle exceptions within
-pipelines.
-
-## Development Status
-
-`pipes-safe` is mostly stable.  Research into prompter finalization alternatives
-will take place in a separate library.
-
-## Community Resources
-
-Use the same resources as the core `pipes` library to learn more, contribute, or
-request help:
-
-* [Haskell wiki page](http://www.haskell.org/haskellwiki/Pipes)
-
-* [Mailing list](mailto:haskell-pipes@googlegroups.com) ([Google Group](https://groups.google.com/forum/?fromgroups#!forum/haskell-pipes))
-
-## How to contribute
-
-* Build derived libraries
-
-* Write `pipes-safe` tutorials
-
-## License (BSD 3-clause)
-
-Copyright (c) 2013 Gabriel Gonzalez
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice, this
-  list of conditions and the following disclaimer in the documentation and/or
-  other materials provided with the distribution.
-
-* Neither the name of Gabriel Gonzalez nor the names of other contributors may
-  be used to endorse or promote products derived from this software without
-  specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+# Pipes-Safe v2.2.4++`pipes-safe` builds upon+[the `pipes` library](https://github.com/Gabriel439/Haskell-Pipes-Library) to+provide exception safety and resource management.++## Quick start++* Install the [Haskell Platform](http://www.haskell.org/platform/)+* `cabal install pipes-safe`++The official tutorial is on+[Hackage](http://hackage.haskell.org/package/pipes-safe).++## Features++* *Resource Safety*: Guarantee finalization using `finally`, `bracket`, and more++* *Exception Safety*: Even against asynchronous exceptions!++* *Laziness*: Only acquire resources when you need them++* *Promptness*: Finalize resources early when you are done with them++* *Native Exception Handling*: Catch and resume from exceptions inside pipes++* *No Buy-in*: Mix resource-safe pipes with unmanaged pipes using `hoist`++## Outline++Use `pipes-safe` for production code where you need deterministic and prompt+release of resources in the fact of exceptions or premature pipe termination.+`pipes-safe` lets you safely acquire resources and handle exceptions within+pipelines.++## Development Status++`pipes-safe` is mostly stable.  Research into prompter finalization alternatives+will take place in a separate library.++## Community Resources++Use the same resources as the core `pipes` library to learn more, contribute, or+request help:++* [Haskell wiki page](http://www.haskell.org/haskellwiki/Pipes)++* [Mailing list](mailto:haskell-pipes@googlegroups.com) ([Google Group](https://groups.google.com/forum/?fromgroups#!forum/haskell-pipes))++## How to contribute++* Build derived libraries++* Write `pipes-safe` tutorials++## License (BSD 3-clause)++Copyright (c) 2013 Gabriel Gonzalez+All rights reserved.++Redistribution and use in source and binary forms, with or without modification,+are permitted provided that the following conditions are met:++* Redistributions of source code must retain the above copyright notice, this+  list of conditions and the following disclaimer.++* Redistributions in binary form must reproduce the above copyright notice, this+  list of conditions and the following disclaimer in the documentation and/or+  other materials provided with the distribution.++* Neither the name of Gabriel Gonzalez nor the names of other contributors may+  be used to endorse or promote products derived from this software without+  specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple
-main = defaultMain
+import Distribution.Simple+main = defaultMain
changelog.md view
@@ -1,3 +1,16 @@-# Version 2.2.1
-
-* Raise upper-bound on `exceptions` dependency.
+# Version 2.2.4++* Increase upper bound on `pipes`++# Version 2.2.3++* Add several new instances to `SafeT`+* Add `tryP` and `catchP`++# Version 2.2.2++* Raise upper-bound on `exceptions` dependency++# Version 2.2.1++* Raise upper-bound on `exceptions` dependency.
pipes-safe.cabal view
@@ -1,50 +1,51 @@-Name: pipes-safe
-Version: 2.2.3
-Cabal-Version: >=1.8.0.2
-Build-Type: Simple
-License: BSD3
-License-File: LICENSE
-Extra-Source-Files: README.md changelog.md
-Copyright: 2013, 2014 Gabriel Gonzalez
-Author: Gabriel Gonzalez
-Maintainer: Gabriel439@gmail.com
-Bug-Reports: https://github.com/Gabriel439/Haskell-Pipes-Safe-Library/issues
-Synopsis: Safety for the pipes ecosystem
-Description:
-    This package adds resource management and exception handling to the @pipes@
-    ecosystem.
-    .
-    Notable features include:
-    .
-    * /Resource Safety/: Guarantee finalization using @finally@, @bracket@ and
-      more
-    .
-    * /Exception Safety/: Even against asynchronous exceptions!
-    .
-    * /Laziness/: Only acquire resources when you need them
-    .
-    * /Promptness/: Finalize resources early when you are done with them
-    .
-    * /Native Exception Handling/: Catch and resume from exceptions inside pipes
-    .
-    * /No Buy-in/: Mix resource-safe pipes with unmanaged pipes using @hoist@
-Category: Control, Pipes, Error Handling
-Source-Repository head
-    Type: git
-    Location: https://github.com/Gabriel439/Haskell-Pipes-Safe-Library
-
-Library
-    Build-Depends:
-        base              >= 4       && < 5  ,
-        containers        >= 0.3.0.0 && < 0.6,
-        exceptions        >= 0.6     && < 0.9,
-        mtl               >= 2.1     && < 2.3,
-        transformers      >= 0.2.0.0 && < 0.5,
-        transformers-base >= 0.4.4   && < 0.5,
-        monad-control     >= 1.0.0.4 && < 1.1,
-        pipes             >= 4.0.0   && < 4.2
-    Exposed-Modules:
-        Pipes.Safe,
-        Pipes.Safe.Prelude
-    HS-Source-Dirs: src
-    GHC-Options: -O2 -Wall
+Name: pipes-safe+Version: 2.2.4+Cabal-Version: >=1.8.0.2+Build-Type: Simple+License: BSD3+License-File: LICENSE+Extra-Source-Files: README.md changelog.md+Copyright: 2013, 2014 Gabriel Gonzalez+Author: Gabriel Gonzalez+Maintainer: Gabriel439@gmail.com+Tested-With: GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.2, GHC == 8.0.1+Bug-Reports: https://github.com/Gabriel439/Haskell-Pipes-Safe-Library/issues+Synopsis: Safety for the pipes ecosystem+Description:+    This package adds resource management and exception handling to the @pipes@+    ecosystem.+    .+    Notable features include:+    .+    * /Resource Safety/: Guarantee finalization using @finally@, @bracket@ and+      more+    .+    * /Exception Safety/: Even against asynchronous exceptions!+    .+    * /Laziness/: Only acquire resources when you need them+    .+    * /Promptness/: Finalize resources early when you are done with them+    .+    * /Native Exception Handling/: Catch and resume from exceptions inside pipes+    .+    * /No Buy-in/: Mix resource-safe pipes with unmanaged pipes using @hoist@+Category: Control, Pipes, Error Handling+Source-Repository head+    Type: git+    Location: https://github.com/Gabriel439/Haskell-Pipes-Safe-Library++Library+    Build-Depends:+        base              >= 4       && < 5  ,+        containers        >= 0.3.0.0 && < 0.6,+        exceptions        >= 0.6     && < 0.9,+        mtl               >= 2.1     && < 2.3,+        transformers      >= 0.2.0.0 && < 0.6,+        transformers-base >= 0.4.4   && < 0.5,+        monad-control     >= 1.0.0.4 && < 1.1,+        pipes             >= 4.0.0   && < 4.3+    Exposed-Modules:+        Pipes.Safe,+        Pipes.Safe.Prelude+    HS-Source-Dirs: src+    GHC-Options: -O2 -Wall
src/Pipes/Safe.hs view
@@ -1,434 +1,434 @@-{-# LANGUAGE RankNTypes, TypeFamilies, FlexibleContexts, FlexibleInstances,
-      MultiParamTypeClasses, UndecidableInstances, ScopedTypeVariables,
-      GeneralizedNewtypeDeriving, CPP #-}
-{-# OPTIONS_GHC -fno-warn-orphans #-}
-
-{-| This module provides an orphan 'MonadCatch' instance for 'Proxy' of the
-    form:
-
-> instance (MonadCatch m, MonadIO m) => MonadCatch (Proxy a' a b' b m) where
-
-    ... so you can throw and catch exceptions within pipes using all
-    'MonadCatch' operations.
-
-    This module also provides generalized versions of some 'MonadCatch'
-    operations so that you can also protect against premature termination of
-    connected components.  For example, if you protect a 'readFile' computation
-    using 'bracket' from this module:
-
-> -- readFile.hs
-> import Pipes
-> import qualified Pipes.Prelude as P
-> import Pipes.Safe
-> import qualified System.IO as IO
-> import Prelude hiding (readFile)
->
-> readFile :: FilePath -> Producer' String (SafeT IO) ()
-> readFile file = bracket
->     (do h <- IO.openFile file IO.ReadMode
->         putStrLn $ "{" ++ file ++ " open}"
->         return h )
->     (\h -> do
->         IO.hClose h
->         putStrLn $ "{" ++ file ++ " closed}" )
->     P.fromHandle
-
-    ... then this generalized 'bracket' will guard against both exceptions and
-    premature termination of other pipes:
-
->>> runSafeT $ runEffect $ readFile "readFile.hs" >-> P.take 4 >-> P.stdoutLn
-{readFile.hs open}
--- readFile.hs
-import Pipes
-import qualified Pipes.Prelude as P
-import Pipes.Safe
-{readFile.hs closed}
-
-    Note that the 'MonadCatch' instance for 'Proxy' provides weaker versions of
-    'mask' and 'uninterruptibleMask' that do not completely prevent asynchronous
-    exceptions.  Instead, they provide a weaker guarantee that asynchronous
-    exceptions will only occur during 'Pipes.await's or 'Pipes.yield's and
-    nowhere else.  For example, if you write:
-
-> mask_ $ do
->     x <- await
->     lift $ print x
->     lift $ print x
-
-    ... then you may receive an asynchronous exception during the 'Pipes.await',
-    but you will not receive an asynchronous exception during or in between the
-    two 'print' statements.  This weaker guarantee suffices to provide
-    asynchronous exception safety.
--}
-
-module Pipes.Safe
-    ( -- * SafeT
-      SafeT
-    , runSafeT
-    , runSafeP
-
-     -- * MonadSafe
-    , ReleaseKey
-    , MonadSafe(..)
-
-      -- * Utilities
-      -- $utilities
-    , onException
-    , finally
-    , bracket
-    , bracket_
-    , bracketOnError
-
-    -- * Re-exports
-    -- $reexports
-    , module Control.Monad.Catch
-    , module Control.Exception
-    ) where
-
-import Control.Applicative (Applicative, Alternative)
-import Control.Exception(Exception(..), SomeException(..))
-import qualified Control.Monad.Catch as C
-import Control.Monad.Catch
-    ( MonadCatch(..)
-    , MonadThrow(..)
-    , MonadMask(..)
-    , mask_
-    , uninterruptibleMask_
-    , catchAll
-    , catchIOError
-    , catchJust
-    , catchIf
-    , Handler(..)
-    , catches
-    , handle
-    , handleAll
-    , handleIOError
-    , handleJust
-    , handleIf
-    , try
-    , tryJust
-    , Exception(..)
-    , SomeException
-    )
-import Control.Monad (MonadPlus)
-import Control.Monad.IO.Class (MonadIO(liftIO))
-import Control.Monad.Trans.Control (MonadBaseControl(..))
-import Control.Monad.Trans.Class (MonadTrans(lift))
-import qualified Control.Monad.Base                as B
-import qualified Control.Monad.Catch.Pure          as E
-import qualified Control.Monad.Trans.Identity      as I
-import qualified Control.Monad.Cont.Class          as CC
-import qualified Control.Monad.Error.Class         as EC
-import qualified Control.Monad.Trans.Reader        as R
-import qualified Control.Monad.Trans.RWS.Lazy      as RWS
-import qualified Control.Monad.Trans.RWS.Strict    as RWS'
-import qualified Control.Monad.Trans.State.Lazy    as S
-import qualified Control.Monad.Trans.State.Strict  as S'
-import qualified Control.Monad.State.Class         as SC
-import qualified Control.Monad.Trans.Writer.Lazy   as W
-import qualified Control.Monad.Trans.Writer.Strict as W'
-import qualified Control.Monad.Writer.Class        as WC
-import Data.IORef (IORef, newIORef, readIORef, writeIORef, atomicModifyIORef')
-import qualified Data.Map as M
-import Data.Monoid (Monoid)
-import Pipes (Proxy, Effect, Effect', runEffect)
-import Pipes.Internal (Proxy(..))
-import Pipes.Lift (liftCatchError)
-
-data Restore m = Unmasked | Masked (forall x . m x -> m x)
-
-liftMask
-    :: forall m a' a b' b r . (MonadIO m, MonadCatch m)
-    => (forall s . ((forall x . m x -> m x) -> m s) -> m s)
-    -> ((forall x . Proxy a' a b' b m x -> Proxy a' a b' b m x)
-        -> Proxy a' a b' b m r)
-    -> Proxy a' a b' b m r
-liftMask maskVariant k = do
-    ioref <- liftIO $ newIORef Unmasked
-
-    let -- mask adjacent actions in base monad
-        loop :: Proxy a' a b' b m r -> Proxy a' a b' b m r
-        loop (Request a' fa ) = Request a' (loop . fa )
-        loop (Respond b  fb') = Respond b  (loop . fb')
-        loop (M m)            = M $ maskVariant $ \unmaskVariant -> do
-            -- stash base's unmask and merge action
-            liftIO $ writeIORef ioref $ Masked unmaskVariant
-            m >>= chunk >>= return . loop
-        loop (Pure r)         = Pure r
-
-        -- unmask adjacent actions in base monad
-        unmask :: forall q. Proxy a' a b' b m q -> Proxy a' a b' b m q
-        unmask (Request a' fa ) = Request a' (unmask . fa )
-        unmask (Respond b  fb') = Respond b  (unmask . fb')
-        unmask (M m)            = M $ do
-            -- retrieve base's unmask and apply to merged action
-            Masked unmaskVariant <- liftIO $ readIORef ioref
-            unmaskVariant (m >>= chunk >>= return . unmask)
-        unmask (Pure q)         = Pure q
-
-        -- merge adjacent actions in base monad
-        chunk :: forall s. Proxy a' a b' b m s -> m (Proxy a' a b' b m s)
-        chunk (M m) = m >>= chunk
-        chunk s     = return s
-
-    loop $ k unmask
-
-instance (MonadThrow m) => MonadThrow (Proxy a' a b' b m) where
-    throwM = lift . throwM
-
-instance (MonadCatch m) => MonadCatch (Proxy a' a b' b m) where
-    catch = liftCatchError C.catch
-
-instance (MonadMask m, MonadIO m) => MonadMask (Proxy a' a b' b m) where
-    mask                = liftMask mask
-    uninterruptibleMask = liftMask uninterruptibleMask
-
-data Finalizers m = Finalizers
-    { _nextKey    :: !Integer
-    , _finalizers :: !(M.Map Integer (m ()))
-    }
-
-{-| 'SafeT' is a monad transformer that extends the base monad with the ability
-    to 'register' and 'release' finalizers.
-
-    All unreleased finalizers are called at the end of the 'SafeT' block, even
-    in the event of exceptions.
--}
-newtype SafeT m r = SafeT { unSafeT :: R.ReaderT (IORef (Maybe (Finalizers m))) m r }
-    deriving (Functor, Applicative, Alternative, Monad, MonadPlus,
-              EC.MonadError e, SC.MonadState s, WC.MonadWriter w, CC.MonadCont,
-              MonadThrow, MonadCatch, MonadMask, MonadIO, B.MonadBase b)
-
-instance MonadTrans SafeT where
-    lift m = SafeT (lift m)
-
-instance MonadBaseControl b m => MonadBaseControl b (SafeT m) where
-#if MIN_VERSION_monad_control(1,0,0)
-     type StM (SafeT m) a = StM m a
-     liftBaseWith f = SafeT $ R.ReaderT $ \reader' ->
-         liftBaseWith $ \runInBase ->
-             f $ runInBase . (\(SafeT r) -> R.runReaderT r reader'  )
-     restoreM = SafeT . R.ReaderT . const . restoreM
-#else
-     newtype StM (SafeT m) a = StMT (StM m a)
-     liftBaseWith f = SafeT $ R.ReaderT $ \reader' ->
-         liftBaseWith $ \runInBase ->
-             f $ liftM StMT . runInBase . \(SafeT r) -> R.runReaderT r reader'
-     restoreM (StMT base) = SafeT $ R.ReaderT $ const $ restoreM base
-#endif
-
-{-| Run the 'SafeT' monad transformer, executing all unreleased finalizers at
-    the end of the computation
--}
-runSafeT :: (MonadMask m, MonadIO m) => SafeT m r -> m r
-runSafeT m = C.bracket
-    (liftIO $ newIORef $! Just $! Finalizers 0 M.empty)
-    (\ioref -> do
-        mres <- liftIO $ atomicModifyIORef' ioref $ \val ->
-            (Nothing, val)
-        case mres of
-            Nothing -> error "runSafeT's resources were freed by another"
-            Just (Finalizers _ fs) -> mapM snd (M.toDescList fs) )
-    (R.runReaderT (unSafeT m))
-{-# INLINABLE runSafeT #-}
-
-{-| Run 'SafeT' in the base monad, executing all unreleased finalizers at the
-    end of the computation
-
-    Use 'runSafeP' to safely flush all unreleased finalizers and ensure prompt
-    finalization without exiting the 'Proxy' monad.
--}
-runSafeP :: (MonadMask m, MonadIO m) => Effect (SafeT m) r -> Effect' m r
-runSafeP = lift . runSafeT . runEffect
-{-# INLINABLE runSafeP #-}
-
--- | Token used to 'release' a previously 'register'ed finalizer
-newtype ReleaseKey = ReleaseKey { unlock :: Integer }
-
-{-| 'MonadSafe' lets you 'register' and 'release' finalizers that execute in a
-    'Base' monad
--}
-class (MonadCatch m, MonadMask m, MonadIO m, MonadIO (Base m)) => MonadSafe m where
-    {-| The monad used to run resource management actions, corresponding to the
-        monad directly beneath 'SafeT'
-    -}
-    type Base (m :: * -> *) :: * -> *
-
-    -- | Lift an action from the 'Base' monad
-    liftBase :: Base m r -> m r
-
-    {-| 'register' a finalizer, ensuring that the finalizer gets called if the
-        finalizer is not 'release'd before the end of the surrounding 'SafeT'
-        block.
-    -}
-    register :: Base m () -> m ReleaseKey
-
-    {-| 'release' a registered finalizer
-
-        You can safely call 'release' more than once on the same 'ReleaseKey'.
-        Every 'release' after the first one does nothing.
-    -}
-    release  :: ReleaseKey -> m ()
-
-instance (MonadIO m, MonadCatch m, MonadMask m) => MonadSafe (SafeT m) where
-    type Base (SafeT m) = m
-
-    liftBase = lift
-
-    register io = do
-        ioref <- SafeT R.ask
-        liftIO $ do
-            n <- atomicModifyIORef' ioref $ \val ->
-                case val of
-                    Nothing -> error "register: SafeT block is closed"
-                    Just (Finalizers n fs) ->
-                        (Just $! Finalizers (n + 1) (M.insert n io fs), n)
-            return (ReleaseKey n)
-
-    release key = do
-        ioref <- SafeT R.ask
-        liftIO $ atomicModifyIORef' ioref $ \val ->
-            case val of
-                Nothing -> error "release: SafeT block is closed"
-                Just (Finalizers n fs) ->
-                    (Just $! Finalizers n (M.delete (unlock key) fs), ())
-
-instance (MonadSafe m) => MonadSafe (Proxy a' a b' b m) where
-    type Base (Proxy a' a b' b m) = Base m
-    liftBase = lift . liftBase
-    register = lift . register
-    release  = lift . release
-
-instance (MonadSafe m) => MonadSafe (I.IdentityT m) where
-    type Base (I.IdentityT m) = Base m
-    liftBase = lift . liftBase
-    register = lift . register
-    release  = lift . release
-
-instance (MonadSafe m) => MonadSafe (E.CatchT m) where
-    type Base (E.CatchT m) = Base m
-    liftBase = lift . liftBase
-    register = lift . register
-    release  = lift . release
-
-instance (MonadSafe m) => MonadSafe (R.ReaderT i m) where
-    type Base (R.ReaderT i m) = Base m
-    liftBase = lift . liftBase
-    register = lift . register
-    release  = lift . release
-
-instance (MonadSafe m) => MonadSafe (S.StateT s m) where
-    type Base (S.StateT s m) = Base m
-    liftBase = lift . liftBase
-    register = lift . register
-    release  = lift . release
-
-instance (MonadSafe m) => MonadSafe (S'.StateT s m) where
-    type Base (S'.StateT s m) = Base m
-    liftBase = lift . liftBase
-    register = lift . register
-    release  = lift . release
-
-instance (MonadSafe m, Monoid w) => MonadSafe (W.WriterT w m) where
-    type Base (W.WriterT w m) = Base m
-    liftBase = lift . liftBase
-    register = lift . register
-    release  = lift . release
-
-instance (MonadSafe m, Monoid w) => MonadSafe (W'.WriterT w m) where
-    type Base (W'.WriterT w m) = Base m
-    liftBase = lift . liftBase
-    register = lift . register
-    release  = lift . release
-
-instance (MonadSafe m, Monoid w) => MonadSafe (RWS.RWST i w s m) where
-    type Base (RWS.RWST i w s m) = Base m
-    liftBase = lift . liftBase
-    register = lift . register
-    release  = lift . release
-
-instance (MonadSafe m, Monoid w) => MonadSafe (RWS'.RWST i w s m) where
-    type Base (RWS'.RWST i w s m) = Base m
-    liftBase = lift . liftBase
-    register = lift . register
-    release  = lift . release
-
-{-| Analogous to 'C.onException' from @Control.Monad.Catch@, except this also
-    protects against premature termination
-
-    @(\`onException\` io)@ is a monad morphism.
--}
-onException :: (MonadSafe m) => m a -> Base m b -> m a
-m1 `onException` io = do
-    key <- register (io >> return ())
-    r   <- m1
-    release key
-    return r
-{-# INLINABLE onException #-}
-
-{- $utilities
-    These utilities let you supply a finalizer that runs in the 'Base' monad
-    (i.e. the monad directly beneath 'SafeT').  If you don't need to use the
-    full power of the 'Base' monad and you only need to use to use 'IO', then
-    just wrap the finalizer in 'liftIO', like this:
-
-> myAction `finally` (liftIO myFinalizer)
-
-    This will lead to a simple inferred type with a single 'MonadSafe'
-    constraint:
-
-> (MonadSafe m) => ...
-
-    For examples of this, see the utilities in "Pipes.Safe.Prelude".
-
-    If you omit the 'liftIO', the compiler will infer the following constraint
-    instead:
-
-> (MonadSafe m, Base m ~ IO) => ...
-
-    This means that this function would require 'IO' directly beneath the
-    'SafeT' monad transformer, which might not be what you want.
--}
-
-{-| Analogous to 'C.finally' from @Control.Monad.Catch@, except this also
-    protects against premature termination
--}
-finally :: (MonadSafe m) => m a -> Base m b -> m a
-m1 `finally` after = bracket_ (return ()) after m1
-{-# INLINABLE finally #-}
-
-{-| Analogous to 'C.bracket' from @Control.Monad.Catch@, except this also
-    protects against premature termination
--}
-bracket :: (MonadSafe m) => Base m a -> (a -> Base m b) -> (a -> m c) -> m c
-bracket before after action = mask $ \restore -> do
-    h <- liftBase before
-    r <- restore (action h) `onException` after h
-    _ <- liftBase (after h)
-    return r
-{-# INLINABLE bracket #-}
-
-{-| Analogous to 'C.bracket_' from @Control.Monad.Catch@, except this also
-    protects against premature termination
--}
-bracket_ :: (MonadSafe m) => Base m a -> Base m b -> m c -> m c
-bracket_ before after action = bracket before (\_ -> after) (\_ -> action)
-{-# INLINABLE bracket_ #-}
-
-{-| Analogous to 'C.bracketOnError' from @Control.Monad.Catch@, except this also
-    protects against premature termination
--}
-bracketOnError
-    :: (MonadSafe m) => Base m a -> (a -> Base m b) -> (a -> m c) -> m c
-bracketOnError before after action = mask $ \restore -> do
-    h <- liftBase before
-    restore (action h) `onException` after h
-{-# INLINABLE bracketOnError #-}
-
-{- $reexports
-    @Control.Monad.Catch@ re-exports all functions except for the ones that
-    conflict with the generalized versions provided here (i.e. 'bracket',
-    'finally', etc.).
-
-    @Control.Exception@ re-exports 'Exception' and 'SomeException'.
--}
+{-# LANGUAGE RankNTypes, TypeFamilies, FlexibleContexts, FlexibleInstances,+      MultiParamTypeClasses, UndecidableInstances, ScopedTypeVariables,+      GeneralizedNewtypeDeriving, CPP, Trustworthy #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++{-| This module provides an orphan 'MonadCatch' instance for 'Proxy' of the+    form:++> instance (MonadCatch m, MonadIO m) => MonadCatch (Proxy a' a b' b m) where++    ... so you can throw and catch exceptions within pipes using all+    'MonadCatch' operations.++    This module also provides generalized versions of some 'MonadCatch'+    operations so that you can also protect against premature termination of+    connected components.  For example, if you protect a 'readFile' computation+    using 'bracket' from this module:++> -- readFile.hs+> import Pipes+> import qualified Pipes.Prelude as P+> import Pipes.Safe+> import qualified System.IO as IO+> import Prelude hiding (readFile)+>+> readFile :: FilePath -> Producer' String (SafeT IO) ()+> readFile file = bracket+>     (do h <- IO.openFile file IO.ReadMode+>         putStrLn $ "{" ++ file ++ " open}"+>         return h )+>     (\h -> do+>         IO.hClose h+>         putStrLn $ "{" ++ file ++ " closed}" )+>     P.fromHandle++    ... then this generalized 'bracket' will guard against both exceptions and+    premature termination of other pipes:++>>> runSafeT $ runEffect $ readFile "readFile.hs" >-> P.take 4 >-> P.stdoutLn+{readFile.hs open}+-- readFile.hs+import Pipes+import qualified Pipes.Prelude as P+import Pipes.Safe+{readFile.hs closed}++    Note that the 'MonadCatch' instance for 'Proxy' provides weaker versions of+    'mask' and 'uninterruptibleMask' that do not completely prevent asynchronous+    exceptions.  Instead, they provide a weaker guarantee that asynchronous+    exceptions will only occur during 'Pipes.await's or 'Pipes.yield's and+    nowhere else.  For example, if you write:++> mask_ $ do+>     x <- await+>     lift $ print x+>     lift $ print x++    ... then you may receive an asynchronous exception during the 'Pipes.await',+    but you will not receive an asynchronous exception during or in between the+    two 'print' statements.  This weaker guarantee suffices to provide+    asynchronous exception safety.+-}++module Pipes.Safe+    ( -- * SafeT+      SafeT+    , runSafeT+    , runSafeP++     -- * MonadSafe+    , ReleaseKey+    , MonadSafe(..)++      -- * Utilities+      -- $utilities+    , onException+    , finally+    , bracket+    , bracket_+    , bracketOnError++    -- * Re-exports+    -- $reexports+    , module Control.Monad.Catch+    , module Control.Exception+    ) where++import Control.Applicative (Applicative, Alternative)+import Control.Exception(Exception(..), SomeException(..))+import qualified Control.Monad.Catch as C+import Control.Monad.Catch+    ( MonadCatch(..)+    , MonadThrow(..)+    , MonadMask(..)+    , mask_+    , uninterruptibleMask_+    , catchAll+    , catchIOError+    , catchJust+    , catchIf+    , Handler(..)+    , catches+    , handle+    , handleAll+    , handleIOError+    , handleJust+    , handleIf+    , try+    , tryJust+    , Exception(..)+    , SomeException+    )+import Control.Monad (MonadPlus)+import Control.Monad.IO.Class (MonadIO(liftIO))+import Control.Monad.Trans.Control (MonadBaseControl(..))+import Control.Monad.Trans.Class (MonadTrans(lift))+import qualified Control.Monad.Base                as B+import qualified Control.Monad.Catch.Pure          as E+import qualified Control.Monad.Trans.Identity      as I+import qualified Control.Monad.Cont.Class          as CC+import qualified Control.Monad.Error.Class         as EC+import qualified Control.Monad.Trans.Reader        as R+import qualified Control.Monad.Trans.RWS.Lazy      as RWS+import qualified Control.Monad.Trans.RWS.Strict    as RWS'+import qualified Control.Monad.Trans.State.Lazy    as S+import qualified Control.Monad.Trans.State.Strict  as S'+import qualified Control.Monad.State.Class         as SC+import qualified Control.Monad.Trans.Writer.Lazy   as W+import qualified Control.Monad.Trans.Writer.Strict as W'+import qualified Control.Monad.Writer.Class        as WC+import Data.IORef (IORef, newIORef, readIORef, writeIORef, atomicModifyIORef')+import qualified Data.Map as M+import Data.Monoid (Monoid)+import Pipes (Proxy, Effect, Effect', runEffect)+import Pipes.Internal (Proxy(..))+import Pipes.Lift (liftCatchError)++data Restore m = Unmasked | Masked (forall x . m x -> m x)++liftMask+    :: forall m a' a b' b r . (MonadIO m, MonadCatch m)+    => (forall s . ((forall x . m x -> m x) -> m s) -> m s)+    -> ((forall x . Proxy a' a b' b m x -> Proxy a' a b' b m x)+        -> Proxy a' a b' b m r)+    -> Proxy a' a b' b m r+liftMask maskVariant k = do+    ioref <- liftIO $ newIORef Unmasked++    let -- mask adjacent actions in base monad+        loop :: Proxy a' a b' b m r -> Proxy a' a b' b m r+        loop (Request a' fa ) = Request a' (loop . fa )+        loop (Respond b  fb') = Respond b  (loop . fb')+        loop (M m)            = M $ maskVariant $ \unmaskVariant -> do+            -- stash base's unmask and merge action+            liftIO $ writeIORef ioref $ Masked unmaskVariant+            m >>= chunk >>= return . loop+        loop (Pure r)         = Pure r++        -- unmask adjacent actions in base monad+        unmask :: forall q. Proxy a' a b' b m q -> Proxy a' a b' b m q+        unmask (Request a' fa ) = Request a' (unmask . fa )+        unmask (Respond b  fb') = Respond b  (unmask . fb')+        unmask (M m)            = M $ do+            -- retrieve base's unmask and apply to merged action+            Masked unmaskVariant <- liftIO $ readIORef ioref+            unmaskVariant (m >>= chunk >>= return . unmask)+        unmask (Pure q)         = Pure q++        -- merge adjacent actions in base monad+        chunk :: forall s. Proxy a' a b' b m s -> m (Proxy a' a b' b m s)+        chunk (M m) = m >>= chunk+        chunk s     = return s++    loop $ k unmask++instance (MonadThrow m) => MonadThrow (Proxy a' a b' b m) where+    throwM = lift . throwM++instance (MonadCatch m) => MonadCatch (Proxy a' a b' b m) where+    catch = liftCatchError C.catch++instance (MonadMask m, MonadIO m) => MonadMask (Proxy a' a b' b m) where+    mask                = liftMask mask+    uninterruptibleMask = liftMask uninterruptibleMask++data Finalizers m = Finalizers+    { _nextKey    :: !Integer+    , _finalizers :: !(M.Map Integer (m ()))+    }++{-| 'SafeT' is a monad transformer that extends the base monad with the ability+    to 'register' and 'release' finalizers.++    All unreleased finalizers are called at the end of the 'SafeT' block, even+    in the event of exceptions.+-}+newtype SafeT m r = SafeT { unSafeT :: R.ReaderT (IORef (Maybe (Finalizers m))) m r }+    deriving (Functor, Applicative, Alternative, Monad, MonadPlus,+              EC.MonadError e, SC.MonadState s, WC.MonadWriter w, CC.MonadCont,+              MonadThrow, MonadCatch, MonadMask, MonadIO, B.MonadBase b)++instance MonadTrans SafeT where+    lift m = SafeT (lift m)++instance MonadBaseControl b m => MonadBaseControl b (SafeT m) where+#if MIN_VERSION_monad_control(1,0,0)+     type StM (SafeT m) a = StM m a+     liftBaseWith f = SafeT $ R.ReaderT $ \reader' ->+         liftBaseWith $ \runInBase ->+             f $ runInBase . (\(SafeT r) -> R.runReaderT r reader'  )+     restoreM = SafeT . R.ReaderT . const . restoreM+#else+     newtype StM (SafeT m) a = StMT (StM m a)+     liftBaseWith f = SafeT $ R.ReaderT $ \reader' ->+         liftBaseWith $ \runInBase ->+             f $ liftM StMT . runInBase . \(SafeT r) -> R.runReaderT r reader'+     restoreM (StMT base) = SafeT $ R.ReaderT $ const $ restoreM base+#endif++{-| Run the 'SafeT' monad transformer, executing all unreleased finalizers at+    the end of the computation+-}+runSafeT :: (MonadMask m, MonadIO m) => SafeT m r -> m r+runSafeT m = C.bracket+    (liftIO $ newIORef $! Just $! Finalizers 0 M.empty)+    (\ioref -> do+        mres <- liftIO $ atomicModifyIORef' ioref $ \val ->+            (Nothing, val)+        case mres of+            Nothing -> error "runSafeT's resources were freed by another"+            Just (Finalizers _ fs) -> mapM snd (M.toDescList fs) )+    (R.runReaderT (unSafeT m))+{-# INLINABLE runSafeT #-}++{-| Run 'SafeT' in the base monad, executing all unreleased finalizers at the+    end of the computation++    Use 'runSafeP' to safely flush all unreleased finalizers and ensure prompt+    finalization without exiting the 'Proxy' monad.+-}+runSafeP :: (MonadMask m, MonadIO m) => Effect (SafeT m) r -> Effect' m r+runSafeP = lift . runSafeT . runEffect+{-# INLINABLE runSafeP #-}++-- | Token used to 'release' a previously 'register'ed finalizer+newtype ReleaseKey = ReleaseKey { unlock :: Integer }++{-| 'MonadSafe' lets you 'register' and 'release' finalizers that execute in a+    'Base' monad+-}+class (MonadCatch m, MonadMask m, MonadIO m, MonadIO (Base m)) => MonadSafe m where+    {-| The monad used to run resource management actions, corresponding to the+        monad directly beneath 'SafeT'+    -}+    type Base (m :: * -> *) :: * -> *++    -- | Lift an action from the 'Base' monad+    liftBase :: Base m r -> m r++    {-| 'register' a finalizer, ensuring that the finalizer gets called if the+        finalizer is not 'release'd before the end of the surrounding 'SafeT'+        block.+    -}+    register :: Base m () -> m ReleaseKey++    {-| 'release' a registered finalizer++        You can safely call 'release' more than once on the same 'ReleaseKey'.+        Every 'release' after the first one does nothing.+    -}+    release  :: ReleaseKey -> m ()++instance (MonadIO m, MonadCatch m, MonadMask m) => MonadSafe (SafeT m) where+    type Base (SafeT m) = m++    liftBase = lift++    register io = do+        ioref <- SafeT R.ask+        liftIO $ do+            n <- atomicModifyIORef' ioref $ \val ->+                case val of+                    Nothing -> error "register: SafeT block is closed"+                    Just (Finalizers n fs) ->+                        (Just $! Finalizers (n + 1) (M.insert n io fs), n)+            return (ReleaseKey n)++    release key = do+        ioref <- SafeT R.ask+        liftIO $ atomicModifyIORef' ioref $ \val ->+            case val of+                Nothing -> error "release: SafeT block is closed"+                Just (Finalizers n fs) ->+                    (Just $! Finalizers n (M.delete (unlock key) fs), ())++instance (MonadSafe m) => MonadSafe (Proxy a' a b' b m) where+    type Base (Proxy a' a b' b m) = Base m+    liftBase = lift . liftBase+    register = lift . register+    release  = lift . release++instance (MonadSafe m) => MonadSafe (I.IdentityT m) where+    type Base (I.IdentityT m) = Base m+    liftBase = lift . liftBase+    register = lift . register+    release  = lift . release++instance (MonadSafe m) => MonadSafe (E.CatchT m) where+    type Base (E.CatchT m) = Base m+    liftBase = lift . liftBase+    register = lift . register+    release  = lift . release++instance (MonadSafe m) => MonadSafe (R.ReaderT i m) where+    type Base (R.ReaderT i m) = Base m+    liftBase = lift . liftBase+    register = lift . register+    release  = lift . release++instance (MonadSafe m) => MonadSafe (S.StateT s m) where+    type Base (S.StateT s m) = Base m+    liftBase = lift . liftBase+    register = lift . register+    release  = lift . release++instance (MonadSafe m) => MonadSafe (S'.StateT s m) where+    type Base (S'.StateT s m) = Base m+    liftBase = lift . liftBase+    register = lift . register+    release  = lift . release++instance (MonadSafe m, Monoid w) => MonadSafe (W.WriterT w m) where+    type Base (W.WriterT w m) = Base m+    liftBase = lift . liftBase+    register = lift . register+    release  = lift . release++instance (MonadSafe m, Monoid w) => MonadSafe (W'.WriterT w m) where+    type Base (W'.WriterT w m) = Base m+    liftBase = lift . liftBase+    register = lift . register+    release  = lift . release++instance (MonadSafe m, Monoid w) => MonadSafe (RWS.RWST i w s m) where+    type Base (RWS.RWST i w s m) = Base m+    liftBase = lift . liftBase+    register = lift . register+    release  = lift . release++instance (MonadSafe m, Monoid w) => MonadSafe (RWS'.RWST i w s m) where+    type Base (RWS'.RWST i w s m) = Base m+    liftBase = lift . liftBase+    register = lift . register+    release  = lift . release++{-| Analogous to 'C.onException' from @Control.Monad.Catch@, except this also+    protects against premature termination++    @(\`onException\` io)@ is a monad morphism.+-}+onException :: (MonadSafe m) => m a -> Base m b -> m a+m1 `onException` io = do+    key <- register (io >> return ())+    r   <- m1+    release key+    return r+{-# INLINABLE onException #-}++{- $utilities+    These utilities let you supply a finalizer that runs in the 'Base' monad+    (i.e. the monad directly beneath 'SafeT').  If you don't need to use the+    full power of the 'Base' monad and you only need to use to use 'IO', then+    just wrap the finalizer in 'liftIO', like this:++> myAction `finally` (liftIO myFinalizer)++    This will lead to a simple inferred type with a single 'MonadSafe'+    constraint:++> (MonadSafe m) => ...++    For examples of this, see the utilities in "Pipes.Safe.Prelude".++    If you omit the 'liftIO', the compiler will infer the following constraint+    instead:++> (MonadSafe m, Base m ~ IO) => ...++    This means that this function would require 'IO' directly beneath the+    'SafeT' monad transformer, which might not be what you want.+-}++{-| Analogous to 'C.finally' from @Control.Monad.Catch@, except this also+    protects against premature termination+-}+finally :: (MonadSafe m) => m a -> Base m b -> m a+m1 `finally` after = bracket_ (return ()) after m1+{-# INLINABLE finally #-}++{-| Analogous to 'C.bracket' from @Control.Monad.Catch@, except this also+    protects against premature termination+-}+bracket :: (MonadSafe m) => Base m a -> (a -> Base m b) -> (a -> m c) -> m c+bracket before after action = mask $ \restore -> do+    h <- liftBase before+    r <- restore (action h) `onException` after h+    _ <- liftBase (after h)+    return r+{-# INLINABLE bracket #-}++{-| Analogous to 'C.bracket_' from @Control.Monad.Catch@, except this also+    protects against premature termination+-}+bracket_ :: (MonadSafe m) => Base m a -> Base m b -> m c -> m c+bracket_ before after action = bracket before (\_ -> after) (\_ -> action)+{-# INLINABLE bracket_ #-}++{-| Analogous to 'C.bracketOnError' from @Control.Monad.Catch@, except this also+    protects against premature termination+-}+bracketOnError+    :: (MonadSafe m) => Base m a -> (a -> Base m b) -> (a -> m c) -> m c+bracketOnError before after action = mask $ \restore -> do+    h <- liftBase before+    restore (action h) `onException` after h+{-# INLINABLE bracketOnError #-}++{- $reexports+    @Control.Monad.Catch@ re-exports all functions except for the ones that+    conflict with the generalized versions provided here (i.e. 'bracket',+    'finally', etc.).++    @Control.Exception@ re-exports 'Exception' and 'SomeException'.+-}
src/Pipes/Safe/Prelude.hs view
@@ -1,46 +1,46 @@--- | Simple resource management functions
-
-{-# LANGUAGE RankNTypes #-}
-
-module Pipes.Safe.Prelude (
-    -- * Handle management
-    withFile,
-
-    -- * String I/O
-    -- $strings
-    readFile,
-    writeFile
-    ) where
-
-import Control.Monad.IO.Class (MonadIO(liftIO))
-import Pipes (Producer', Consumer')
-import Pipes.Safe (bracket, MonadSafe)
-import qualified Pipes.Prelude as P
-import qualified System.IO as IO
-import Prelude hiding (readFile, writeFile)
-
--- | Acquire a 'IO.Handle' within 'MonadSafe'
-withFile :: (MonadSafe m) => FilePath -> IO.IOMode -> (IO.Handle -> m r) -> m r
-withFile file ioMode = bracket (liftIO $ IO.openFile file ioMode) (liftIO . IO.hClose)
-{-# INLINABLE withFile #-}
-
-{- $strings
-    Note that 'String's are very inefficient, and I will release future separate
-    packages with 'Data.ByteString.ByteString' and 'Data.Text.Text' operations.
-    I only provide these to allow users to test simple I/O without requiring any
-    additional library dependencies.
--}
-
-{-| Read lines from a file, automatically opening and closing the file as
-    necessary
--}
-readFile :: (MonadSafe m) => FilePath -> Producer' String m ()
-readFile file = withFile file IO.ReadMode P.fromHandle
-{-# INLINABLE readFile #-}
-
-{-| Write lines to a file, automatically opening and closing the file as
-    necessary
--}
-writeFile :: (MonadSafe m) => FilePath -> Consumer' String m r
-writeFile file = withFile file IO.WriteMode P.toHandle
-{-# INLINABLE writeFile #-}
+-- | Simple resource management functions++{-# LANGUAGE RankNTypes, Safe #-}++module Pipes.Safe.Prelude (+    -- * Handle management+    withFile,++    -- * String I/O+    -- $strings+    readFile,+    writeFile+    ) where++import Control.Monad.IO.Class (MonadIO(liftIO))+import Pipes (Producer', Consumer')+import Pipes.Safe (bracket, MonadSafe)+import qualified Pipes.Prelude as P+import qualified System.IO as IO+import Prelude hiding (readFile, writeFile)++-- | Acquire a 'IO.Handle' within 'MonadSafe'+withFile :: (MonadSafe m) => FilePath -> IO.IOMode -> (IO.Handle -> m r) -> m r+withFile file ioMode = bracket (liftIO $ IO.openFile file ioMode) (liftIO . IO.hClose)+{-# INLINABLE withFile #-}++{- $strings+    Note that 'String's are very inefficient, and I will release future separate+    packages with 'Data.ByteString.ByteString' and 'Data.Text.Text' operations.+    I only provide these to allow users to test simple I/O without requiring any+    additional library dependencies.+-}++{-| Read lines from a file, automatically opening and closing the file as+    necessary+-}+readFile :: (MonadSafe m) => FilePath -> Producer' String m ()+readFile file = withFile file IO.ReadMode P.fromHandle+{-# INLINABLE readFile #-}++{-| Write lines to a file, automatically opening and closing the file as+    necessary+-}+writeFile :: (MonadSafe m) => FilePath -> Consumer' String m r+writeFile file = withFile file IO.WriteMode P.toHandle+{-# INLINABLE writeFile #-}