blaze-builder-conduit (empty) → 0.0.0
raw patch · 5 files changed
+239/−0 lines, 5 filesdep +HUnitdep +QuickCheckdep +basesetup-changed
Dependencies added: HUnit, QuickCheck, base, blaze-builder, blaze-builder-conduit, bytestring, conduit, containers, hspec, text, transformers
Files
- Data/Conduit/Blaze.hs +114/−0
- LICENSE +30/−0
- Setup.lhs +7/−0
- blaze-builder-conduit.cabal +44/−0
- test/main.hs +44/−0
+ Data/Conduit/Blaze.hs view
@@ -0,0 +1,114 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE BangPatterns #-}+-- | Convert a stream of blaze-builder @Builder@s into a stream of @ByteString@s.+--+-- Adapted from blaze-builder-enumerator, written by myself and Simon Meier.+--+-- Note that the functions here can work in any monad built on top of @IO@ or+-- @ST@.+module Data.Conduit.Blaze+ (++ -- * Buffers+ Buffer++ -- ** Status information+ , freeSize+ , sliceSize+ , bufferSize++ -- ** Creation and modification+ , allocBuffer+ , reuseBuffer+ , nextSlice++ -- ** Conversion to bytestings+ , unsafeFreezeBuffer+ , unsafeFreezeNonEmptyBuffer++ -- * Buffer allocation strategies+ , BufferAllocStrategy+ , allNewBuffersStrategy+ , reuseBufferStrategy++ -- * Enumeratees from builders to bytestrings+ , builderToByteString+ , unsafeBuilderToByteString+ , builderToByteStringWith++ ) where++import Data.Conduit hiding (SinkResult (Done))+import Control.Monad.Trans.Resource+import Control.Monad.Trans.Class++import qualified Data.ByteString as S++import Blaze.ByteString.Builder.Internal+import Blaze.ByteString.Builder.Internal.Types+import Blaze.ByteString.Builder.Internal.Buffer++-- | Incrementally execute builders and pass on the filled chunks as+-- bytestrings.+builderToByteString :: ResourceUnsafeIO m => Conduit Builder m S.ByteString+builderToByteString =+ builderToByteStringWith (allNewBuffersStrategy defaultBufferSize)++-- | Incrementally execute builders on the given buffer and pass on the filled+-- chunks as bytestrings. Note that, if the given buffer is too small for the+-- execution of a build step, a larger one will be allocated.+--+-- WARNING: This conduit yields bytestrings that are NOT+-- referentially transparent. Their content will be overwritten as soon+-- as control is returned from the inner sink!+unsafeBuilderToByteString :: ResourceUnsafeIO m+ => IO Buffer -- action yielding the inital buffer.+ -> Conduit Builder m S.ByteString+unsafeBuilderToByteString = builderToByteStringWith . reuseBufferStrategy+++-- | A conduit that incrementally executes builders and passes on the+-- filled chunks as bytestrings to an inner sink.+--+-- INV: All bytestrings passed to the inner sink are non-empty.+builderToByteStringWith :: ResourceUnsafeIO m+ => BufferAllocStrategy+ -> Conduit Builder m S.ByteString+builderToByteStringWith (ioBuf0, nextBuf) = conduitState+ ioBuf0+ push+ close+ where+ finalStep !(BufRange pf _) = return $ Done pf ()++ close ioBuf = lift $ unsafeFromIO $ do+ buf <- ioBuf+ return $ maybe [] return $ unsafeFreezeNonEmptyBuffer buf++ push ioBuf x = lift $ unsafeFromIO $ do+ (ioBuf', front) <- go (unBuilder x (buildStep finalStep)) ioBuf id+ return (ioBuf', Producing $ front [])++ go bStep ioBuf front = do+ !buf <- ioBuf+ signal <- (execBuildStep bStep buf)+ case signal of+ Done op' _ -> return (return $ updateEndOfSlice buf op', front)+ BufferFull minSize op' bStep' -> do+ let buf' = updateEndOfSlice buf op'+ {-# INLINE cont #-}+ cont front' = do+ -- sequencing the computation of the next buffer+ -- construction here ensures that the reference to the+ -- foreign pointer `fp` is lost as soon as possible.+ ioBuf' <- nextBuf minSize buf'+ go bStep' ioBuf' front'+ case unsafeFreezeNonEmptyBuffer buf' of+ Nothing -> cont front+ Just bs -> cont (front . (bs:))+ InsertByteString op' bs bStep' -> do+ let buf' = updateEndOfSlice buf op'+ bsk = maybe id (:) $ unsafeFreezeNonEmptyBuffer buf'+ front' = front . bsk . (bs:)+ ioBuf' <- nextBuf 1 buf'+ go bStep' ioBuf' front'
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c)2011, Michael Snoyman++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Michael Snoyman nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,7 @@+#!/usr/bin/env runhaskell++> module Main where+> import Distribution.Simple++> main :: IO ()+> main = defaultMain
+ blaze-builder-conduit.cabal view
@@ -0,0 +1,44 @@+Name: blaze-builder-conduit+Version: 0.0.0+Synopsis: Convert streams of builders to streams of bytestrings.+Description: Convert streams of builders to streams of bytestrings.+License: BSD3+License-file: LICENSE+Author: Michael Snoyman+Maintainer: michael@snoyman.com+Category: Data, Conduit+Build-type: Simple+Cabal-version: >=1.8+Homepage: http://github.com/snoyberg/conduit+extra-source-files: test/main.hs++Library+ Exposed-modules: Data.Conduit.Blaze+ Build-depends: base >= 4 && < 5+ , containers+ , transformers >= 0.2.2 && < 0.3+ , bytestring >= 0.9+ , text >= 0.11+ , blaze-builder >= 0.2.1.4 && < 0.4+ , conduit >= 0.0 && < 0.1+ ghc-options: -Wall++test-suite test+ hs-source-dirs: test+ main-is: main.hs+ type: exitcode-stdio-1.0+ cpp-options: -DTEST+ build-depends: conduit+ , base+ , hspec+ , HUnit+ , QuickCheck+ , bytestring+ , blaze-builder+ , blaze-builder-conduit+ , transformers+ ghc-options: -Wall++source-repository head+ type: git+ location: git://github.com/snoyberg/conduit.git
+ test/main.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE CPP #-}+import Test.Hspec.Monadic+import Test.Hspec.HUnit ()+import Test.Hspec.QuickCheck (prop)+import Test.HUnit++import qualified Data.Conduit as C+import qualified Data.Conduit.List as CL+import Data.ByteString.Char8 ()+import Data.Conduit.Blaze (builderToByteString)+import Data.Conduit (runResourceT)+import Control.Monad.ST (runST)+import Data.Monoid+import qualified Data.ByteString as S+import Blaze.ByteString.Builder (fromByteString, toLazyByteString, insertLazyByteString)+import qualified Data.ByteString.Lazy as L+import Data.ByteString.Lazy.Char8 ()+import Control.Monad.IO.Class (liftIO)++main :: IO ()+main = hspecX $ do+ describe "blaze" $ do+ prop "idempotent to toLazyByteString" $ \bss' -> runST $ runResourceT $ do+ let bss = map S.pack bss'+ let builders = map fromByteString bss+ let lbs = toLazyByteString $ mconcat builders+ let src = mconcat $ map (CL.sourceList . return) builders+ outBss <- src C.$= builderToByteString C.$$ CL.consume+ return $ lbs == L.fromChunks outBss++ it "works for large input" $ runResourceT $ do+ let builders = replicate 10000 (fromByteString "hello world!")+ let lbs = toLazyByteString $ mconcat builders+ let src = mconcat $ map (CL.sourceList . return) builders+ outBss <- src C.$= builderToByteString C.$$ CL.consume :: C.ResourceT IO [S.ByteString]+ liftIO $ lbs @=? L.fromChunks outBss++ it "works for lazy bytestring insertion" $ runResourceT $ do+ let builders = replicate 10000 (insertLazyByteString "hello world!")+ let lbs = toLazyByteString $ mconcat builders+ let src = mconcat $ map (CL.sourceList . return) builders+ outBss <- src C.$= builderToByteString C.$$ CL.consume :: C.ResourceT IO [S.ByteString]+ liftIO $ lbs @=? L.fromChunks outBss