{-# LANGUAGE FlexibleContexts #-}{-# LANGUAGE RankNTypes #-}{-# LANGUAGE TypeFamilies #-}{-# LANGUAGE CPP #-}-- | Utilities for constructing and covnerting conduits. Please see-- "Data.Conduit.Types.Conduit" for more information on the base types.moduleData.Conduit.Util.Conduit(conduitState,ConduitStateResult(..),conduitIO,ConduitIOResult(..),transConduit-- *** Sequencing,SequencedSink,sequenceSink,SequencedSinkResponse(..))whereimportControl.Monad.Trans.ResourceimportControl.Monad.Trans.ClassimportData.Conduit.Types.ConduitimportData.Conduit.Types.Sink-- | A helper type for @conduitState@, indicating the result of being pushed-- to. It can either indicate that processing is done, or to continue with the-- updated state.---- Since 0.2.0dataConduitStateResultstateinputoutput=StateFinished(Maybeinput)[output]|StateProducingstate[output]instanceFunctor(ConduitStateResultstateinput)wherefmapf(StateFinishedab)=StateFinisheda(mapfb)fmapf(StateProducingab)=StateProducinga(mapfb)-- | Construct a 'Conduit' with some stateful functions. This function addresses-- threading the state value for you.---- Since 0.2.0conduitState::Resourcem=>state-- ^ initial state->(state->input->ResourceTm(ConduitStateResultstateinputoutput))-- ^ Push function.->(state->ResourceTm[output])-- ^ Close function. The state need not be returned, since it will not be used again.->ConduitinputmoutputconduitStatestate0push0close0=Conduit(pushstate0)(close0state0)wherepushstateinput=dores<-state`seq`push0stateinputreturn$caseresofStateFinishedab->FinishedabStateProducingstate'output->Producing(Conduit(pushstate')(close0state'))output-- | A helper type for @conduitIO@, indicating the result of being pushed to.-- It can either indicate that processing is done, or to continue.---- Since 0.2.0dataConduitIOResultinputoutput=IOFinished(Maybeinput)[output]|IOProducing[output]instanceFunctor(ConduitIOResultinput)wherefmapf(IOFinishedab)=IOFinisheda(mapfb)fmapf(IOProducingb)=IOProducing(mapfb)-- | Construct a 'Conduit'.---- Since 0.2.0conduitIO::ResourceIOm=>IOstate-- ^ resource and/or state allocation->(state->IO())-- ^ resource and/or state cleanup->(state->input->m(ConduitIOResultinputoutput))-- ^ Push function. Note that this need not explicitly perform any cleanup.->(state->m[output])-- ^ Close function. Note that this need not explicitly perform any cleanup.->ConduitinputmoutputconduitIOalloccleanuppush0close0=Conduit{conduitPush=\input->do(key,state)<-withIOalloccleanuppushkeystateinput,conduitClose=do(key,state)<-withIOalloccleanupclosekeystate}wherepushkeystateinput=dores<-lift$push0stateinputcaseresofIOProducingoutput->return$Producing(Conduit(pushkeystate)(closekeystate))outputIOFinishedab->doreleasekeyreturn$Finishedabclosekeystate=dooutput<-lift$close0statereleasekeyreturnoutput-- | Transform the monad a 'Conduit' lives in.---- See @transSource@ for more information.---- Since 0.2.0transConduit::(Monadm,Basem~Basen)=>(foralla.ma->na)->Conduitinputmoutput->ConduitinputnoutputtransConduitfc=c{conduitPush=transResourceTf.fmap(transConduitPushf).conduitPushc,conduitClose=transResourceTf(conduitClosec)}transConduitPush::(Basem~Basen,Monadm)=>(foralla.ma->na)->ConduitResultinputmoutput->ConduitResultinputnoutputtransConduitPush_(Finishedab)=FinishedabtransConduitPushf(Producingconduitoutput)=Producing(transConduitfconduit)output-- | Return value from a 'SequencedSink'.---- Since 0.2.0dataSequencedSinkResponsestateinputmoutput=Emitstate[output]-- ^ Set a new state, and emit some new output.|Stop-- ^ End the conduit.|StartConduit(Conduitinputmoutput)-- ^ Pass control to a new conduit.-- | Helper type for constructing a @Conduit@ based on @Sink@s. This allows you-- to write higher-level code that takes advantage of existing conduits and-- sinks, and leverages a sink's monadic interface.---- Since 0.2.0typeSequencedSinkstateinputmoutput=state->Sinkinputm(SequencedSinkResponsestateinputmoutput)dataSCStatestateinputmoutput=SCNewStatestate|SCConduit(Conduitinputmoutput)|SCSink(input->ResourceTm(SinkResultinputm(SequencedSinkResponsestateinputmoutput)))(ResourceTm(SequencedSinkResponsestateinputmoutput))-- | Convert a 'SequencedSink' into a 'Conduit'.---- Since 0.2.0sequenceSink::Resourcem=>state-- ^ initial state->SequencedSinkstateinputmoutput->ConduitinputmoutputsequenceSinkstate0fsink=conduitState(SCNewStatestate0)(scPushidfsink)scClosegoRes::Resourcem=>SequencedSinkResponsestateinputmoutput->Maybeinput->([output]->[output])->SequencedSinkstateinputmoutput->ResourceTm(ConduitStateResult(SCStatestateinputmoutput)inputoutput)goRes(Emitstateoutput)(Justinput)frontfsink=scPush(front.(output++))fsink(SCNewStatestate)inputgoRes(Emitstateoutput)Nothingfront_=return$StateProducing(SCNewStatestate)$frontoutputgoResStopminputfront_=return$StateFinishedminput$front[]goRes(StartConduitc)Nothingfront_=return$StateProducing(SCConduitc)$front[]goRes(StartConduitc)(Justinput)frontfsink=scPushfrontfsink(SCConduitc)inputscPush::Resourcem=>([output]->[output])->SequencedSinkstateinputmoutput->SCStatestateinputmoutput->input->ResourceTm(ConduitStateResult(SCStatestateinputmoutput)inputoutput)scPushfrontfsink(SCNewStatestate)input=go(fsinkstate)wherego(SinkDatapush'close')=scPushfrontfsink(SCSinkpush'close')inputgo(SinkNoDatares)=goResres(Justinput)frontfsinkgo(SinkLiftmsink)=msink>>=goscPushfront_(SCConduitconduit)input=dores<-conduitPushconduitinputreturn$caseresofProducingcx->StateProducing(SCConduitc)$frontxFinishedxy->StateFinishedx$frontyscPushfrontfsink(SCSinkpush_)input=domres<-pushinputcasemresofDoneminputres->goResresminputfrontfsinkProcessingpush'close'->return(StateProducing(SCSinkpush'close')$front[])scClose::Monadm=>SCStatestateinptumoutput->ResourceTm[output]scClose(SCNewState_)=return[]scClose(SCConduitconduit)=conduitCloseconduitscClose(SCSink_close)=dores<-closecaseresofEmit_os->returnosStop->return[]StartConduitc->conduitClosec