@@ -6,12 +6,18 @@ module Network.Wai.Enumerator
66 , fromLBS'
77 -- * Source
88 , toSource
9+ -- * Handle
10+ , fromHandle
11+ -- * FilePath
12+ , fromFile
13+ , fromEitherFile
914 ) where
1015
1116import Network.Wai (Enumerator)
1217import qualified Data.ByteString.Lazy as L
1318import qualified Data.ByteString as B
1419import System.IO.Unsafe (unsafeInterleaveIO)
20+import System.IO (withBinaryFile, IOMode (ReadMode), Handle, hIsEOF)
1521
1622-- | This uses 'unsafeInterleaveIO' to lazily read from an enumerator. All
1723-- normal lazy I/O warnings apply.
@@ -27,11 +33,11 @@ toLBS e = L.fromChunks `fmap` helper where
2733
2834fromLBS :: L.ByteString -> Enumerator a
2935fromLBS lbs iter a0 = helper a0 $ L.toChunks lbs where
30− helper a [] = return a
36+ helper a [] = return $ Right a
3137 helper a (x:xs) = do
3238 ea <- iter a x
3339 case ea of
34− Left a' -> return a'
40+ Left a' -> return $ Left a'
3541 Right a' -> helper a' xs
3642
3743fromLBS' :: IO L.ByteString -> Enumerator a
@@ -41,4 +47,26 @@ fromLBS' lbs' iter a0 = lbs' >>= \lbs -> fromLBS lbs iter a0
4147-- Each time you call it, it returns the next chunk of data if available, or
4248-- 'Nothing' if the data has been completely consumed.
4349toSource :: Enumerator (Maybe B.ByteString) -> IO (Maybe B.ByteString)
44−toSource e = e (const $ return . Left . Just) Nothing
50+toSource e = fmap (either id id) $ e (const $ return . Left . Just) Nothing
51+
52+chunkSize :: Int
53+chunkSize = 1024 -- FIXME
54+
55+fromHandle :: Handle -> Enumerator a
56+fromHandle h iter a = do
57+ eof <- hIsEOF h
58+ if eof
59+ then return $ Right a
60+ else do
61+ bs <- B.hGet h chunkSize
62+ ea' <- iter a bs
63+ case ea' of
64+ Left a' -> return $ Left a'
65+ Right a' -> fromHandle h iter a'
66+
67+fromFile :: FilePath -> Enumerator a
68+fromFile fp iter a0 = withBinaryFile fp ReadMode $ \h -> fromHandle h iter a0
69+
70+fromEitherFile :: Either FilePath (Enumerator a) -> Enumerator a
71+fromEitherFile (Left fp) = fromFile fp
72+fromEitherFile (Right e) = e