packages feed

pipes-safe 2.2.9 → 2.3.5

raw patch · 6 files changed

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2013, 2014 Gabriel Gonzalez+Copyright (c) 2013, 2014 Gabriella Gonzalez All rights reserved.  Redistribution and use in source and binary forms, with or without modification,@@ -8,7 +8,7 @@     * 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+    * Neither the name of Gabriella Gonzalez nor the names of other contributors       may be used to endorse or promote products derived from this software       without specific prior written permission. 
README.md view
@@ -1,7 +1,7 @@-# Pipes-Safe v2.2.9+# Pipes-Safe  `pipes-safe` builds upon-[the `pipes` library](https://github.com/Gabriel439/Haskell-Pipes-Library) to+[the `pipes` library](https://github.com/Gabriella439/Haskell-Pipes-Library) to provide exception safety and resource management.  ## Quick start@@ -55,7 +55,7 @@  ## License (BSD 3-clause) -Copyright (c) 2013 Gabriel Gonzalez+Copyright (c) 2013 Gabriella Gonzalez All rights reserved.  Redistribution and use in source and binary forms, with or without modification,@@ -68,7 +68,7 @@   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+* Neither the name of Gabriella Gonzalez nor the names of other contributors may   be used to endorse or promote products derived from this software without   specific prior written permission. 
changelog.md view
@@ -1,3 +1,38 @@+# Version++* Export `SafeT` constructor++# Version 2.3.1++* Remove `MonadFail` constraints introduced in version 2.3.0+* Implement `MonadFail` for `SafeT`++# Version 2.3.0++* BREAKING CHANGE: Support GHC 8.6.1+    * This requires adding a `MonadFail` constraints to certain utilities++# Version 2.2.9++* Fix build against older versions of `exceptions`++# Version 2.2.8++* Increase upper bound on `exceptions`++# Version 2.2.7++* Increase upper bound on `exceptions`++# Version 2.2.6++* Add `PrimMonad` instance for `SafeT`++# Version 2.2.5++* Add `tryP` and `catchP`+* `MonadThrow` and `MonadCatch` instances for `Proxy` upstreamed to `pipes`+ # Version 2.2.4  * Increase upper bound on `pipes`
pipes-safe.cabal view
@@ -1,15 +1,15 @@ Name: pipes-safe-Version: 2.2.9-Cabal-Version: >=1.8.0.2+Version: 2.3.5+Cabal-Version: >=1.10 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.4.2, 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+Copyright: 2013, 2014 Gabriella Gonzalez+Author: Gabriella Gonzalez+Maintainer: GenuineGabriella@gmail.com+Tested-With: GHC == 8.10.7, GHC == 9.0.2, GHC == 9.2.1+Bug-Reports: https://github.com/Gabriella439/Haskell-Pipes-Safe-Library/issues Synopsis: Safety for the pipes ecosystem Description:     This package adds resource management and exception handling to the @pipes@@@ -32,21 +32,22 @@ Category: Control, Pipes, Error Handling Source-Repository head     Type: git-    Location: https://github.com/Gabriel439/Haskell-Pipes-Safe-Library+    Location: https://github.com/Gabriella439/Haskell-Pipes-Safe-Library  Library     Build-Depends:-        base              >= 4       && < 5   ,-        containers        >= 0.3.0.0 && < 0.6 ,-        exceptions        >= 0.6     && < 0.11,-        mtl               >= 2.1     && < 2.3 ,-        transformers      >= 0.2.0.0 && < 0.6 ,+        base              >= 4.14    && < 4.19,+        containers        >= 0.6.2.1 && < 0.7 ,+        exceptions        >= 0.10.4  && < 0.11,+        mtl               >= 2.2.2   && < 2.4 ,+        transformers      >= 0.5.6.2 && < 0.7 ,         transformers-base >= 0.4.4   && < 0.5 ,         monad-control     >= 1.0.0.4 && < 1.1 ,-        primitive         >= 0.6.2.0 && < 0.7 ,-        pipes             >= 4.3.0   && < 4.4+        primitive         >= 0.7.0.0 && < 0.9 ,+        pipes             >= 4.3.10  && < 4.4     Exposed-Modules:         Pipes.Safe,         Pipes.Safe.Prelude     HS-Source-Dirs: src     GHC-Options: -O2 -Wall+    Default-Language: Haskell2010
src/Pipes/Safe.hs view
@@ -1,15 +1,14 @@ {-# LANGUAGE RankNTypes, TypeFamilies, FlexibleContexts, FlexibleInstances,       MultiParamTypeClasses, UndecidableInstances, ScopedTypeVariables,-      GeneralizedNewtypeDeriving, CPP, Trustworthy #-}+      GeneralizedNewtypeDeriving, Trustworthy #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -{-| This module provides an orphan 'MonadCatch' instance for 'Proxy' of the+{-| This module provides an orphan 'MonadMask' instance for 'Proxy' of the     form: -> instance (MonadCatch m, MonadIO m) => MonadCatch (Proxy a' a b' b m) where+> instance (MonadMask m, MonadIO m) => MonadMask (Proxy a' a b' b m) where -    ... so you can throw and catch exceptions within pipes using all-    'MonadCatch' operations.+    Which is needed to implement the instance for MonadSafe for Proxy.      This module also provides generalized versions of some 'MonadCatch'     operations so that you can also protect against premature termination of@@ -63,7 +62,7 @@  module Pipes.Safe     ( -- * SafeT-      SafeT+      SafeT(SafeT)     , runSafeT     , runSafeP @@ -81,22 +80,23 @@     , bracket_     , bracketOnError +    -- * Internals+    , Env+     -- * Re-exports     -- $reexports     , module Control.Monad.Catch     , module Control.Exception     ) where -import Control.Applicative (Applicative, Alternative)+import Control.Applicative (Alternative) import Control.Exception(Exception(..), SomeException(..)) import qualified Control.Monad.Catch as C import Control.Monad.Catch     ( MonadCatch(..)     , MonadThrow(..)     , MonadMask(..)-#if MIN_VERSION_exceptions(0,10,0)     , ExitCase(..)-#endif     , mask_     , uninterruptibleMask_     , catchAll@@ -134,13 +134,9 @@ 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-#if MIN_VERSION_base(4,6,0) import Data.IORef (IORef, newIORef, readIORef, writeIORef, atomicModifyIORef')-#else-import Data.IORef (IORef, newIORef, readIORef, writeIORef, atomicModifyIORef)-#endif+import Data.Kind (Type) import qualified Data.Map as M-import Data.Monoid (Monoid) import Pipes (Proxy, Effect, Effect', runEffect) import Pipes.Internal (Proxy(..)) @@ -171,7 +167,9 @@         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 <- liftIO $ do+                Masked unmaskVariant <- readIORef ioref+                return unmaskVariant             unmaskVariant (m >>= chunk >>= return . unmask)         unmask (Pure q)         = Pure q @@ -187,7 +185,6 @@      uninterruptibleMask = liftMask uninterruptibleMask -#if MIN_VERSION_exceptions(0,10,0)     generalBracket acquire release_ use = mask $ \unmasked -> do       a <- acquire       let action = do@@ -202,41 +199,64 @@  -- | This is to avoid an unnecessary partial pattern match in `generalBracket` data ExitCase_ a = ExitCaseSuccess_ a | ExitCaseException_ SomeException-#endif  data Finalizers m = Finalizers     { _nextKey    :: !Integer     , _finalizers :: !(M.Map Integer (m ()))     } +-- | Internal 'SafeT' read-write environment. Exported only so that it can be+-- passed around unmodified by users of the v'SafeT' constructor.+--+-- Warning: Using the 'Env' outside the corresponding 'SafeT' scope will+-- result in undefined behavior.+newtype Env m = Env (IORef (Maybe (Finalizers 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, MonadFix,-              EC.MonadError e, SC.MonadState s, WC.MonadWriter w, CC.MonadCont,-              MonadThrow, MonadCatch, MonadMask, MonadIO, B.MonadBase b)+newtype SafeT m r+    = -- | Constructor exported in case it's necessary for integrating 'SafeT'+      -- with other libraries. For example, implementing @mtl@-like+      -- Monad/Something/ instances will often require access to the 'SafeT'+      -- constructor.+      --+      -- Warning: Using the 'Env' outside the corresponding 'SafeT' scope will+      -- result in undefined behavior.+      SafeT (R.ReaderT (Env m) m r)+    deriving+    ( Functor+    , Applicative+    , Alternative+    , Monad+-- The derived instance for `MonadFail` requires a `MonadFail` instance for+-- `ReaderT` which is first available in `transformers-0.5.0.0`+    , MonadFail+    , MonadPlus+    , MonadFix+    , 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  instance Prim.PrimMonad m => Prim.PrimMonad (SafeT m) where   type PrimState (SafeT m) = Prim.PrimState m@@ -247,19 +267,15 @@     the end of the computation -} runSafeT :: (MonadMask m, MonadIO m) => SafeT m r -> m r-runSafeT m = C.bracket+runSafeT (SafeT m) = C.bracket     (liftIO $ newIORef $! Just $! Finalizers 0 M.empty)     (\ioref -> do-#if MIN_VERSION_base(4,6,0)         mres <- liftIO $ atomicModifyIORef' ioref $ \val ->-#else-        mres <- liftIO $ atomicModifyIORef ioref $ \val ->-#endif             (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))+    (R.runReaderT m . Env) {-# INLINABLE runSafeT #-}  {-| Run 'SafeT' in the base monad, executing all unreleased finalizers at the@@ -269,7 +285,7 @@     finalization without exiting the 'Proxy' monad. -} runSafeP :: (MonadMask m, MonadIO m) => Effect (SafeT m) r -> Effect' m r-runSafeP = lift . runSafeT . runEffect+runSafeP e = lift . runSafeT . runEffect $ e {-# INLINABLE runSafeP #-}  -- | Token used to 'release' a previously 'register'ed finalizer@@ -282,7 +298,7 @@     {-| The monad used to run resource management actions, corresponding to the         monad directly beneath 'SafeT'     -}-    type Base (m :: * -> *) :: * -> *+    type Base (m :: Type -> Type) :: Type -> Type      -- | Lift an action from the 'Base' monad     liftBase :: Base m r -> m r@@ -306,13 +322,9 @@     liftBase = lift      register io = do-        ioref <- SafeT R.ask+        Env ioref <- SafeT R.ask         liftIO $ do-#if MIN_VERSION_base(4,6,0)             n <- atomicModifyIORef' ioref $ \val ->-#else-            n <- atomicModifyIORef ioref $ \val ->-#endif                 case val of                     Nothing -> error "register: SafeT block is closed"                     Just (Finalizers n fs) ->@@ -320,18 +332,14 @@             return (ReleaseKey n)      release key = do-        ioref <- SafeT R.ask-#if MIN_VERSION_base(4,6,0)+        Env ioref <- SafeT R.ask         liftIO $ atomicModifyIORef' ioref $ \val ->-#else-        liftIO $ atomicModifyIORef ioref $ \val ->-#endif             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+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
src/Pipes/Safe/Prelude.hs view
@@ -5,25 +5,64 @@ module Pipes.Safe.Prelude (     -- * Handle management     withFile,+    withBinaryFile,+    openFile,+    openBinaryFile,      -- * String I/O     -- $strings     readFile,-    writeFile+    writeFile,++    -- * Registering/releasing+    allocate,+    allocate_     ) where +import Control.Monad.Catch (mask_) import Control.Monad.IO.Class (MonadIO(liftIO)) import Pipes (Producer', Consumer')-import Pipes.Safe (bracket, MonadSafe)+import Pipes.Safe (bracket, liftBase, register, Base, MonadSafe, ReleaseKey) 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+{- | Acquire a 'IO.Handle' within 'MonadSafe'++     The file is opened in text mode. See also: 'withBinaryFile'+-}+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 #-} +{- | Like 'withFile', but open the file in binary mode++     See 'System.IO.hSetBinaryMode' for the differences between binary and text mode.+-}+withBinaryFile :: MonadSafe m => FilePath -> IO.IOMode -> (IO.Handle -> m r) -> m r+withBinaryFile file ioMode = bracket (liftIO $ IO.openBinaryFile file ioMode) (liftIO . IO.hClose)+{-# INLINABLE withBinaryFile #-}++{- | Acquire a 'IO.Handle' within 'MonadSafe'++     The 'ReleaseKey' can be used to close the handle with 'Pipes.Safe.release';+     otherwise the handle will be closed automatically at the conclusion of the+     'MonadSafe' block.++     The file is opened in text mode. See also: 'openBinaryFile'+-}+openFile :: MonadSafe m => FilePath -> IO.IOMode -> m (ReleaseKey, IO.Handle)+openFile file ioMode = allocate (liftIO $ IO.openFile file ioMode) (liftIO . IO.hClose)+{-# INLINABLE openFile #-}++{- | Like 'openFile', but open the file in binary mode++     See 'System.IO.hSetBinaryMode' for the differences between binary and text mode.+-}+openBinaryFile :: MonadSafe m => FilePath -> IO.IOMode -> m (ReleaseKey, IO.Handle)+openBinaryFile file ioMode = allocate (liftIO $ IO.openBinaryFile file ioMode) (liftIO . IO.hClose)+{-# INLINABLE openBinaryFile #-}+ {- $strings     Note that 'String's are very inefficient, and I will release future separate     packages with 'Data.ByteString.ByteString' and 'Data.Text.Text' operations.@@ -34,13 +73,41 @@ {-| Read lines from a file, automatically opening and closing the file as     necessary -}-readFile :: (MonadSafe m) => FilePath -> Producer' String m ()+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+writeFile :: MonadSafe m => FilePath -> Consumer' String m r+writeFile file = withFile file IO.WriteMode $ \h -> P.toHandle h {-# INLINABLE writeFile #-}++{- | Acquire some resource with a guarantee that it will eventually be released++     The 'ReleaseKey' can be passed to 'Pipes.Safe.release' to+     release the resource manually. If this has not been done by the end+     of the 'MonadSafe' block, the resource will be released automatically.+-}+allocate :: MonadSafe m =>+    Base m a             -- ^ Acquire+    -> (a -> Base m ())  -- ^ Release+    -> m (ReleaseKey, a)+allocate acq rel = mask_ $ do+    a <- liftBase acq+    key <- register (rel a)+    return (key, a)++{- | Like 'allocate', but for when the resource itself is not needed++     The acquire  action runs immediately. The 'ReleaseKey' can be passed+     to 'Pipes.Safe.release' to run the release action. If this has not been+     done by the end of the 'MonadSafe' block, the release action will be+     run automatically.+-}+allocate_ :: MonadSafe m =>+    Base m a        -- ^ Acquire+    -> (Base m ())  -- ^ Release+    -> m ReleaseKey+allocate_ acq rel = fmap fst (allocate acq (const rel))