{-
Copyright 2010 Mario Blazevic
This file is part of the Streaming Component Combinators (SCC) project.
The SCC project is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
version.
SCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with SCC. If not, see
<http://www.gnu.org/licenses/>.
-}-- | This module provides a bridge between the Control.Monad.Coroutine and the Data.Enumerator monad transformers.moduleControl.Monad.Coroutine.Enumerator(coroutineEnumerator,enumeratorCoroutine,coroutineIteratee,iterateeCoroutine,iterateeStreamCoroutine,streamCoroutineIteratee)whereimportControl.Monad(liftM,unless)importControl.Exception.Base(SomeException)importData.Enumerator(Enumerator,Iteratee(..),Stream(..))importqualifiedData.EnumeratorasEnumeratorimportControl.Monad.CoroutineimportControl.Monad.Coroutine.SuspensionFunctors(Await(Await),Yield(Yield),await,yield)-- | Converts an 'Iteratee' into a 'Coroutine' parameterized with the 'Await' [x] functor. The coroutine treats an empty-- input chunk as 'EOF'.iterateeCoroutine::Monadm=>Iterateeamb->Coroutine(Await[a])m(EitherSomeException(b,[a]))iterateeCoroutine=convert.iterateeStreamCoroutinewhereconvert=liftM(eitherLeft(Right.streamChunk)).mapSuspensionconvertSuspensionconvertSuspension(Awaitcont)=Await(endOnEmptyChunkcont)endOnEmptyChunkcont[]=contEOFendOnEmptyChunkcontchunk=cont(Chunkschunk)streamChunk(b,EOF)=(b,[])streamChunk(b,Chunkschunk)=(b,chunk)-- | Converts a 'Coroutine' parameterized with the 'Await' [x] functor, treating an ampty input chunk as 'EOF', into an-- 'Iteratee'.coroutineIteratee::Monadm=>Coroutine(Await[a])m(EitherSomeException(b,[a]))->IterateeambcoroutineIteratee=streamCoroutineIteratee.convert.liftM(eitherLeft(Right.\(b,chunk)->(b,Chunkschunk)))whereconvertcort=Coroutine{resume=resumecort>>=return.either(Left.convertSuspension)Right}convertSuspension(Awaitcont)=Await(ignoreEmptyChunks(convert.cont))ignoreEmptyChunkscont(Chunks[])=suspend$Await(ignoreEmptyChunkscont)ignoreEmptyChunkscont(Chunkschunk)=contchunkignoreEmptyChunkscontEOF=cont[]-- | Converts an 'Iteratee' into a 'Coroutine' parameterized with the 'Await' ('Stream' x) functor.iterateeStreamCoroutine::Monadm=>Iterateeamb->Coroutine(Await(Streama))m(EitherSomeException(b,Streama))iterateeStreamCoroutineiter=Coroutine{resume=liftMconvertStep$runIterateeiter}whereconvertStep(Enumerator.Yieldbs)=Right$Right(b,s)convertStep(Enumerator.Errore)=Right$LefteconvertStep(Enumerator.Continuecont)=Left(Await(iterateeStreamCoroutine.cont))-- | Converts a 'Coroutine' parameterized with the 'Await' functor into an 'Iteratee'.streamCoroutineIteratee::Monadm=>Coroutine(Await(Streama))m(EitherSomeException(b,Streama))->IterateeambstreamCoroutineIterateec=Iteratee(liftMconvertStep$resumec)whereconvertStep(Left(Awaitcont))=Enumerator.Continue(streamCoroutineIteratee.cont)convertStep(Right(Lefte))=Enumerator.ErroreconvertStep(Right(Right(b,s)))=Enumerator.Yieldbs-- | Converts an 'Enumerator' into a 'Coroutine' parameterized with the 'Yield' functor.enumeratorCoroutine::Monadm=>Enumeratora(Coroutine(Yield[a])m)()->Coroutine(Yield[a])m()enumeratorCoroutineenum=runIteratee(enumstep)>>return()wherestep=Enumerator.Continueyieldingyielding(Chunksxs)=Iteratee(unless(nullxs)(yieldxs)>>returnstep)yieldingEOF=Enumerator.returnI(Enumerator.Yield()EOF)-- | Converts a 'Coroutine' parameterized with the 'Yield' functor into an 'Enumerator'.coroutineEnumerator::Monadm=>Coroutine(Yield[a])mb->EnumeratoramccoroutineEnumeratorcstep@(Enumerator.Continuecont)=Iteratee(resumec>>=eitherfeed(const$returnstep))wherefeed(Yieldchunkc)=runIteratee(cont(Chunkschunk))>>=runIteratee.coroutineEnumeratorccoroutineEnumerator_step=Enumerator.returnIstep