packages feed

pipes-safe 2.2.2 → 2.2.3

raw patch · 7 files changed

+643/−645 lines, 7 filesdep +monad-controldep +mtldep +transformers-basedep ~basesetup-changedPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: monad-control, mtl, transformers-base

Dependency ranges changed: base

API changes (from Hackage documentation)

- Pipes.Safe: instance Monad m => Applicative (SafeT m)
- Pipes.Safe: instance Monad m => Functor (SafeT 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 MonadBase b m => MonadBase b (SafeT m)
+ Pipes.Safe: instance MonadBaseControl b m => MonadBaseControl b (SafeT m)
+ Pipes.Safe: instance MonadCont m => MonadCont (SafeT m)
+ Pipes.Safe: instance MonadError e m => MonadError e (SafeT m)
+ Pipes.Safe: instance MonadPlus m => MonadPlus (SafeT m)
+ Pipes.Safe: instance MonadState s m => MonadState s (SafeT m)
+ Pipes.Safe: instance MonadWriter w m => MonadWriter w (SafeT m)

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.0--`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.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.
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple-main = defaultMain+import Distribution.Simple
+main = defaultMain
changelog.md view
@@ -1,3 +1,3 @@-# Version 2.2.1--* Raise upper-bound on `exceptions` dependency.+# Version 2.2.1
+
+* Raise upper-bound on `exceptions` dependency.
pipes-safe.cabal view
@@ -1,47 +1,50 @@-Name: pipes-safe-Version: 2.2.2-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,-        transformers >= 0.2.0.0 && < 0.5,-        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.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
src/Pipes/Safe.hs view
@@ -1,439 +1,434 @@-{-# LANGUAGE RankNTypes, TypeFamilies, FlexibleContexts, ScopedTypeVariables #-}-{-# 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(pure, (<*>)))-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.IO.Class (MonadIO(liftIO))-import Control.Monad.Trans.Class (MonadTrans(lift))-import qualified Control.Monad.Catch.Pure          as E-import qualified Control.Monad.Trans.Identity      as I-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.Trans.Writer.Lazy   as W-import qualified Control.Monad.Trans.Writer.Strict as W'-import Data.IORef (IORef, newIORef, readIORef, writeIORef)-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 (Finalizers m)) m r }---- Deriving 'Functor'-instance (Monad m) => Functor (SafeT m) where-    fmap f m = SafeT (do-        r <- unSafeT m-        return (f r) )---- Deriving 'Applicative'-instance (Monad m) => Applicative (SafeT m) where-    pure r = SafeT (return r)-    mf <*> mx = SafeT (do-        f <- unSafeT mf-        x <- unSafeT mx-        return (f x) )---- Deriving 'Monad'-instance (Monad m) => Monad (SafeT m) where-    return r = SafeT (return r)-    m >>= f = SafeT (do-        r <- unSafeT m-        unSafeT (f r) )---- Deriving 'MonadIO'-instance (MonadIO m) => MonadIO (SafeT m) where-    liftIO m = SafeT (liftIO m)---- Deriving 'MonadThrow'-instance MonadThrow m => MonadThrow (SafeT m) where-    throwM e = SafeT (throwM e)---- Deriving 'MonadCatch'-instance (MonadCatch m) => MonadCatch (SafeT m) where-    m `catch` f = SafeT (unSafeT m `C.catch` \r -> unSafeT (f r))---- Deriving 'MonadMask'-instance (MonadMask m) => MonadMask (SafeT m) where-    mask k = SafeT (mask (\restore ->-        unSafeT (k (\ma -> SafeT (restore (unSafeT ma)))) ))-    uninterruptibleMask k = SafeT (uninterruptibleMask (\restore ->-        unSafeT (k (\ma -> SafeT (restore (unSafeT ma)))) ))--instance MonadTrans SafeT where-    lift m = SafeT (lift m)--{-| 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 $! Finalizers 0 M.empty)-    (\ioref -> do-        Finalizers _ fs <- liftIO (readIORef ioref)-        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-            Finalizers n fs <- readIORef ioref-            writeIORef ioref $! Finalizers (n + 1) (M.insert n io fs)-            return (ReleaseKey n)--    release key = do-        ioref <- SafeT R.ask-        liftIO $ do-            Finalizers n fs <- readIORef ioref-            writeIORef ioref $! 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 #-}
+{-# 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 #-}
+
+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 #-}