Blame Data/Conduit/Lazy.hs

Packit 4b2029
{-# LANGUAGE CPP #-}
Packit 4b2029
{-# LANGUAGE FlexibleContexts #-}
Packit 4b2029
{-# LANGUAGE Trustworthy #-}
Packit 4b2029
Packit 4b2029
{-# OPTIONS_GHC -fno-warn-deprecations #-} -- Suppress warnings around Control.Monad.Trans.Error
Packit 4b2029
-- | Use lazy I\/O for consuming the contents of a source. Warning: All normal
Packit 4b2029
-- warnings of lazy I\/O apply. In particular, if you are using this with a
Packit 4b2029
-- @ResourceT@ transformer, you must force the list to be evaluated before
Packit 4b2029
-- exiting the @ResourceT@.
Packit 4b2029
module Data.Conduit.Lazy
Packit 4b2029
    ( lazyConsume
Packit 4b2029
    , MonadActive (..)
Packit 4b2029
    ) where
Packit 4b2029
Packit 4b2029
import Data.Conduit
Packit 4b2029
import Data.Conduit.Internal (Pipe (..), unConduitM)
Packit 4b2029
import System.IO.Unsafe (unsafeInterleaveIO)
Packit 4b2029
Packit 4b2029
import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_)
Packit 4b2029
import Control.Monad.Trans.Class (lift)
Packit 4b2029
import Control.Monad.IO.Class (MonadIO, liftIO)
Packit 4b2029
Packit 4b2029
import Control.Monad.Trans.Identity ( IdentityT)
Packit 4b2029
import Control.Monad.Trans.List     ( ListT    )
Packit 4b2029
import Control.Monad.Trans.Maybe    ( MaybeT   )
Packit 4b2029
import Control.Monad.Trans.Error    ( ErrorT, Error)
Packit 4b2029
import Control.Monad.Trans.Reader   ( ReaderT  )
Packit 4b2029
import Control.Monad.Trans.State    ( StateT   )
Packit 4b2029
import Control.Monad.Trans.Writer   ( WriterT  )
Packit 4b2029
import Control.Monad.Trans.RWS      ( RWST     )
Packit 4b2029
Packit 4b2029
import qualified Control.Monad.Trans.RWS.Strict    as Strict ( RWST   )
Packit 4b2029
import qualified Control.Monad.Trans.State.Strict  as Strict ( StateT )
Packit 4b2029
import qualified Control.Monad.Trans.Writer.Strict as Strict ( WriterT )
Packit 4b2029
Packit 4b2029
#if (__GLASGOW_HASKELL__ < 710)
Packit 4b2029
import Data.Monoid (Monoid)
Packit 4b2029
#endif
Packit 4b2029
import Control.Monad.ST (ST)
Packit 4b2029
import qualified Control.Monad.ST.Lazy as Lazy
Packit 4b2029
import Data.Functor.Identity (Identity)
Packit 4b2029
import Control.Monad.Trans.Resource.Internal (ResourceT (ResourceT), ReleaseMap (ReleaseMapClosed))
Packit 4b2029
import qualified Data.IORef as I
Packit 4b2029
Packit 4b2029
-- | Use lazy I\/O to consume all elements from a @Source@.
Packit 4b2029
--
Packit 4b2029
-- This function relies on 'monadActive' to determine if the underlying monadic
Packit 4b2029
-- state has been closed.
Packit 4b2029
--
Packit 4b2029
-- Since 0.3.0
Packit 4b2029
lazyConsume :: (MonadBaseControl IO m, MonadActive m) => Source m a -> m [a]
Packit 4b2029
lazyConsume =
Packit 4b2029
#if MIN_VERSION_conduit(1, 2, 0)
Packit 4b2029
    go . flip unConduitM Done
Packit 4b2029
#else
Packit 4b2029
    go . unConduitM
Packit 4b2029
#endif
Packit 4b2029
  where
Packit 4b2029
    go (Done _) = return []
Packit 4b2029
    go (HaveOutput src _ x) = do
Packit 4b2029
        xs <- liftBaseOp_ unsafeInterleaveIO $ go src
Packit 4b2029
        return $ x : xs
Packit 4b2029
    go (PipeM msrc) = liftBaseOp_ unsafeInterleaveIO $ do
Packit 4b2029
        a <- monadActive
Packit 4b2029
        if a
Packit 4b2029
            then msrc >>= go
Packit 4b2029
            else return []
Packit 4b2029
    go (NeedInput _ c) = go (c ())
Packit 4b2029
    go (Leftover p _) = go p
Packit 4b2029
Packit 4b2029
-- | Determine if some monad is still active. This is intended to prevent usage
Packit 4b2029
-- of a monadic state after it has been closed.  This is necessary for such
Packit 4b2029
-- cases as lazy I\/O, where an unevaluated thunk may still refer to a
Packit 4b2029
-- closed @ResourceT@.
Packit 4b2029
--
Packit 4b2029
-- Since 0.3.0
Packit 4b2029
class Monad m => MonadActive m where
Packit 4b2029
    monadActive :: m Bool
Packit 4b2029
Packit 4b2029
instance (MonadIO m, MonadActive m) => MonadActive (ResourceT m) where
Packit 4b2029
    monadActive = ResourceT $ \rmMap -> do
Packit 4b2029
        rm <- liftIO $ I.readIORef rmMap
Packit 4b2029
        case rm of
Packit 4b2029
            ReleaseMapClosed -> return False
Packit 4b2029
            _ -> monadActive -- recurse
Packit 4b2029
Packit 4b2029
instance MonadActive Identity where
Packit 4b2029
    monadActive = return True
Packit 4b2029
Packit 4b2029
instance MonadActive IO where
Packit 4b2029
    monadActive = return True
Packit 4b2029
Packit 4b2029
instance MonadActive (ST s) where
Packit 4b2029
    monadActive = return True
Packit 4b2029
Packit 4b2029
instance MonadActive (Lazy.ST s) where
Packit 4b2029
    monadActive = return True
Packit 4b2029
Packit 4b2029
#define GO(T) instance MonadActive m => MonadActive (T m) where monadActive = lift monadActive
Packit 4b2029
#define GOX(X, T) instance (X, MonadActive m) => MonadActive (T m) where monadActive = lift monadActive
Packit 4b2029
GO(IdentityT)
Packit 4b2029
GO(ListT)
Packit 4b2029
GO(MaybeT)
Packit 4b2029
GOX(Error e, ErrorT e)
Packit 4b2029
GO(ReaderT r)
Packit 4b2029
GO(StateT s)
Packit 4b2029
GOX(Monoid w, WriterT w)
Packit 4b2029
GOX(Monoid w, RWST r w s)
Packit 4b2029
GOX(Monoid w, Strict.RWST r w s)
Packit 4b2029
GO(Strict.StateT s)
Packit 4b2029
GOX(Monoid w, Strict.WriterT w)
Packit 4b2029
#undef GO
Packit 4b2029
#undef GOX
Packit 4b2029
Packit 4b2029
instance MonadActive m => MonadActive (Pipe l i o u m) where
Packit 4b2029
    monadActive = lift monadActive
Packit 4b2029
instance MonadActive m => MonadActive (ConduitM i o m) where
Packit 4b2029
    monadActive = lift monadActive