------------------------------------------------------------------------------- |-- Module: Data.Enumerator.Binary-- Copyright: 2010 John Millikin-- License: MIT---- Maintainer: jmillikin@gmail.com-- Portability: portable---- This module is intended to be imported qualified:---- @-- import qualified Data.Enumerator.Binary as EB-- @---- Since: 0.4.5-------------------------------------------------------------------------------moduleData.Enumerator.Binary(-- * Binary IOenumHandle,enumFile,iterHandle-- * List analogues,Data.Enumerator.Binary.head,Data.Enumerator.Binary.drop,Data.Enumerator.Binary.dropWhile,Data.Enumerator.Binary.take,Data.Enumerator.Binary.takeWhile,Data.Enumerator.Binary.consume,require,isolate)whereimportPreludehiding(head,drop,takeWhile)importData.Enumeratorhiding(head,drop)importqualifiedData.ByteStringasBimportData.Enumerator.Util(tryStep)importqualifiedControl.ExceptionasExcimportControl.Monad.IO.Class(MonadIO)importqualifiedSystem.IOasIOimportSystem.IO.Error(isEOFError)importData.Word(Word8)importqualifiedData.ByteString.LazyasBL-- | Read bytes (in chunks of the given buffer size) from the handle, and-- stream them to an 'Iteratee'. If an exception occurs during file IO,-- enumeration will stop and 'Error' will be returned. Exceptions from the-- iteratee are not caught.---- This enumerator blocks until at least one byte is available from the-- handle, and might read less than the maximum buffer size in some-- cases.---- The handle should be opened with no encoding, and in 'IO.ReadMode' or-- 'IO.ReadWriteMode'.enumHandle::MonadIOm=>Integer-- ^ Buffer size->IO.Handle->EnumeratorB.ByteStringmbenumHandlebufferSizeh=loopwhereloop(Continuek)=withBytes$\bytes->ifB.nullbytesthencontinuekelsek(Chunks[bytes])>>==looploopstep=returnIstepintSize=fromIntegerbufferSizewithBytes=tryStep$dohasInput<-Exc.catch(IO.hWaitForInputh(-1))(\err->ifisEOFErrorerrthenreturnFalseelseExc.throwIOerr)ifhasInputthenB.hGetNonBlockinghintSizeelsereturnB.empty-- | Opens a file path in binary mode, and passes the handle to 'enumHandle'.-- The file will be closed when the 'Iteratee' finishes.enumFile::FilePath->EnumeratorB.ByteStringIObenumFilepath=enumwherewithHandle=tryStep(IO.openBinaryFilepathIO.ReadMode)enumstep=withHandle$\h->doIteratee$Exc.finally(runIteratee(enumHandle4096hstep))(IO.hCloseh)-- | Read bytes from a stream and write them to a handle. If an exception-- occurs during file IO, enumeration will stop and 'Error' will be-- returned.---- The handle should be opened with no encoding, and in 'IO.WriteMode' or-- 'IO.ReadWriteMode'.iterHandle::MonadIOm=>IO.Handle->IterateeB.ByteStringm()iterHandleh=continuestepwherestepEOF=yield()EOFstep(Chunks[])=continuestepstep(Chunksbytes)=letput=mapM_(B.hPuth)bytesintryStepput(\_->continuestep)toChunks::BL.ByteString->StreamB.ByteStringtoChunks=Chunks.BL.toChunks-- | Get the next byte from the stream, or 'Nothing' if the stream has-- ended.---- Since: 0.4.5head::Monadm=>IterateeB.ByteStringm(MaybeWord8)head=continueloopwhereloop(Chunksxs)=caseBL.uncons(BL.fromChunksxs)ofJust(char,extra)->yield(Justchar)(toChunksextra)Nothing->headloopEOF=yieldNothingEOF-- | @drop n@ ignores /n/ bytes of input from the stream.---- Since: 0.4.5drop::Monadm=>Integer->IterateeB.ByteStringm()dropn|n<=0=return()dropn=continue(loopn)whereloopn'(Chunksxs)=iterwherelazy=BL.fromChunksxslen=toInteger(BL.lengthlazy)iter=iflen<n'thendrop(n'-len)elseyield()(toChunks(BL.drop(fromIntegern')lazy))loop_EOF=yield()EOF-- | @dropWhile p@ ignores input from the stream until the first byte which-- does not match the predicate.---- Since: 0.4.5dropWhile::Monadm=>(Word8->Bool)->IterateeB.ByteStringm()dropWhilep=continueloopwhereloop(Chunksxs)=iterwherelazy=BL.dropWhilep(BL.fromChunksxs)iter=ifBL.nulllazythencontinueloopelseyield()(toChunkslazy)loopEOF=yield()EOF-- | @take n@ extracts the next /n/ bytes from the stream, as a lazy-- ByteString.---- Since: 0.4.5take::Monadm=>Integer->IterateeB.ByteStringmBL.ByteStringtaken|n<=0=returnBL.emptytaken=continue(loopidn)whereloopaccn'(Chunksxs)=iterwherelazy=BL.fromChunksxslen=toInteger(BL.lengthlazy)iter=iflen<n'thencontinue(loop(acc.(BL.appendlazy))(n'-len))elselet(xs',extra)=BL.splitAt(fromIntegern')lazyinyield(accxs')(toChunksextra)loopacc_EOF=yield(accBL.empty)EOF-- | @takeWhile p@ extracts input from the stream until the first byte which-- does not match the predicate.---- Since: 0.4.5takeWhile::Monadm=>(Word8->Bool)->IterateeB.ByteStringmBL.ByteStringtakeWhilep=continue(loopid)whereloopacc(Chunks[])=continue(loopacc)loopacc(Chunksxs)=iterwherelazy=BL.fromChunksxs(xs',extra)=BL.spanplazyiter=ifBL.nullextrathencontinue(loop(acc.(BL.appendlazy)))elseyield(accxs')(toChunksextra)loopaccEOF=yield(accBL.empty)EOF-- | Read all remaining input from the stream, and return as a lazy-- ByteString.---- Since: 0.4.5consume::Monadm=>IterateeB.ByteStringmBL.ByteStringconsume=continue(loopid)whereloopacc(Chunks[])=continue(loopacc)loopacc(Chunksxs)=iterwherelazy=BL.fromChunksxsiter=continue(loop(acc.(BL.appendlazy)))loopaccEOF=yield(accBL.empty)EOF-- | @require n@ buffers input until at least /n/ bytes are available, or-- throws an error if the stream ends early.---- Since: 0.4.5require::Monadm=>Integer->IterateeB.ByteStringm()requiren|n<=0=return()requiren=continue(loopidn)whereloopaccn'(Chunksxs)=iterwherelazy=BL.fromChunksxslen=toInteger(BL.lengthlazy)iter=iflen<n'thencontinue(loop(acc.(BL.appendlazy))(n'-len))elseyield()(toChunks(acclazy))loop__EOF=throwError(Exc.ErrorCall"require: Unexpected EOF")-- | @isolate n@ reads at most /n/ bytes from the stream, and passes them-- to its iteratee. If the iteratee finishes early, bytes continue to be-- consumed from the outer stream until /n/ have been consumed.---- Since: 0.4.5isolate::Monadm=>Integer->EnumerateeB.ByteStringB.ByteStringmbisolatenstep|n<=0=returnstepisolaten(Continuek)=continueloopwhereloop(Chunks[])=continuelooploop(Chunksxs)=iterwherelazy=BL.fromChunksxslen=toInteger(BL.lengthlazy)iter=iflen<=nthenk(Chunksxs)>>==isolate(n-len)elselet(s1,s2)=BL.splitAt(fromIntegern)lazyink(toChunkss1)>>==(\step->yieldstep(toChunkss2))loopEOF=kEOF>>==(\step->yieldstepEOF)isolatenstep=dropn>>returnstep