module Network.Wai.Source
    (
    -- * Conversions
      toEnumerator
    , toLBS
    , fromLBS
    ) where

import Network.Wai
import qualified Data.ByteString.Lazy as L
import System.IO.Unsafe (unsafeInterleaveIO)

-- | This function safely converts a 'Source' (where you pull data) to an
-- 'Enumerator' (which pushes the data to you). There should be no significant
-- performance impact from its use, and it uses no unsafe functions.
toEnumerator :: Source -> Enumerator
toEnumerator source0 = Enumerator $ helper source0 where
    helper source iter a = do
        next <- runSource source
        case next of
            Nothing -> return $ Right a
            Just (bs, source') -> do
                res <- iter a bs
                case res of
                    Left a' -> return $ Left a'
                    Right a' -> helper source' iter a'

-- | Uses lazy I\/O (via 'unsafeInterleaveIO') to provide a lazy interface to
-- the given 'Source'. Normal lazy I\/O warnings apply.
toLBS :: Source -> IO L.ByteString
toLBS source0 = L.fromChunks `fmap` helper source0 where
    helper source = unsafeInterleaveIO $ do
        next <- runSource source
        case next of
            Nothing -> return []
            Just (bs, source') -> do
                rest <- helper source'
                return $ bs : rest

-- | Convert a lazy bytestring to a 'Source'. This operation does not request lazy I\/O.
fromLBS :: L.ByteString -> Source
fromLBS =
    go . L.toChunks
  where
    go [] = Source $ return Nothing
    go (x:xs) = Source $ return $ Just (x, go xs)