{-# LANGUAGE RankNTypes #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE CPP #-} -- | Utilities for constructing and converting 'Source', 'Source' and -- 'BSource' types. Please see "Data.Conduit.Types.Source" for more information -- on the base types. module Data.Conduit.Util.Source ( sourceState , sourceIO , transSource ) where import Control.Monad.Trans.Resource import Control.Monad.Trans.Class (lift) import Data.Conduit.Types.Source import Control.Monad (liftM) -- | Construct a 'Source' with some stateful functions. This function address -- all mutable state for you. -- -- Since 0.0.0 sourceState :: Resource m => state -- ^ Initial state -> (state -> ResourceT m (state, SourceResult output)) -- ^ Pull function -> Source m output sourceState state0 pull = Source $ do istate <- newRef state0 #if DEBUG iclosed <- newRef False #endif return PreparedSource { sourcePull = do #if DEBUG False <- readRef iclosed #endif state <- readRef istate (state', res) <- pull state #if DEBUG let isClosed = case res of Closed -> True Open _ -> False writeRef iclosed isClosed #endif writeRef istate state' return res , sourceClose = do #if DEBUG False <- readRef iclosed writeRef iclosed True #else return () #endif } -- | Construct a 'Source' based on some IO actions for alloc/release. -- -- Since 0.0.0 sourceIO :: ResourceIO m => IO state -- ^ resource and/or state allocation -> (state -> IO ()) -- ^ resource and/or state cleanup -> (state -> m (SourceResult output)) -- ^ Pull function. Note that this need not explicitly perform any cleanup. -> Source m output sourceIO alloc cleanup pull = Source $ do (key, state) <- withIO alloc cleanup #if DEBUG iclosed <- newRef False #endif return PreparedSource { sourcePull = do #if DEBUG False <- readRef iclosed #endif res <- lift $ pull state case res of Closed -> do #if DEBUG writeRef iclosed True #endif release key _ -> return () return res , sourceClose = do #if DEBUG False <- readRef iclosed writeRef iclosed True #endif release key } -- | Transform the monad a 'Source' lives in. -- -- Since 0.0.0 transSource :: (Base m ~ Base n, Monad m) => (forall a. m a -> n a) -> Source m output -> Source n output transSource f (Source mc) = Source (transResourceT f (liftM go mc)) where go c = c { sourcePull = transResourceT f (sourcePull c) , sourceClose = transResourceT f (sourceClose c) }