on master help sign in
Simpler definition of Source

Thanks to Felipe Lessa for the idea.

commitaab9bc35ef5c4cb8d8c2ec81630a05e44fff3510 authorSnoyman <snoyman@snoytop-karmic.(none)> dateSat 27 Feb 2010, 23:16 (17 years ago) parent480122b
4 files changed+26−31
Network/Wai.hs+6−11 Network/Wai/Enumerator.hs+5−5 Network/Wai/Handler/SimpleServer.hs+5−5 Network/Wai/Source.hs+10−10
Network/Wai.hs+6−11
@@ -311,19 +311,14 @@ statusMessage Status405 = B8.pack "Method Not Allowed"
311311statusMessage Status500 = B8.pack "Internal Server Error"
312312statusMessage (Status _ m) = m
313313
314−-- | This is a source for 'B.ByteString's. It is composed of two pieces: a
315−-- state variable, and a function to produce the output. The type of the state
316−-- variable is completely unknown to the user; some examples might be an 'Int'
317−-- for the remaining length of the content, or a list of 'B.ByteString's from
318−-- which to generate content.
314+-- | This is a source for 'B.ByteString's. It is a function (wrapped in a
315+-- newtype) that will return Nothing if the data has been completely consumed,
316+-- or return the next 'B.ByteString' from the source along with a new 'Source'
317+-- to continue reading from.
319318--
320−-- The function accepts that state variable as its first argument. If input has
321−-- been fully consumed, it returns 'Nothing'; otherwise, it returns the next
322−-- piece of data and the next state.
323−--
324−-- Be certain not to reuse a state variable! It might work fine with some
319+-- Be certain not to reuse a 'Source'! It might work fine with some
325320-- implementations of 'Source', while causing bugs with others.
326−data Source = forall a. Source a (a -> IO (Maybe (B.ByteString, a)))
321+newtype Source = Source { runSource :: IO (Maybe (B.ByteString, Source)) }
327322
328323-- | An enumerator is a data producer. It takes two arguments: a function to
329324-- enumerate over (the iteratee) and an accumulating parameter. As the
Network/Wai/Enumerator.hs+5−5
@@ -69,7 +69,7 @@ toSource :: Enumerator -> IO Source
6969toSource (Enumerator e) = do
7070 buffer <- newEmptyMVar
7171 _ <- forkIO $ e (helper buffer) () >> putMVar buffer Nothing
72− return $ Source () $ source buffer
72+ return $ source buffer
7373 where
7474 helper :: MVar (Maybe B.ByteString)
7575 -> ()
@@ -78,9 +78,9 @@ toSource (Enumerator e) = do
7878 helper buffer _ bs = do
7979 putMVar buffer $ Just bs
8080 return $ Right ()
81− source :: MVar (Maybe B.ByteString) -> ()
82− -> IO (Maybe (B.ByteString, ()))
83− source mmbs () = do
81+ source :: MVar (Maybe B.ByteString)
82+ -> Source
83+ source mmbs = Source $ do
8484 mbs <- takeMVar mmbs
8585 case mbs of
8686 Nothing -> do
@@ -88,7 +88,7 @@ toSource (Enumerator e) = do
8888 -- again without causing a deadlock.
8989 putMVar mmbs Nothing
9090 return Nothing
91− Just bs -> return $ Just (bs, ())
91+ Just bs -> return $ Just (bs, source mmbs)
9292
9393-- | Read a chunk of data from the given 'Handle' at a time. We use
9494-- 'defaultChunkSize' from the bytestring package to determine the largest
Network/Wai/Handler/SimpleServer.hs+5−5
@@ -128,19 +128,19 @@ parseRequest port lines' handle remoteHost' = do
128128 , serverPort = port
129129 , requestHeaders = heads
130130 , urlScheme = HTTP
131− , requestBody = Source len $ requestBodyHandle handle
131+ , requestBody = requestBodyHandle handle len
132132 , errorHandler = System.IO.hPutStr System.IO.stderr
133133 , remoteHost = B8.pack remoteHost'
134134 }
135135
136−requestBodyHandle :: Handle -> Int -> IO (Maybe (B8.ByteString, Int))
137−requestBodyHandle _ 0 = return Nothing
138−requestBodyHandle h len = do
136+requestBodyHandle :: Handle -> Int -> Source
137+requestBodyHandle _ 0 = Source $ return Nothing
138+requestBodyHandle h len = Source $ do
139139 let maxChunkSize = 1024
140140 bs <- BS.hGet h $ min len maxChunkSize
141141 let newLen = len - BS.length bs
142142 putStrLn $ "reading a chunk of size " ++ show (BS.length bs)
143− return $ Just (bs, newLen)
143+ return $ Just (bs, requestBodyHandle h newLen)
144144
145145parseFirst :: (StringLike s, MonadFailure InvalidRequest m) =>
146146 s
Network/Wai/Source.hs+10−10
@@ -13,25 +13,25 @@ import System.IO.Unsafe (unsafeInterleaveIO)
1313-- 'Enumerator' (which pushes the data to you). There should be no significant
1414-- performance impact from its use, and it uses no unsafe functions.
1515toEnumerator :: Source -> Enumerator
16−toEnumerator (Source b0 source) = Enumerator $ helper b0 where
17− helper b iter a = do
18− next <- source b
16+toEnumerator source0 = Enumerator $ helper source0 where
17+ helper source iter a = do
18+ next <- runSource source
1919 case next of
2020 Nothing -> return $ Right a
21− Just (bs, b') -> do
21+ Just (bs, source') -> do
2222 res <- iter a bs
2323 case res of
2424 Left a' -> return $ Left a'
25− Right a' -> helper b' iter a'
25+ Right a' -> helper source' iter a'
2626
2727-- | Uses lazy I\/O (via 'unsafeInterleaveIO') to provide a lazy interface to
2828-- the given 'Source'. Normal lazy I\/O warnings apply.
2929toLBS :: Source -> IO L.ByteString
30−toLBS (Source b0 source) = L.fromChunks `fmap` helper b0 where
31− helper b = unsafeInterleaveIO $ do
32− next <- source b
30+toLBS source0 = L.fromChunks `fmap` helper source0 where
31+ helper source = unsafeInterleaveIO $ do
32+ next <- runSource source
3333 case next of
3434 Nothing -> return []
35− Just (bs, b') -> do
36− rest <- helper b'
35+ Just (bs, source') -> do
36+ rest <- helper source'
3737 return $ bs : rest