{-# LANGUAGE FlexibleContexts #-} -- | Defines the types for a source, which is a producer of data. module Data.Conduit.Types.Source ( SourceResult (..) , Source (..) ) where import Control.Monad.Trans.Resource import Data.Monoid (Monoid (..)) import Control.Monad (liftM) -- | Result of pulling from a source. Either a new piece of data (@Open@), or -- indicates that the source is now @Closed@. -- -- The @Open@ constructor returns both a new value, as well as a new @Source@, -- which should be used in place of the previous @Source@. -- -- Since 0.2.0 data SourceResult m a = Open (Source m a) a | Closed instance Monad m => Functor (SourceResult m) where fmap f (Open p a) = Open (fmap f p) (f a) fmap _ Closed = Closed -- | A @Source@ has two operations on it: pull some data, and close the -- @Source@. Since @Source@ is built on top of 'ResourceT', all acquired -- resources should be automatically released anyway. Closing a @Source@ early -- is merely an optimization to free scarce resources as soon as possible. -- -- A @Source@ is should free any resources it allocated when either -- @sourceClose@ is called or a @Closed@ is returned. However, based on the -- usage of @ResourceT@, this is simply an optimization. -- -- Since 0.2.0 data Source m a = Source { sourcePull :: ResourceT m (SourceResult m a) , sourceClose :: ResourceT m () } instance Monad m => Functor (Source m) where fmap f src = src { sourcePull = liftM (fmap f) (sourcePull src) } instance Resource m => Monoid (Source m a) where mempty = Source { sourcePull = return Closed , sourceClose = return () } mappend a b = mconcat [a, b] mconcat [] = mempty mconcat (next0:rest0) = src next0 rest0 where src next rest = Source (pull next rest) (close next rest) pull current rest = do res <- sourcePull current case res of -- end of the current Source Closed -> do case rest of -- ... and open the next one a:as -> pull a as -- no more source, return an EOF [] -> return Closed Open current' val -> return (Open (src current' rest) val) close current _rest = do -- we only need to close the current Source, since they are opened -- one at a time sourceClose current