@@ -23,6 +23,8 @@ import qualified Data.ByteString as B
2323import System.IO.Unsafe (unsafeInterleaveIO)
2424import System.IO (withBinaryFile, IOMode (ReadMode), Handle, hIsEOF)
2525import Data.ByteString.Lazy.Internal (defaultChunkSize)
26+import Control.Concurrent (forkIO)
27+import Control.Concurrent.MVar
2628
2729-- | Performs a specified conversion on each 'B.ByteString' output by an
2830-- enumerator.
@@ -32,14 +34,17 @@ mapE f e iter = e iter' where
3234
3335-- | This uses 'unsafeInterleaveIO' to lazily read from an enumerator. All
3436-- normal lazy I/O warnings apply.
35−toLBS :: Enumerator (Maybe B.ByteString) -> IO L.ByteString
36−toLBS e = L.fromChunks `fmap` helper where
37− helper = unsafeInterleaveIO $ do
38− x <- toSource e
37+toLBS :: Enumerator () -> IO L.ByteString
38+toLBS e = do
39+ source <- toSource e
40+ L.fromChunks `fmap` helper source
41+ where
42+ helper source = unsafeInterleaveIO $ do
43+ x <- source
3944 case x of
4045 Nothing -> return []
4146 Just x' -> do
42− xs <- helper
47+ xs <- helper source
4348 return $ x' : xs
4449
4550-- | This function safely converts a lazy bytestring into an enumerator.
@@ -61,8 +66,29 @@ fromLBS' lbs' iter a0 = lbs' >>= \lbs -> fromLBS lbs iter a0
6166-- | A source is a more standard way of accessing data from an 'Enumerator'.
6267-- Each time you call it, it returns the next chunk of data if available, or
6368-- 'Nothing' if the data has been completely consumed.
64−toSource :: Enumerator (Maybe B.ByteString) -> IO (Maybe B.ByteString)
65−toSource e = fmap (either id id) $ e (const $ return . Left . Just) Nothing
69+toSource :: Enumerator () -> IO (IO (Maybe B.ByteString))
70+toSource e = do
71+ buffer <- newEmptyMVar
72+ forkIO $ e (helper buffer) () >> putMVar buffer Nothing
73+ return $ source buffer
74+ where
75+ helper :: MVar (Maybe B.ByteString)
76+ -> ()
77+ -> B.ByteString
78+ -> IO (Either () ())
79+ helper buffer _ bs = do
80+ putMVar buffer $ Just bs
81+ return $ Right ()
82+ source :: MVar (Maybe B.ByteString) -> IO (Maybe B.ByteString)
83+ source mmbs = do
84+ mbs <- takeMVar mmbs
85+ case mbs of
86+ Nothing -> do
87+ -- By putting Nothing back in, the source can be called
88+ -- again without causing a deadlock.
89+ putMVar mmbs Nothing
90+ return Nothing
91+ Just bs -> return $ Just bs
6692
6793-- | Read a chunk of data from the given 'Handle' at a time. We use
6894-- 'defaultChunkSize' from the bytestring package to determine the largest