{-# LANGUAGE Unsafe #-}{-# LANGUAGE TypeFamilies #-}{-# LANGUAGE NoMonoLocalBinds #-}{-# OPTIONS_HADDOCK not-home #-}-- | Copyright : (c) 2010 - 2011 Simon Meier-- License : BSD3-style (see LICENSE)---- Maintainer : Simon Meier <iridcode@gmail.com>-- Stability : unstable, private-- Portability : GHC---- *Warning:* this module is internal. If you find that you need it then please-- contact the maintainers and explain what you are trying to do and discuss-- what you would need in the public API. It is important that you do this as-- the module may not be exposed at all in future releases.---- Core types and functions for the 'Builder' monoid and its generalization,-- the 'Put' monad.---- The design of the 'Builder' monoid is optimized such that---- 1. buffers of arbitrary size can be filled as efficiently as possible and---- 2. sequencing of 'Builder's is as cheap as possible.---- We achieve (1) by completely handing over control over writing to the buffer-- to the 'BuildStep' implementing the 'Builder'. This 'BuildStep' is just told-- the start and the end of the buffer (represented as a 'BufferRange'). Then,-- the 'BuildStep' can write to as big a prefix of this 'BufferRange' in any-- way it desires. If the 'BuildStep' is done, the 'BufferRange' is full, or a-- long sequence of bytes should be inserted directly, then the 'BuildStep'-- signals this to its caller using a 'BuildSignal'.---- We achieve (2) by requiring that every 'Builder' is implemented by a-- 'BuildStep' that takes a continuation 'BuildStep', which it calls with the-- updated 'BufferRange' after it is done. Therefore, only two pointers have-- to be passed in a function call to implement concatenation of 'Builder's.-- Moreover, many 'Builder's are completely inlined, which enables the compiler-- to sequence them without a function call and with no boxing at all.---- This design gives the implementation of a 'Builder' full access to the 'IO'-- monad. Therefore, utmost care has to be taken to not overwrite anything-- outside the given 'BufferRange's. Moreover, further care has to be taken to-- ensure that 'Builder's and 'Put's are referentially transparent. See the-- comments of the 'builder' and 'put' functions for further information.-- Note that there are /no safety belts/ at all, when implementing a 'Builder'-- using an 'IO' action: you are writing code that might enable the next-- buffer-overflow attack on a Haskell server!--moduleData.ByteString.Builder.Internal(-- * Buffer managementBuffer (..),BufferRange (..),newBuffer ,bufferSize ,byteStringFromBuffer ,ChunkIOStream (..),buildStepToCIOS ,ciosUnitToLazyByteString ,ciosToLazyByteString -- * Build signals and steps,BuildSignal ,BuildStep ,finalBuildStep ,done ,bufferFull ,insertChunk ,fillWithBuildStep -- * The Builder monoid,Builder ,builder ,runBuilder ,runBuilderWith -- ** Primitive combinators,empty ,append ,flush ,ensureFree -- , sizedChunksInsert,byteStringCopy ,byteStringInsert ,byteStringThreshold ,lazyByteStringCopy ,lazyByteStringInsert ,lazyByteStringThreshold ,shortByteString ,maximalCopySize ,byteString ,lazyByteString -- ** Execution,toLazyByteString ,toLazyByteStringWith ,AllocationStrategy ,safeStrategy ,untrimmedStrategy ,customStrategy ,L.smallChunkSize ,L.defaultChunkSize ,L.chunkOverhead -- * The Put monad,Put ,put ,runPut -- ** Execution,putToLazyByteString ,putToLazyByteStringWith ,hPut -- ** Conversion to and from Builders,putBuilder ,fromPut -- -- ** Lifting IO actions-- , putLiftIO)whereimportControl.Arrow(second)importControl.DeepSeq(NFData(..))importGHC.Exts(IsList(..))importData.Semigroup(Semigroup(..))importData.List.NonEmpty(NonEmpty(..))importqualifiedData.ByteString asSimportqualifiedData.ByteString.Unsafe asSimportqualifiedData.ByteString.Internal.Type asSimportqualifiedData.ByteString.Lazy.Internal asLimportqualifiedData.ByteString.Short.Internal asShimportqualifiedGHC.IO.BufferasIO(Buffer(..),newByteBuffer)importGHC.IO.Handle.Internals(wantWritableHandle,flushWriteBuffer)importGHC.IO.Handle.Types(Handle__,haByteBuffer,haBufferMode)importSystem.IO(hFlush,BufferMode(..),Handle)importData.IORefimportForeignimportForeign.ForeignPtr.Unsafe(unsafeForeignPtrToPtr)importSystem.IO.Unsafe(unsafeDupablePerformIO)-------------------------------------------------------------------------------- Buffers-------------------------------------------------------------------------------- | A range of bytes in a buffer represented by the pointer to the first byte-- of the range and the pointer to the first byte /after/ the range.dataBufferRange =BufferRange {-# UNPACK#-}!(PtrWord8)-- First byte of range{-# UNPACK#-}!(PtrWord8)-- First byte /after/ range-- | @since 0.12.2.0instanceNFDataBufferRange wherernf :: BufferRange -> ()
rnf !BufferRange
_=()-- | A 'Buffer' together with the 'BufferRange' of free bytes. The filled-- space starts at offset 0 and ends at the first free byte.dataBuffer =Buffer {-# UNPACK#-}!(ForeignPtrWord8){-# UNPACK#-}!BufferRange -- | Like the @NFData@ instance for @StrictByteString@,-- this does not force the @ForeignPtrContents@ field-- of the underlying @ForeignPtr@.---- @since 0.12.2.0instanceNFDataBuffer wherernf :: Buffer -> ()
rnf!Buffer
_=()-- | Combined size of the filled and free space in the buffer.{-# INLINEbufferSize #-}bufferSize ::Buffer ->IntbufferSize :: Buffer -> Int
bufferSize (Buffer ForeignPtr Word8
fpbuf (BufferRange Ptr Word8
_Ptr Word8
ope ))=Ptr Word8
ope Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr`ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtrForeignPtr Word8
fpbuf -- | Allocate a new buffer of the given size.{-# INLINEnewBuffer #-}newBuffer ::Int->IOBuffer newBuffer :: Int -> IO Buffer
newBuffer Int
size =doForeignPtr Word8
fpbuf <-Int -> IO (ForeignPtr Word8)
forall a. Int -> IO (ForeignPtr a)
S.mallocByteString Int
size letpbuf :: Ptr Word8
pbuf =ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtrForeignPtr Word8
fpbuf Buffer -> IO Buffer
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(Buffer -> IO Buffer) -> Buffer -> IO Buffer
forall a b. (a -> b) -> a -> b
$!ForeignPtr Word8 -> BufferRange -> Buffer
Buffer ForeignPtr Word8
fpbuf (Ptr Word8 -> Ptr Word8 -> BufferRange
BufferRange Ptr Word8
pbuf (Ptr Word8
pbuf Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr`Int
size ))-- | Convert the filled part of a 'Buffer' to a 'S.StrictByteString'.{-# INLINEbyteStringFromBuffer #-}byteStringFromBuffer ::Buffer ->S.StrictByteString byteStringFromBuffer :: Buffer -> StrictByteString
byteStringFromBuffer (Buffer ForeignPtr Word8
fpbuf (BufferRange Ptr Word8
op Ptr Word8
_))=ForeignPtr Word8 -> Int -> StrictByteString
S.BS ForeignPtr Word8
fpbuf (Ptr Word8
op Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr`ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtrForeignPtr Word8
fpbuf )-- | Prepend the filled part of a 'Buffer' to a 'L.LazyByteString'-- trimming it if necessary.{-# INLINEtrimmedChunkFromBuffer #-}trimmedChunkFromBuffer ::AllocationStrategy ->Buffer ->L.LazyByteString ->L.LazyByteString trimmedChunkFromBuffer :: AllocationStrategy -> Buffer -> LazyByteString -> LazyByteString
trimmedChunkFromBuffer (AllocationStrategy Maybe (Buffer, Int) -> IO Buffer
_Int
_Int -> Int -> Bool
trim )Buffer
buf LazyByteString
k |StrictByteString -> Bool
S.null StrictByteString
bs =LazyByteString
k |Int -> Int -> Bool
trim (StrictByteString -> Int
S.length StrictByteString
bs )(Buffer -> Int
bufferSize Buffer
buf )=StrictByteString -> LazyByteString -> LazyByteString
L.Chunk (StrictByteString -> StrictByteString
S.copy StrictByteString
bs )LazyByteString
k |Bool
otherwise=StrictByteString -> LazyByteString -> LazyByteString
L.Chunk StrictByteString
bs LazyByteString
k wherebs :: StrictByteString
bs =Buffer -> StrictByteString
byteStringFromBuffer Buffer
buf -------------------------------------------------------------------------------- Chunked IO Stream-------------------------------------------------------------------------------- | A stream of chunks that are constructed in the 'IO' monad.---- This datatype serves as the common interface for the buffer-by-buffer-- execution of a 'BuildStep' by 'buildStepToCIOS'. Typical users of this-- interface are 'ciosToLazyByteString' or iteratee-style libraries like-- @enumerator@.dataChunkIOStream a =Finished Buffer a -- ^ The partially filled last buffer together with the result.|Yield1 S.StrictByteString (IO(ChunkIOStream a ))-- ^ Yield a /non-empty/ 'S.StrictByteString'.-- | A smart constructor for yielding one chunk that ignores the chunk if-- it is empty.{-# INLINEyield1 #-}yield1 ::S.StrictByteString ->IO(ChunkIOStream a )->IO(ChunkIOStream a )yield1 :: forall a.
StrictByteString -> IO (ChunkIOStream a) -> IO (ChunkIOStream a)
yield1 StrictByteString
bs IO (ChunkIOStream a)
cios |StrictByteString -> Bool
S.null StrictByteString
bs =IO (ChunkIOStream a)
cios |Bool
otherwise=ChunkIOStream a -> IO (ChunkIOStream a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(ChunkIOStream a -> IO (ChunkIOStream a))
-> ChunkIOStream a -> IO (ChunkIOStream a)
forall a b. (a -> b) -> a -> b
$StrictByteString -> IO (ChunkIOStream a) -> ChunkIOStream a
forall a.
StrictByteString -> IO (ChunkIOStream a) -> ChunkIOStream a
Yield1 StrictByteString
bs IO (ChunkIOStream a)
cios -- | Convert a @'ChunkIOStream' ()@ to a 'L.LazyByteString' using-- 'unsafeDupablePerformIO'.{-# INLINEciosUnitToLazyByteString #-}ciosUnitToLazyByteString ::AllocationStrategy ->L.LazyByteString ->ChunkIOStream ()->L.LazyByteString ciosUnitToLazyByteString :: AllocationStrategy
-> LazyByteString -> ChunkIOStream () -> LazyByteString
ciosUnitToLazyByteString AllocationStrategy
strategy LazyByteString
k =ChunkIOStream () -> LazyByteString
forall {a}. ChunkIOStream a -> LazyByteString
go wherego :: ChunkIOStream a -> LazyByteString
go (Finished Buffer
buf a
_)=AllocationStrategy -> Buffer -> LazyByteString -> LazyByteString
trimmedChunkFromBuffer AllocationStrategy
strategy Buffer
buf LazyByteString
k go (Yield1 StrictByteString
bs IO (ChunkIOStream a)
io )=StrictByteString -> LazyByteString -> LazyByteString
L.Chunk StrictByteString
bs (LazyByteString -> LazyByteString)
-> LazyByteString -> LazyByteString
forall a b. (a -> b) -> a -> b
$IO LazyByteString -> LazyByteString
forall a. IO a -> a
unsafeDupablePerformIO(ChunkIOStream a -> LazyByteString
go (ChunkIOStream a -> LazyByteString)
-> IO (ChunkIOStream a) -> IO LazyByteString
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>IO (ChunkIOStream a)
io )-- | Convert a 'ChunkIOStream' to a lazy tuple of the result and the written-- 'L.LazyByteString' using 'unsafeDupablePerformIO'.{-# INLINEciosToLazyByteString #-}ciosToLazyByteString ::AllocationStrategy ->(a ->(b ,L.LazyByteString ))->ChunkIOStream a ->(b ,L.LazyByteString )ciosToLazyByteString :: forall a b.
AllocationStrategy
-> (a -> (b, LazyByteString))
-> ChunkIOStream a
-> (b, LazyByteString)
ciosToLazyByteString AllocationStrategy
strategy a -> (b, LazyByteString)
k =ChunkIOStream a -> (b, LazyByteString)
go wherego :: ChunkIOStream a -> (b, LazyByteString)
go (Finished Buffer
buf a
x )=(LazyByteString -> LazyByteString)
-> (b, LazyByteString) -> (b, LazyByteString)
forall b c d. (b -> c) -> (d, b) -> (d, c)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second(AllocationStrategy -> Buffer -> LazyByteString -> LazyByteString
trimmedChunkFromBuffer AllocationStrategy
strategy Buffer
buf )((b, LazyByteString) -> (b, LazyByteString))
-> (b, LazyByteString) -> (b, LazyByteString)
forall a b. (a -> b) -> a -> b
$a -> (b, LazyByteString)
k a
x go (Yield1 StrictByteString
bs IO (ChunkIOStream a)
io )=(LazyByteString -> LazyByteString)
-> (b, LazyByteString) -> (b, LazyByteString)
forall b c d. (b -> c) -> (d, b) -> (d, c)
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second(StrictByteString -> LazyByteString -> LazyByteString
L.Chunk StrictByteString
bs )((b, LazyByteString) -> (b, LazyByteString))
-> (b, LazyByteString) -> (b, LazyByteString)
forall a b. (a -> b) -> a -> b
$IO (b, LazyByteString) -> (b, LazyByteString)
forall a. IO a -> a
unsafeDupablePerformIO(ChunkIOStream a -> (b, LazyByteString)
go (ChunkIOStream a -> (b, LazyByteString))
-> IO (ChunkIOStream a) -> IO (b, LazyByteString)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>IO (ChunkIOStream a)
io )-------------------------------------------------------------------------------- Build signals-------------------------------------------------------------------------------- | 'BuildStep's may be called *multiple times* and they must not rise an-- async. exception.typeBuildStep a =BufferRange ->IO(BuildSignal a )-- | 'BuildSignal's abstract signals to the caller of a 'BuildStep'. There are-- three signals: 'done', 'bufferFull', or 'insertChunks signalsdataBuildSignal a =Done {-# UNPACK#-}!(PtrWord8)a |BufferFull {-# UNPACK#-}!Int{-# UNPACK#-}!(PtrWord8)(BuildStep a )|InsertChunk {-# UNPACK#-}!(PtrWord8)S.StrictByteString (BuildStep a )-- | Signal that the current 'BuildStep' is done and has computed a value.{-# INLINEdone #-}done ::PtrWord8-- ^ Next free byte in current 'BufferRange'->a -- ^ Computed value->BuildSignal a done :: forall a. Ptr Word8 -> a -> BuildSignal a
done =Ptr Word8 -> a -> BuildSignal a
forall a. Ptr Word8 -> a -> BuildSignal a
Done -- | Signal that the current buffer is full.{-# INLINEbufferFull #-}bufferFull ::Int-- ^ Minimal size of next 'BufferRange'.->PtrWord8-- ^ Next free byte in current 'BufferRange'.->BuildStep a -- ^ 'BuildStep' to run on the next 'BufferRange'. This 'BuildStep'-- may assume that it is called with a 'BufferRange' of at least the-- required minimal size; i.e., the caller of this 'BuildStep' must-- guarantee this.->BuildSignal a bufferFull :: forall a. Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
bufferFull =Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
forall a. Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
BufferFull -- | Signal that a 'S.StrictByteString' chunk should be inserted directly.{-# INLINEinsertChunk #-}insertChunk ::PtrWord8-- ^ Next free byte in current 'BufferRange'->S.StrictByteString -- ^ Chunk to insert.->BuildStep a -- ^ 'BuildStep' to run on next 'BufferRange'->BuildSignal a insertChunk :: forall a.
Ptr Word8 -> StrictByteString -> BuildStep a -> BuildSignal a
insertChunk =Ptr Word8 -> StrictByteString -> BuildStep a -> BuildSignal a
forall a.
Ptr Word8 -> StrictByteString -> BuildStep a -> BuildSignal a
InsertChunk -- | Fill a 'BufferRange' using a 'BuildStep'.{-# INLINEfillWithBuildStep #-}fillWithBuildStep ::BuildStep a -- ^ Build step to use for filling the 'BufferRange'.->(PtrWord8->a ->IOb )-- ^ Handling the 'done' signal->(PtrWord8->Int->BuildStep a ->IOb )-- ^ Handling the 'bufferFull' signal->(PtrWord8->S.StrictByteString ->BuildStep a ->IOb )-- ^ Handling the 'insertChunk' signal->BufferRange -- ^ Buffer range to fill.->IOb -- ^ Value computed while filling this 'BufferRange'.fillWithBuildStep :: forall a b.
BuildStep a
-> (Ptr Word8 -> a -> IO b)
-> (Ptr Word8 -> Int -> BuildStep a -> IO b)
-> (Ptr Word8 -> StrictByteString -> BuildStep a -> IO b)
-> BufferRange
-> IO b
fillWithBuildStep BuildStep a
step Ptr Word8 -> a -> IO b
fDone Ptr Word8 -> Int -> BuildStep a -> IO b
fFull Ptr Word8 -> StrictByteString -> BuildStep a -> IO b
fChunk !BufferRange
br =doBuildSignal a
signal <-BuildStep a
step BufferRange
br caseBuildSignal a
signal ofDone Ptr Word8
op a
x ->Ptr Word8 -> a -> IO b
fDone Ptr Word8
op a
x BufferFull Int
minSize Ptr Word8
op BuildStep a
nextStep ->Ptr Word8 -> Int -> BuildStep a -> IO b
fFull Ptr Word8
op Int
minSize BuildStep a
nextStep InsertChunk Ptr Word8
op StrictByteString
bs BuildStep a
nextStep ->Ptr Word8 -> StrictByteString -> BuildStep a -> IO b
fChunk Ptr Word8
op StrictByteString
bs BuildStep a
nextStep -------------------------------------------------------------------------------- The 'Builder' monoid-------------------------------------------------------------------------------- | 'Builder's denote sequences of bytes.-- They are 'Monoid's where-- 'mempty' is the zero-length sequence and-- 'mappend' is concatenation, which runs in /O(1)/.newtypeBuilder =Builder (forallr .BuildStep r ->BuildStep r )-- | Construct a 'Builder'. In contrast to 'BuildStep's, 'Builder's are-- referentially transparent.{-# INLINEbuilder #-}builder ::(forallr .BuildStep r ->BuildStep r )-- ^ A function that fills a 'BufferRange', calls the continuation with-- the updated 'BufferRange' once its done, and signals its caller how-- to proceed using 'done', 'bufferFull', or 'insertChunk'.---- This function must be referentially transparent; i.e., calling it-- multiple times with equally sized 'BufferRange's must result in the-- same sequence of bytes being written. If you need mutable state,-- then you must allocate it anew upon each call of this function.-- Moreover, this function must call the continuation once its done.-- Otherwise, concatenation of 'Builder's does not work. Finally, this-- function must write to all bytes that it claims it has written.-- Otherwise, the resulting 'Builder' is not guaranteed to be-- referentially transparent and sensitive data might leak.->Builder builder :: (forall r. BuildStep r -> BuildStep r) -> Builder
builder =(forall r. BuildStep r -> BuildStep r) -> Builder
Builder -- | The final build step that returns the 'done' signal.finalBuildStep ::BuildStep ()finalBuildStep :: BuildStep ()
finalBuildStep (BufferRange Ptr Word8
op Ptr Word8
_)=BuildSignal () -> IO (BuildSignal ())
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(BuildSignal () -> IO (BuildSignal ()))
-> BuildSignal () -> IO (BuildSignal ())
forall a b. (a -> b) -> a -> b
$Ptr Word8 -> () -> BuildSignal ()
forall a. Ptr Word8 -> a -> BuildSignal a
Done Ptr Word8
op ()-- | Run a 'Builder' with the 'finalBuildStep'.{-# INLINErunBuilder #-}runBuilder ::Builder -- ^ 'Builder' to run->BuildStep ()-- ^ 'BuildStep' that writes the byte stream of this-- 'Builder' and signals 'done' upon completion.runBuilder :: Builder -> BuildStep ()
runBuilder Builder
b =Builder -> BuildStep () -> BuildStep ()
forall a. Builder -> BuildStep a -> BuildStep a
runBuilderWith Builder
b BuildStep ()
finalBuildStep -- | Run a 'Builder'.{-# INLINErunBuilderWith #-}runBuilderWith ::Builder -- ^ 'Builder' to run->BuildStep a -- ^ Continuation 'BuildStep'->BuildStep a runBuilderWith :: forall a. Builder -> BuildStep a -> BuildStep a
runBuilderWith (Builder forall r. BuildStep r -> BuildStep r
b )=BuildStep a -> BuildStep a
forall r. BuildStep r -> BuildStep r
b -- | The 'Builder' denoting a zero-length sequence of bytes. This function is-- only exported for use in rewriting rules. Use 'mempty' otherwise.{-# INLINE[1]empty #-}empty ::Builder empty :: Builder
empty =(forall r. BuildStep r -> BuildStep r) -> Builder
Builder (\BuildStep r
k BufferRange
br ->BuildStep r
k BufferRange
br )-- This eta expansion (hopefully) allows GHC to worker-wrapper the-- 'BufferRange' in the 'empty' base case of loops (since-- worker-wrapper requires (TODO: verify this) that all paths match-- against the wrapped argument.---- Do not use ($), which has arity 1 since base-4.19.-- See also https://gitlab.haskell.org/ghc/ghc/-/issues/23822-- | Concatenate two 'Builder's. This function is only exported for use in rewriting-- rules. Use 'mappend' otherwise.{-# INLINE[1]append #-}append ::Builder ->Builder ->Builder append :: Builder -> Builder -> Builder
append (Builder forall r. BuildStep r -> BuildStep r
b1 )(Builder forall r. BuildStep r -> BuildStep r
b2 )=(forall r. BuildStep r -> BuildStep r) -> Builder
Builder ((forall r. BuildStep r -> BuildStep r) -> Builder)
-> (forall r. BuildStep r -> BuildStep r) -> Builder
forall a b. (a -> b) -> a -> b
$BuildStep r -> BuildStep r
forall r. BuildStep r -> BuildStep r
b1 (BuildStep r -> BuildStep r)
-> (BuildStep r -> BuildStep r) -> BuildStep r -> BuildStep r
forall b c a. (b -> c) -> (a -> b) -> a -> c
.BuildStep r -> BuildStep r
forall r. BuildStep r -> BuildStep r
b2 stimesBuilder ::Integralt =>t ->Builder ->Builder {-# INLINABLEstimesBuilder #-}stimesBuilder :: forall t. Integral t => t -> Builder -> Builder
stimesBuilder t
n Builder
b |t
n t -> t -> Bool
forall a. Ord a => a -> a -> Bool
>=t
0=t -> Builder
forall {t}. (Eq t, Num t) => t -> Builder
go t
n |Bool
otherwise=Builder
stimesNegativeErr wherego :: t -> Builder
go t
0=Builder
empty go t
k =Builder
b Builder -> Builder -> Builder
`append` t -> Builder
go (t
k t -> t -> t
forall a. Num a => a -> a -> a
-t
1)stimesNegativeErr ::Builder -- See Note [Float error calls out of INLINABLE things]-- in Data.ByteString.Internal.TypestimesNegativeErr :: Builder
stimesNegativeErr =[Char] -> Builder
forall a. [Char] -> a
errorWithoutStackTrace[Char]
"stimes @Builder: non-negative multiplier expected"instanceSemigroupBuilder where{-# INLINE(<>)#-}<> :: Builder -> Builder -> Builder
(<>)=Builder -> Builder -> Builder
append sconcat :: NonEmpty Builder -> Builder
sconcat (Builder
b :|[Builder]
bs )=Builder
b Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>(Builder -> Builder -> Builder) -> Builder -> [Builder] -> Builder
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldrBuilder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
mappendBuilder
forall a. Monoid a => a
mempty[Builder]
bs {-# INLINEstimes#-}stimes :: forall t. Integral t => t -> Builder -> Builder
stimes=b -> Builder -> Builder
forall t. Integral t => t -> Builder -> Builder
stimesBuilder instanceMonoidBuilder where{-# INLINEmempty#-}mempty :: Builder
mempty=Builder
empty {-# INLINEmappend#-}mappend :: Builder -> Builder -> Builder
mappend=Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
(<>){-# INLINEmconcat#-}mconcat :: [Builder] -> Builder
mconcat=(Builder -> Builder -> Builder) -> Builder -> [Builder] -> Builder
forall a b. (a -> b -> b) -> b -> [a] -> b
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldrBuilder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
mappendBuilder
forall a. Monoid a => a
mempty-- | For long or infinite lists use 'fromList' because it uses 'LazyByteString' otherwise use 'fromListN' which uses 'StrictByteString'.instanceIsListBuilder wheretypeItemBuilder =Word8fromList :: [Item Builder] -> Builder
fromList=LazyByteString -> Builder
lazyByteString (LazyByteString -> Builder)
-> ([Word8] -> LazyByteString) -> [Word8] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
.[Word8] -> LazyByteString
[Item LazyByteString] -> LazyByteString
forall l. IsList l => [Item l] -> l
fromListfromListN :: Int -> [Item Builder] -> Builder
fromListNInt
n =StrictByteString -> Builder
byteString (StrictByteString -> Builder)
-> ([Word8] -> StrictByteString) -> [Word8] -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Int -> [Item StrictByteString] -> StrictByteString
forall l. IsList l => Int -> [Item l] -> l
fromListNInt
n toList :: Builder -> [Item Builder]
toList=LazyByteString -> [Word8]
LazyByteString -> [Item LazyByteString]
forall l. IsList l => l -> [Item l]
toList(LazyByteString -> [Word8])
-> (Builder -> LazyByteString) -> Builder -> [Word8]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.Builder -> LazyByteString
toLazyByteString -- | Flush the current buffer. This introduces a chunk boundary.{-# INLINEflush #-}flush ::Builder flush :: Builder
flush =(forall r. BuildStep r -> BuildStep r) -> Builder
builder BuildStep r -> BuildStep r
forall r. BuildStep r -> BuildStep r
forall {m :: * -> *} {a}.
Monad m =>
BuildStep a -> BufferRange -> m (BuildSignal a)
step wherestep :: BuildStep a -> BufferRange -> m (BuildSignal a)
step BuildStep a
k (BufferRange Ptr Word8
op Ptr Word8
_)=BuildSignal a -> m (BuildSignal a)
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return(BuildSignal a -> m (BuildSignal a))
-> BuildSignal a -> m (BuildSignal a)
forall a b. (a -> b) -> a -> b
$Ptr Word8 -> StrictByteString -> BuildStep a -> BuildSignal a
forall a.
Ptr Word8 -> StrictByteString -> BuildStep a -> BuildSignal a
insertChunk Ptr Word8
op StrictByteString
S.empty BuildStep a
k -------------------------------------------------------------------------------- Put-------------------------------------------------------------------------------- | A 'Put' action denotes a computation of a value that writes a stream of-- bytes as a side-effect. 'Put's are strict in their side-effect; i.e., the-- stream of bytes will always be written before the computed value is-- returned.---- 'Put's are a generalization of 'Builder's. The typical use case is the-- implementation of an encoding that might fail (e.g., an interface to the-- <https://hackage.haskell.org/package/zlib zlib>-- compression library or the conversion from Base64 encoded data to-- 8-bit data). For a 'Builder', the only way to handle and report such a-- failure is ignore it or call 'error'. In contrast, 'Put' actions are-- expressive enough to allow reporting and handling such a failure in a pure-- fashion.---- @'Put' ()@ actions are isomorphic to 'Builder's. The functions 'putBuilder'-- and 'fromPut' convert between these two types. Where possible, you should-- use 'Builder's, as sequencing them is slightly cheaper than sequencing-- 'Put's because they do not carry around a computed value.newtypePut a =Put {forall a. Put a -> forall r. (a -> BuildStep r) -> BuildStep r
unPut ::forallr .(a ->BuildStep r )->BuildStep r }-- | Construct a 'Put' action. In contrast to 'BuildStep's, 'Put's are-- referentially transparent in the sense that sequencing the same 'Put'-- multiple times yields every time the same value with the same side-effect.{-# INLINEput #-}put ::(forallr .(a ->BuildStep r )->BuildStep r )-- ^ A function that fills a 'BufferRange', calls the continuation with-- the updated 'BufferRange' and its computed value once its done, and-- signals its caller how to proceed using 'done', 'bufferFull', or-- 'insertChunk' signals.---- This function must be referentially transparent; i.e., calling it-- multiple times with equally sized 'BufferRange's must result in the-- same sequence of bytes being written and the same value being-- computed. If you need mutable state, then you must allocate it anew-- upon each call of this function. Moreover, this function must call-- the continuation once its done. Otherwise, monadic sequencing of-- 'Put's does not work. Finally, this function must write to all bytes-- that it claims it has written. Otherwise, the resulting 'Put' is-- not guaranteed to be referentially transparent and sensitive data-- might leak.->Put a put :: forall a. (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
put =(forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
forall a. (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
Put -- | Run a 'Put'.{-# INLINErunPut #-}runPut ::Put a -- ^ Put to run->BuildStep a -- ^ 'BuildStep' that first writes the byte stream of-- this 'Put' and then yields the computed value using-- the 'done' signal.runPut :: forall a. Put a -> BuildStep a
runPut (Put forall r. (a -> BuildStep r) -> BuildStep r
p )=(a -> BuildStep a) -> BuildStep a
forall r. (a -> BuildStep r) -> BuildStep r
p ((a -> BuildStep a) -> BuildStep a)
-> (a -> BuildStep a) -> BuildStep a
forall a b. (a -> b) -> a -> b
$\a
x (BufferRange Ptr Word8
op Ptr Word8
_)->BuildSignal a -> IO (BuildSignal a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(BuildSignal a -> IO (BuildSignal a))
-> BuildSignal a -> IO (BuildSignal a)
forall a b. (a -> b) -> a -> b
$Ptr Word8 -> a -> BuildSignal a
forall a. Ptr Word8 -> a -> BuildSignal a
Done Ptr Word8
op a
x instanceFunctorPut wherefmap :: forall a b. (a -> b) -> Put a -> Put b
fmapa -> b
f Put a
p =(forall r. (b -> BuildStep r) -> BuildStep r) -> Put b
forall a. (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
Put ((forall r. (b -> BuildStep r) -> BuildStep r) -> Put b)
-> (forall r. (b -> BuildStep r) -> BuildStep r) -> Put b
forall a b. (a -> b) -> a -> b
$\b -> BuildStep r
k ->Put a -> forall r. (a -> BuildStep r) -> BuildStep r
forall a. Put a -> forall r. (a -> BuildStep r) -> BuildStep r
unPut Put a
p (b -> BuildStep r
k (b -> BuildStep r) -> (a -> b) -> a -> BuildStep r
forall b c a. (b -> c) -> (a -> b) -> a -> c
.a -> b
f ){-# INLINEfmap#-}-- | Synonym for '<*' from 'Applicative'; used in rewriting rules.{-# INLINE[1]ap_l #-}ap_l ::Put a ->Put b ->Put a ap_l :: forall a b. Put a -> Put b -> Put a
ap_l (Put forall r. (a -> BuildStep r) -> BuildStep r
a )(Put forall r. (b -> BuildStep r) -> BuildStep r
b )=(forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
forall a. (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
Put ((forall r. (a -> BuildStep r) -> BuildStep r) -> Put a)
-> (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
forall a b. (a -> b) -> a -> b
$\a -> BuildStep r
k ->(a -> BuildStep r) -> BuildStep r
forall r. (a -> BuildStep r) -> BuildStep r
a (\a
a' ->(b -> BuildStep r) -> BuildStep r
forall r. (b -> BuildStep r) -> BuildStep r
b (\b
_->a -> BuildStep r
k a
a' ))-- | Synonym for '*>' from 'Applicative' and '>>' from 'Monad'; used in-- rewriting rules.{-# INLINE[1]ap_r #-}ap_r ::Put a ->Put b ->Put b ap_r :: forall a b. Put a -> Put b -> Put b
ap_r (Put forall r. (a -> BuildStep r) -> BuildStep r
a )(Put forall r. (b -> BuildStep r) -> BuildStep r
b )=(forall r. (b -> BuildStep r) -> BuildStep r) -> Put b
forall a. (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
Put ((forall r. (b -> BuildStep r) -> BuildStep r) -> Put b)
-> (forall r. (b -> BuildStep r) -> BuildStep r) -> Put b
forall a b. (a -> b) -> a -> b
$\b -> BuildStep r
k ->(a -> BuildStep r) -> BuildStep r
forall r. (a -> BuildStep r) -> BuildStep r
a (\a
_->(b -> BuildStep r) -> BuildStep r
forall r. (b -> BuildStep r) -> BuildStep r
b b -> BuildStep r
k )instanceApplicativePut where{-# INLINEpure#-}pure :: forall a. a -> Put a
purea
x =(forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
forall a. (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
Put ((forall r. (a -> BuildStep r) -> BuildStep r) -> Put a)
-> (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
forall a b. (a -> b) -> a -> b
$\a -> BuildStep r
k ->a -> BuildStep r
k a
x {-# INLINE(<*>)#-}Put forall r. ((a -> b) -> BuildStep r) -> BuildStep r
f <*> :: forall a b. Put (a -> b) -> Put a -> Put b
<*>Put forall r. (a -> BuildStep r) -> BuildStep r
a =(forall r. (b -> BuildStep r) -> BuildStep r) -> Put b
forall a. (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
Put ((forall r. (b -> BuildStep r) -> BuildStep r) -> Put b)
-> (forall r. (b -> BuildStep r) -> BuildStep r) -> Put b
forall a b. (a -> b) -> a -> b
$\b -> BuildStep r
k ->((a -> b) -> BuildStep r) -> BuildStep r
forall r. ((a -> b) -> BuildStep r) -> BuildStep r
f (\a -> b
f' ->(a -> BuildStep r) -> BuildStep r
forall r. (a -> BuildStep r) -> BuildStep r
a (b -> BuildStep r
k (b -> BuildStep r) -> (a -> b) -> a -> BuildStep r
forall b c a. (b -> c) -> (a -> b) -> a -> c
.a -> b
f' )){-# INLINE(<*)#-}<* :: forall a b. Put a -> Put b -> Put a
(<*)=Put a -> Put b -> Put a
forall a b. Put a -> Put b -> Put a
ap_l {-# INLINE(*>)#-}*> :: forall a b. Put a -> Put b -> Put b
(*>)=Put a -> Put b -> Put b
forall a b. Put a -> Put b -> Put b
ap_r instanceMonadPut where{-# INLINEreturn#-}return :: forall a. a -> Put a
return=a -> Put a
forall a. a -> Put a
forall (f :: * -> *) a. Applicative f => a -> f a
pure{-# INLINE(>>=)#-}Put forall r. (a -> BuildStep r) -> BuildStep r
m >>= :: forall a b. Put a -> (a -> Put b) -> Put b
>>=a -> Put b
f =(forall r. (b -> BuildStep r) -> BuildStep r) -> Put b
forall a. (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
Put ((forall r. (b -> BuildStep r) -> BuildStep r) -> Put b)
-> (forall r. (b -> BuildStep r) -> BuildStep r) -> Put b
forall a b. (a -> b) -> a -> b
$\b -> BuildStep r
k ->(a -> BuildStep r) -> BuildStep r
forall r. (a -> BuildStep r) -> BuildStep r
m (\a
m' ->Put b -> forall r. (b -> BuildStep r) -> BuildStep r
forall a. Put a -> forall r. (a -> BuildStep r) -> BuildStep r
unPut (a -> Put b
f a
m' )b -> BuildStep r
k ){-# INLINE(>>)#-}>> :: forall a b. Put a -> Put b -> Put b
(>>)=Put a -> Put b -> Put b
forall a b. Put a -> Put b -> Put b
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
(*>)-- Conversion between Put and Builder--------------------------------------- | Run a 'Builder' as a side-effect of a @'Put' ()@ action.{-# INLINE[1]putBuilder #-}putBuilder ::Builder ->Put ()putBuilder :: Builder -> Put ()
putBuilder (Builder forall r. BuildStep r -> BuildStep r
b )=(forall r. (() -> BuildStep r) -> BuildStep r) -> Put ()
forall a. (forall r. (a -> BuildStep r) -> BuildStep r) -> Put a
Put ((forall r. (() -> BuildStep r) -> BuildStep r) -> Put ())
-> (forall r. (() -> BuildStep r) -> BuildStep r) -> Put ()
forall a b. (a -> b) -> a -> b
$\() -> BuildStep r
k ->BuildStep r -> BuildStep r
forall r. BuildStep r -> BuildStep r
b (() -> BuildStep r
k ())-- | Convert a @'Put' ()@ action to a 'Builder'.{-# INLINEfromPut #-}fromPut ::Put ()->Builder fromPut :: Put () -> Builder
fromPut (Put forall r. (() -> BuildStep r) -> BuildStep r
p )=(forall r. BuildStep r -> BuildStep r) -> Builder
Builder ((forall r. BuildStep r -> BuildStep r) -> Builder)
-> (forall r. BuildStep r -> BuildStep r) -> Builder
forall a b. (a -> b) -> a -> b
$\BuildStep r
k ->(() -> BuildStep r) -> BuildStep r
forall r. (() -> BuildStep r) -> BuildStep r
p (BuildStep r -> () -> BuildStep r
forall a b. a -> b -> a
constBuildStep r
k )-- We rewrite consecutive uses of 'putBuilder' such that the append of the-- involved 'Builder's is used. This can significantly improve performance,-- when the bound-checks of the concatenated builders are fused.-- ap_l rules{-# RULES"ap_l/putBuilder"forallb1 b2 .ap_l (putBuilder b1 )(putBuilder b2 )=putBuilder (append b1 b2 )"ap_l/putBuilder/assoc_r"forallb1 b2 (p ::Put a ).ap_l (putBuilder b1 )(ap_l (putBuilder b2 )p )=ap_l (putBuilder (append b1 b2 ))p "ap_l/putBuilder/assoc_l"forall(p ::Put a )b1 b2 .ap_l (ap_l p (putBuilder b1 ))(putBuilder b2 )=ap_l p (putBuilder (append b1 b2 ))#-}-- ap_r rules{-# RULES"ap_r/putBuilder"forallb1 b2 .ap_r (putBuilder b1 )(putBuilder b2 )=putBuilder (append b1 b2 )"ap_r/putBuilder/assoc_r"forallb1 b2 (p ::Put a ).ap_r (putBuilder b1 )(ap_r (putBuilder b2 )p )=ap_r (putBuilder (append b1 b2 ))p "ap_r/putBuilder/assoc_l"forall(p ::Put a )b1 b2 .ap_r (ap_r p (putBuilder b1 ))(putBuilder b2 )=ap_r p (putBuilder (append b1 b2 ))#-}-- combined ap_l/ap_r rules{-# RULES"ap_l/ap_r/putBuilder/assoc_r"forallb1 b2 (p ::Put a ).ap_l (putBuilder b1 )(ap_r (putBuilder b2 )p )=ap_l (putBuilder (append b1 b2 ))p "ap_r/ap_l/putBuilder/assoc_r"forallb1 b2 (p ::Put a ).ap_r (putBuilder b1 )(ap_l (putBuilder b2 )p )=ap_l (putBuilder (append b1 b2 ))p "ap_l/ap_r/putBuilder/assoc_l"forall(p ::Put a )b1 b2 .ap_l (ap_r p (putBuilder b1 ))(putBuilder b2 )=ap_r p (putBuilder (append b1 b2 ))"ap_r/ap_l/putBuilder/assoc_l"forall(p ::Put a )b1 b2 .ap_r (ap_l p (putBuilder b1 ))(putBuilder b2 )=ap_r p (putBuilder (append b1 b2 ))#-}-- Lifting IO actions---------------------{-
-- | Lift an 'IO' action to a 'Put' action.
{-# INLINE putLiftIO #-}
putLiftIO :: IO a -> Put a
putLiftIO io = put $ \k br -> io >>= (`k` br)
-}-------------------------------------------------------------------------------- Executing a Put directly on a buffered Handle-------------------------------------------------------------------------------- | Run a 'Put' action redirecting the produced output to a 'Handle'.---- The output is buffered using the 'Handle's associated buffer. If this-- buffer is too small to execute one step of the 'Put' action, then-- it is replaced with a large enough buffer.hPut ::foralla .Handle->Put a ->IOa hPut :: forall a. Handle -> Put a -> IO a
hPut Handle
h Put a
p =doInt -> BuildStep a -> IO a
fillHandle Int
1(Put a -> BuildStep a
forall a. Put a -> BuildStep a
runPut Put a
p )wherefillHandle ::Int->BuildStep a ->IOa fillHandle :: Int -> BuildStep a -> IO a
fillHandle !Int
minFree BuildStep a
step =doIO a
next <-[Char] -> Handle -> (Handle__ -> IO (IO a)) -> IO (IO a)
forall a. [Char] -> Handle -> (Handle__ -> IO a) -> IO a
wantWritableHandle[Char]
"hPut"Handle
h Handle__ -> IO (IO a)
fillHandle_ IO a
next where-- | We need to return an inner IO action that is executed outside-- the lock taken on the Handle for two reasons:---- 1. GHC.IO.Handle.Internals mentions in "Note [async]" that-- we should never do any side-effecting operations before-- an interruptible operation that may raise an async. exception-- as long as we are inside 'wantWritableHandle' and the like.-- We possibly run the interruptible 'flushWriteBuffer' right at-- the start of 'fillHandle', hence entering it a second time is-- not safe, as it could lead to a 'BuildStep' being run twice.---- FIXME (SM): Adapt this function or at least its documentation,-- as it is OK to run a 'BuildStep' twice. We dropped this-- requirement in favor of being able to use-- 'unsafeDupablePerformIO' and the speed improvement that it-- brings.---- 2. We use the 'S.hPut' function to also write to the handle.-- This function tries to take the same lock taken by-- 'wantWritableHandle'. Therefore, we cannot call 'S.hPut'-- inside 'wantWritableHandle'.--fillHandle_ ::Handle__->IO(IOa )fillHandle_ :: Handle__ -> IO (IO a)
fillHandle_ Handle__
h_ =doBuffer Word8 -> IO ()
forall {e}. Buffer e -> IO ()
makeSpace (Buffer Word8 -> IO ()) -> IO (Buffer Word8) -> IO ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORefIORef (Buffer Word8)
refBuf Buffer Word8 -> IO (IO a)
fillBuffer (Buffer Word8 -> IO (IO a)) -> IO (Buffer Word8) -> IO (IO a)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORefIORef (Buffer Word8)
refBuf whererefBuf :: IORef (Buffer Word8)
refBuf =Handle__ -> IORef (Buffer Word8)
haByteBufferHandle__
h_ freeSpace :: Buffer e -> Int
freeSpace Buffer e
buf =Buffer e -> Int
forall e. Buffer e -> Int
IO.bufSizeBuffer e
buf Int -> Int -> Int
forall a. Num a => a -> a -> a
-Buffer e -> Int
forall e. Buffer e -> Int
IO.bufRBuffer e
buf makeSpace :: Buffer e -> IO ()
makeSpace Buffer e
buf |Buffer e -> Int
forall e. Buffer e -> Int
IO.bufSizeBuffer e
buf Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<Int
minFree =doHandle__ -> IO ()
flushWriteBufferHandle__
h_ BufferState
s <-Buffer Word8 -> BufferState
forall e. Buffer e -> BufferState
IO.bufState(Buffer Word8 -> BufferState)
-> IO (Buffer Word8) -> IO BufferState
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORefIORef (Buffer Word8)
refBuf Int -> BufferState -> IO (Buffer Word8)
IO.newByteBufferInt
minFree BufferState
s IO (Buffer Word8) -> (Buffer Word8 -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORefIORef (Buffer Word8)
refBuf |Buffer e -> Int
forall e. Buffer e -> Int
freeSpace Buffer e
buf Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<Int
minFree =Handle__ -> IO ()
flushWriteBufferHandle__
h_ |Bool
otherwise=() -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return()fillBuffer :: Buffer Word8 -> IO (IO a)
fillBuffer Buffer Word8
buf |Buffer Word8 -> Int
forall e. Buffer e -> Int
freeSpace Buffer Word8
buf Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<Int
minFree =[Char] -> IO (IO a)
forall a. HasCallStack => [Char] -> a
error([Char] -> IO (IO a)) -> [Char] -> IO (IO a)
forall a b. (a -> b) -> a -> b
$[[Char]] -> [Char]
unlines[[Char]
"Data.ByteString.Builder.Internal.hPut: internal error.",[Char]
" Not enough space after flush.",[Char]
" required: "[Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++Int -> [Char]
forall a. Show a => a -> [Char]
showInt
minFree ,[Char]
" free: "[Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++Int -> [Char]
forall a. Show a => a -> [Char]
show(Buffer Word8 -> Int
forall e. Buffer e -> Int
freeSpace Buffer Word8
buf )]|Bool
otherwise=dolet!br :: BufferRange
br =Ptr Word8 -> Ptr Word8 -> BufferRange
BufferRange Ptr Word8
forall {b}. Ptr b
op (Ptr Word8
pBuf Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr`Buffer Word8 -> Int
forall e. Buffer e -> Int
IO.bufSizeBuffer Word8
buf )IO a
res <-BuildStep a
-> (Ptr Word8 -> a -> IO (IO a))
-> (Ptr Word8 -> Int -> BuildStep a -> IO (IO a))
-> (Ptr Word8 -> StrictByteString -> BuildStep a -> IO (IO a))
-> BufferRange
-> IO (IO a)
forall a b.
BuildStep a
-> (Ptr Word8 -> a -> IO b)
-> (Ptr Word8 -> Int -> BuildStep a -> IO b)
-> (Ptr Word8 -> StrictByteString -> BuildStep a -> IO b)
-> BufferRange
-> IO b
fillWithBuildStep BuildStep a
step Ptr Word8 -> a -> IO (IO a)
forall {a} {a}. Ptr a -> a -> IO (IO a)
doneH Ptr Word8 -> Int -> BuildStep a -> IO (IO a)
forall {a}. Ptr a -> Int -> BuildStep a -> IO (IO a)
fullH Ptr Word8 -> StrictByteString -> BuildStep a -> IO (IO a)
forall {a}. Ptr a -> StrictByteString -> BuildStep a -> IO (IO a)
insertChunkH BufferRange
br ForeignPtr Word8 -> IO ()
forall a. ForeignPtr a -> IO ()
touchForeignPtrForeignPtr Word8
fpBuf IO a -> IO (IO a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
returnIO a
res wherefpBuf :: ForeignPtr Word8
fpBuf =Buffer Word8 -> ForeignPtr Word8
forall e. Buffer e -> RawBuffer e
IO.bufRawBuffer Word8
buf pBuf :: Ptr Word8
pBuf =ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtrForeignPtr Word8
fpBuf op :: Ptr b
op =Ptr Word8
pBuf Ptr Word8 -> Int -> Ptr b
forall a b. Ptr a -> Int -> Ptr b
`plusPtr`Buffer Word8 -> Int
forall e. Buffer e -> Int
IO.bufRBuffer Word8
buf {-# INLINEupdateBufR #-}updateBufR :: Ptr a -> IO ()
updateBufR Ptr a
op' =dolet!off' :: Int
off' =Ptr a
op' Ptr a -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr`Ptr Word8
pBuf !buf' :: Buffer Word8
buf' =Buffer Word8
buf {IO.bufR=off' }IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORefIORef (Buffer Word8)
refBuf Buffer Word8
buf' doneH :: Ptr a -> a -> IO (IO a)
doneH Ptr a
op' a
x =doPtr a -> IO ()
forall {a}. Ptr a -> IO ()
updateBufR Ptr a
op' -- We must flush if this Handle is set to NoBuffering.-- If it is set to LineBuffering, be conservative and-- flush anyway (we didn't check for newlines in the data).-- Flushing must happen outside this 'wantWriteableHandle'-- due to the possible async. exception.caseHandle__ -> BufferMode
haBufferModeHandle__
h_ ofBlockBufferingMaybe Int
_->IO a -> IO (IO a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(IO a -> IO (IO a)) -> IO a -> IO (IO a)
forall a b. (a -> b) -> a -> b
$a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
returna
x BufferMode
_line_or_no_buffering ->IO a -> IO (IO a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(IO a -> IO (IO a)) -> IO a -> IO (IO a)
forall a b. (a -> b) -> a -> b
$Handle -> IO ()
hFlushHandle
h IO () -> IO a -> IO a
forall a b. IO a -> IO b -> IO b
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>a -> IO a
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
returna
x fullH :: Ptr a -> Int -> BuildStep a -> IO (IO a)
fullH Ptr a
op' Int
minSize BuildStep a
nextStep =doPtr a -> IO ()
forall {a}. Ptr a -> IO ()
updateBufR Ptr a
op' IO a -> IO (IO a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(IO a -> IO (IO a)) -> IO a -> IO (IO a)
forall a b. (a -> b) -> a -> b
$Int -> BuildStep a -> IO a
fillHandle Int
minSize BuildStep a
nextStep -- 'fillHandle' will flush the buffer (provided there is-- really less than @minSize@ space left) before executing-- the 'nextStep'.insertChunkH :: Ptr a -> StrictByteString -> BuildStep a -> IO (IO a)
insertChunkH Ptr a
op' StrictByteString
bs BuildStep a
nextStep =doPtr a -> IO ()
forall {a}. Ptr a -> IO ()
updateBufR Ptr a
op' IO a -> IO (IO a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(IO a -> IO (IO a)) -> IO a -> IO (IO a)
forall a b. (a -> b) -> a -> b
$doHandle -> StrictByteString -> IO ()
S.hPut Handle
h StrictByteString
bs Int -> BuildStep a -> IO a
fillHandle Int
1BuildStep a
nextStep -- | Execute a 'Put' and return the computed result and the bytes-- written during the computation as a 'L.LazyByteString'.---- This function is strict in the computed result and lazy in the writing of-- the bytes. For example, given---- @--infinitePut = sequence_ (repeat (putBuilder (word8 1))) >> return 0-- @---- evaluating the expression---- @--fst $ putToLazyByteString infinitePut-- @---- does not terminate, while evaluating the expression---- @--L.head $ snd $ putToLazyByteString infinitePut-- @---- does terminate and yields the value @1 :: Word8@.---- An illustrative example for these strictness properties is the-- implementation of Base64 decoding (<http://en.wikipedia.org/wiki/Base64>).---- @--type DecodingState = ...----decodeBase64 :: 'S.StrictByteString' -> DecodingState -> 'Put' (Maybe DecodingState)--decodeBase64 = ...-- @---- The above function takes a 'S.StrictByteString' supposed to represent-- Base64 encoded data and the current decoding state.-- It writes the decoded bytes as the side-effect of the 'Put' and returns the-- new decoding state, if the decoding of all data in the 'S.StrictByteString' was-- successful. The checking if the 'S.StrictByteString' represents Base64-- encoded data and the actual decoding are fused. This makes the common case,-- where all data represents Base64 encoded data, more efficient. It also-- implies that all data must be decoded before the final decoding-- state can be returned. 'Put's are intended for implementing such fused-- checking and decoding/encoding, which is reflected in their strictness-- properties.{-# NOINLINEputToLazyByteString #-}putToLazyByteString ::Put a -- ^ 'Put' to execute->(a ,L.LazyByteString )-- ^ Result and 'L.LazyByteString'-- written as its side-effectputToLazyByteString :: forall a. Put a -> (a, LazyByteString)
putToLazyByteString =AllocationStrategy
-> (a -> (a, LazyByteString)) -> Put a -> (a, LazyByteString)
forall a b.
AllocationStrategy
-> (a -> (b, LazyByteString)) -> Put a -> (b, LazyByteString)
putToLazyByteStringWith (Int -> Int -> AllocationStrategy
safeStrategy Int
L.smallChunkSize Int
L.defaultChunkSize )(,LazyByteString
L.Empty )-- | Execute a 'Put' with a buffer-allocation strategy and a continuation. For-- example, 'putToLazyByteString' is implemented as follows.---- @--putToLazyByteString = 'putToLazyByteStringWith'-- ('safeStrategy' 'L.smallChunkSize' 'L.defaultChunkSize') (\x -> (x, L.empty))-- @--{-# INLINEputToLazyByteStringWith #-}putToLazyByteStringWith ::AllocationStrategy -- ^ Buffer allocation strategy to use->(a ->(b ,L.LazyByteString ))-- ^ Continuation to use for computing the final result and the tail of-- its side-effect (the written bytes).->Put a -- ^ 'Put' to execute->(b ,L.LazyByteString )-- ^ Resulting 'L.LazyByteString'putToLazyByteStringWith :: forall a b.
AllocationStrategy
-> (a -> (b, LazyByteString)) -> Put a -> (b, LazyByteString)
putToLazyByteStringWith AllocationStrategy
strategy a -> (b, LazyByteString)
k Put a
p =AllocationStrategy
-> (a -> (b, LazyByteString))
-> ChunkIOStream a
-> (b, LazyByteString)
forall a b.
AllocationStrategy
-> (a -> (b, LazyByteString))
-> ChunkIOStream a
-> (b, LazyByteString)
ciosToLazyByteString AllocationStrategy
strategy a -> (b, LazyByteString)
k (ChunkIOStream a -> (b, LazyByteString))
-> ChunkIOStream a -> (b, LazyByteString)
forall a b. (a -> b) -> a -> b
$IO (ChunkIOStream a) -> ChunkIOStream a
forall a. IO a -> a
unsafeDupablePerformIO(IO (ChunkIOStream a) -> ChunkIOStream a)
-> IO (ChunkIOStream a) -> ChunkIOStream a
forall a b. (a -> b) -> a -> b
$AllocationStrategy -> BuildStep a -> IO (ChunkIOStream a)
forall a. AllocationStrategy -> BuildStep a -> IO (ChunkIOStream a)
buildStepToCIOS AllocationStrategy
strategy (Put a -> BuildStep a
forall a. Put a -> BuildStep a
runPut Put a
p )-------------------------------------------------------------------------------- ByteString insertion / controlling chunk boundaries-------------------------------------------------------------------------------- Raw memory--------------- | @'ensureFree' n@ ensures that there are at least @n@ free bytes-- for the following 'Builder'.{-# INLINEensureFree #-}ensureFree ::Int->Builder ensureFree :: Int -> Builder
ensureFree Int
minFree =(forall r. BuildStep r -> BuildStep r) -> Builder
builder BuildStep r -> BuildStep r
forall r. BuildStep r -> BuildStep r
step wherestep :: BuildStep a -> BuildStep a
step BuildStep a
k br :: BufferRange
br @(BufferRange Ptr Word8
op Ptr Word8
ope )|Ptr Word8
ope Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr`Ptr Word8
op Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<Int
minFree =BuildSignal a -> IO (BuildSignal a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(BuildSignal a -> IO (BuildSignal a))
-> BuildSignal a -> IO (BuildSignal a)
forall a b. (a -> b) -> a -> b
$Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
forall a. Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
bufferFull Int
minFree Ptr Word8
op BuildStep a
k |Bool
otherwise=BuildStep a
k BufferRange
br -- | Copy the bytes from a 'S.StrictByteString' into the output stream.wrappedBytesCopyStep ::S.StrictByteString -- ^ Input 'S.StrictByteString'.->BuildStep a ->BuildStep a -- See Note [byteStringCopyStep and wrappedBytesCopyStep]wrappedBytesCopyStep :: forall a. StrictByteString -> BuildStep a -> BuildStep a
wrappedBytesCopyStep StrictByteString
bs0 BuildStep a
k =StrictByteString -> BuildStep a
go StrictByteString
bs0 wherego :: StrictByteString -> BuildStep a
go !bs :: StrictByteString
bs @(S.BS ForeignPtr Word8
ifp Int
inpRemaining )(BufferRange Ptr Word8
op Ptr Word8
ope )|Int
inpRemaining Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<=Int
outRemaining =doForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
S.unsafeWithForeignPtrForeignPtr Word8
ifp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$\Ptr Word8
ip ->Ptr Word8 -> Ptr Word8 -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
copyBytesPtr Word8
op Ptr Word8
ip Int
inpRemaining let!br' :: BufferRange
br' =Ptr Word8 -> Ptr Word8 -> BufferRange
BufferRange (Ptr Word8
op Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr`Int
inpRemaining )Ptr Word8
ope BuildStep a
k BufferRange
br' |Bool
otherwise=doForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
S.unsafeWithForeignPtrForeignPtr Word8
ifp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$\Ptr Word8
ip ->Ptr Word8 -> Ptr Word8 -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
copyBytesPtr Word8
op Ptr Word8
ip Int
outRemaining let!bs' :: StrictByteString
bs' =Int -> StrictByteString -> StrictByteString
S.unsafeDrop Int
outRemaining StrictByteString
bs BuildSignal a -> IO (BuildSignal a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(BuildSignal a -> IO (BuildSignal a))
-> BuildSignal a -> IO (BuildSignal a)
forall a b. (a -> b) -> a -> b
$Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
forall a. Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
bufferFull Int
1Ptr Word8
ope (StrictByteString -> BuildStep a
go StrictByteString
bs' )whereoutRemaining :: Int
outRemaining =Ptr Word8
ope Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr`Ptr Word8
op -- Strict ByteStrings-------------------------------------------------------------------------------- | Construct a 'Builder' that copies the 'S.StrictByteString's, if it is-- smaller than the treshold, and inserts it directly otherwise.---- For example, @byteStringThreshold 1024@ copies 'S.StrictByteString's whose size-- is less or equal to 1kb, and inserts them directly otherwise. This implies-- that the average chunk-size of the generated 'L.LazyByteString' may be as-- low as 513 bytes, as there could always be just a single byte between the-- directly inserted 1025 byte, 'S.StrictByteString's.--{-# INLINEbyteStringThreshold #-}byteStringThreshold ::Int->S.StrictByteString ->Builder byteStringThreshold :: Int -> StrictByteString -> Builder
byteStringThreshold Int
maxCopySize =\StrictByteString
bs ->(forall r. BuildStep r -> BuildStep r) -> Builder
builder ((forall r. BuildStep r -> BuildStep r) -> Builder)
-> (forall r. BuildStep r -> BuildStep r) -> Builder
forall a b. (a -> b) -> a -> b
$StrictByteString -> BuildStep r -> BuildStep r
forall a. StrictByteString -> BuildStep a -> BuildStep a
step StrictByteString
bs wherestep :: StrictByteString -> BuildStep a -> BuildStep a
step bs :: StrictByteString
bs @(S.BS ForeignPtr Word8
_Int
len )BuildStep a
k br :: BufferRange
br @(BufferRange !Ptr Word8
op Ptr Word8
_)|Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<=Int
maxCopySize =StrictByteString -> BuildStep a -> BuildStep a
forall a. StrictByteString -> BuildStep a -> BuildStep a
byteStringCopyStep StrictByteString
bs BuildStep a
k BufferRange
br |Bool
otherwise=BuildSignal a -> IO (BuildSignal a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(BuildSignal a -> IO (BuildSignal a))
-> BuildSignal a -> IO (BuildSignal a)
forall a b. (a -> b) -> a -> b
$Ptr Word8 -> StrictByteString -> BuildStep a -> BuildSignal a
forall a.
Ptr Word8 -> StrictByteString -> BuildStep a -> BuildSignal a
insertChunk Ptr Word8
op StrictByteString
bs BuildStep a
k -- | Construct a 'Builder' that copies the 'S.StrictByteString'.---- Use this function to create 'Builder's from smallish (@<= 4kb@)-- 'S.StrictByteString's or if you need to guarantee that the 'S.StrictByteString' is not-- shared with the chunks generated by the 'Builder'.--{-# INLINEbyteStringCopy #-}byteStringCopy ::S.StrictByteString ->Builder byteStringCopy :: StrictByteString -> Builder
byteStringCopy =\StrictByteString
bs ->(forall r. BuildStep r -> BuildStep r) -> Builder
builder ((forall r. BuildStep r -> BuildStep r) -> Builder)
-> (forall r. BuildStep r -> BuildStep r) -> Builder
forall a b. (a -> b) -> a -> b
$StrictByteString -> BuildStep r -> BuildStep r
forall a. StrictByteString -> BuildStep a -> BuildStep a
byteStringCopyStep StrictByteString
bs {-
Note [byteStringCopyStep and wrappedBytesCopyStep]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A Builder that copies the contents of an arbitrary ByteString needs a
recursive loop, since the bytes to be copied might not fit into the
first few chunk buffers provided by the driver. That loop is
implemented in 'wrappedBytesCopyStep'. But we also have a
non-recursive wrapper, 'byteStringCopyStep', which performs exactly
the first iteration of that loop, falling back to 'wrappedBytesCopyStep'
if a chunk boundary is reached before the entire ByteString is copied.
This is very strange! Why do we do this? Perhaps mostly for
historical reasons. But sadly, changing this to use a single
recursive loop regresses the benchmark 'foldMap byteStringCopy' by
about 30% as of 2024, in one of two ways:
 1. If the continuation 'k' is taken as an argument of the
 inner copying loop, it remains an unknown function call.
 So for each bytestring copied, that continuation must be
 entered later via a gen-apply function, which incurs dozens
 of cycles of extra overhead.
 2. If the continuation 'k' is lifted out of the inner copying
 loop, it becomes a free variable. And after a bit of
 inlining, there will be no unknown function call. But, if
 the continuation function has any free variables, these
 become free variables of the inner copying loop, which
 prevent the loop from floating out. (In the actual
 benchmark, the tail of the list of bytestrings to copy is
 such a free variable of the continuation.) As a result,
 the inner copying loop becomes a function closure object
 rather than a top-level function. And that means a new
 inner-copying-loop function-closure-object must be
 allocated on the heap for every bytestring copied, which
 is expensive.
 In theory, GHC's late-lambda-lifting pass can clean this up by
 abstracting over the problematic free variables. But for some
 unknown reason (perhaps a bug in ghc-9.10.1) this optimization
 does not fire on the relevant benchmark code, even with a
 sufficiently high value of -fstg-lift-lams-rec-args.
Alternatively, it is possible to avoid recursion altogether by
requesting that the next chunk be large enough to accommodate the
entire remainder of the input when a chunk boundary is reached.
But:
 * For very large ByteStrings, this may incur unwanted latency.
 * Large next-chunk-size requests have caused breakage downstream
 in the past. See also https://github.com/yesodweb/wai/issues/894
-}{-# INLINEbyteStringCopyStep #-}byteStringCopyStep ::S.StrictByteString ->BuildStep a ->BuildStep a -- See Note [byteStringCopyStep and wrappedBytesCopyStep]byteStringCopyStep :: forall a. StrictByteString -> BuildStep a -> BuildStep a
byteStringCopyStep bs :: StrictByteString
bs @(S.BS ForeignPtr Word8
ifp Int
isize )BuildStep a
k br :: BufferRange
br @(BufferRange Ptr Word8
op Ptr Word8
ope )|Int
isize Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<=Int
osize =doForeignPtr Word8 -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
S.unsafeWithForeignPtrForeignPtr Word8
ifp ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$\Ptr Word8
ip ->Ptr Word8 -> Ptr Word8 -> Int -> IO ()
forall a. Ptr a -> Ptr a -> Int -> IO ()
copyBytesPtr Word8
op Ptr Word8
ip Int
isize BuildStep a
k (Ptr Word8 -> Ptr Word8 -> BufferRange
BufferRange Ptr Word8
forall {b}. Ptr b
op' Ptr Word8
ope )|Bool
otherwise=StrictByteString -> BuildStep a -> BuildStep a
forall a. StrictByteString -> BuildStep a -> BuildStep a
wrappedBytesCopyStep StrictByteString
bs BuildStep a
k BufferRange
br whereosize :: Int
osize =Ptr Word8
ope Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr`Ptr Word8
op op' :: Ptr b
op' =Ptr Word8
op Ptr Word8 -> Int -> Ptr b
forall a b. Ptr a -> Int -> Ptr b
`plusPtr`Int
isize -- | Construct a 'Builder' that always inserts the 'S.StrictByteString'-- directly as a chunk.---- This implies flushing the output buffer, even if it contains just-- a single byte. You should therefore use 'byteStringInsert' only for large-- (@> 8kb@) 'S.StrictByteString's. Otherwise, the generated chunks are too-- fragmented to be processed efficiently afterwards.--{-# INLINEbyteStringInsert #-}byteStringInsert ::S.StrictByteString ->Builder byteStringInsert :: StrictByteString -> Builder
byteStringInsert =\StrictByteString
bs ->(forall r. BuildStep r -> BuildStep r) -> Builder
builder ((forall r. BuildStep r -> BuildStep r) -> Builder)
-> (forall r. BuildStep r -> BuildStep r) -> Builder
forall a b. (a -> b) -> a -> b
$\BuildStep r
k (BufferRange Ptr Word8
op Ptr Word8
_)->BuildSignal r -> IO (BuildSignal r)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(BuildSignal r -> IO (BuildSignal r))
-> BuildSignal r -> IO (BuildSignal r)
forall a b. (a -> b) -> a -> b
$Ptr Word8 -> StrictByteString -> BuildStep r -> BuildSignal r
forall a.
Ptr Word8 -> StrictByteString -> BuildStep a -> BuildSignal a
insertChunk Ptr Word8
op StrictByteString
bs BuildStep r
k -- Short bytestrings-------------------------------------------------------------------------------- | Construct a 'Builder' that copies the 'SH.ShortByteString'.--{-# INLINEshortByteString #-}shortByteString ::Sh.ShortByteString ->Builder shortByteString :: ShortByteString -> Builder
shortByteString =\ShortByteString
sbs ->(forall r. BuildStep r -> BuildStep r) -> Builder
builder ((forall r. BuildStep r -> BuildStep r) -> Builder)
-> (forall r. BuildStep r -> BuildStep r) -> Builder
forall a b. (a -> b) -> a -> b
$ShortByteString -> BuildStep r -> BuildStep r
forall a. ShortByteString -> BuildStep a -> BuildStep a
shortByteStringCopyStep ShortByteString
sbs -- | Copy the bytes from a 'SH.ShortByteString' into the output stream.{-# INLINEshortByteStringCopyStep #-}shortByteStringCopyStep ::Sh.ShortByteString -- ^ Input 'SH.ShortByteString'.->BuildStep a ->BuildStep a shortByteStringCopyStep :: forall a. ShortByteString -> BuildStep a -> BuildStep a
shortByteStringCopyStep !ShortByteString
sbs BuildStep a
k =Int -> Int -> BuildStep a
go Int
0(ShortByteString -> Int
Sh.length ShortByteString
sbs )wherego :: Int -> Int -> BuildStep a
go !Int
ip !Int
ipe (BufferRange Ptr Word8
op Ptr Word8
ope )|Int
inpRemaining Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<=Int
outRemaining =doShortByteString -> Int -> Ptr Word8 -> Int -> IO ()
forall a. ShortByteString -> Int -> Ptr a -> Int -> IO ()
Sh.copyToPtr ShortByteString
sbs Int
ip Ptr Word8
op Int
inpRemaining let!br' :: BufferRange
br' =Ptr Word8 -> Ptr Word8 -> BufferRange
BufferRange (Ptr Word8
op Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr`Int
inpRemaining )Ptr Word8
ope BuildStep a
k BufferRange
br' |Bool
otherwise=doShortByteString -> Int -> Ptr Word8 -> Int -> IO ()
forall a. ShortByteString -> Int -> Ptr a -> Int -> IO ()
Sh.copyToPtr ShortByteString
sbs Int
ip Ptr Word8
op Int
outRemaining let!ip' :: Int
ip' =Int
ip Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
outRemaining BuildSignal a -> IO (BuildSignal a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(BuildSignal a -> IO (BuildSignal a))
-> BuildSignal a -> IO (BuildSignal a)
forall a b. (a -> b) -> a -> b
$Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
forall a. Int -> Ptr Word8 -> BuildStep a -> BuildSignal a
bufferFull Int
1Ptr Word8
ope (Int -> Int -> BuildStep a
go Int
ip' Int
ipe )whereoutRemaining :: Int
outRemaining =Ptr Word8
ope Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr`Ptr Word8
op inpRemaining :: Int
inpRemaining =Int
ipe Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
ip -- Lazy bytestrings-------------------------------------------------------------------------------- | Construct a 'Builder' that uses the thresholding strategy of 'byteStringThreshold'-- for each chunk of the 'L.LazyByteString'.--{-# INLINElazyByteStringThreshold #-}lazyByteStringThreshold ::Int->L.LazyByteString ->Builder lazyByteStringThreshold :: Int -> LazyByteString -> Builder
lazyByteStringThreshold Int
maxCopySize =(StrictByteString -> Builder -> Builder)
-> Builder -> LazyByteString -> Builder
forall a. (StrictByteString -> a -> a) -> a -> LazyByteString -> a
L.foldrChunks (\StrictByteString
bs Builder
b ->Int -> StrictByteString -> Builder
byteStringThreshold Int
maxCopySize StrictByteString
bs Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend`Builder
b )Builder
forall a. Monoid a => a
mempty-- TODO: We could do better here. Currently, Large, Small, Large, leads to-- an unnecessary copy of the 'Small' chunk.-- | Construct a 'Builder' that copies the 'L.LazyByteString'.--{-# INLINElazyByteStringCopy #-}lazyByteStringCopy ::L.LazyByteString ->Builder lazyByteStringCopy :: LazyByteString -> Builder
lazyByteStringCopy =(StrictByteString -> Builder -> Builder)
-> Builder -> LazyByteString -> Builder
forall a. (StrictByteString -> a -> a) -> a -> LazyByteString -> a
L.foldrChunks (\StrictByteString
bs Builder
b ->StrictByteString -> Builder
byteStringCopy StrictByteString
bs Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend`Builder
b )Builder
forall a. Monoid a => a
mempty-- | Construct a 'Builder' that inserts all chunks of the 'L.LazyByteString'-- directly.--{-# INLINElazyByteStringInsert #-}lazyByteStringInsert ::L.LazyByteString ->Builder lazyByteStringInsert :: LazyByteString -> Builder
lazyByteStringInsert =(StrictByteString -> Builder -> Builder)
-> Builder -> LazyByteString -> Builder
forall a. (StrictByteString -> a -> a) -> a -> LazyByteString -> a
L.foldrChunks (\StrictByteString
bs Builder
b ->StrictByteString -> Builder
byteStringInsert StrictByteString
bs Builder -> Builder -> Builder
forall a. Monoid a => a -> a -> a
`mappend`Builder
b )Builder
forall a. Monoid a => a
mempty-- | Create a 'Builder' denoting the same sequence of bytes as a-- 'S.StrictByteString'.-- The 'Builder' inserts large 'S.StrictByteString's directly, but copies small ones-- to ensure that the generated chunks are large on average.--{-# INLINEbyteString #-}byteString ::S.StrictByteString ->Builder byteString :: StrictByteString -> Builder
byteString =Int -> StrictByteString -> Builder
byteStringThreshold Int
maximalCopySize -- | Create a 'Builder' denoting the same sequence of bytes as a lazy-- 'L.LazyByteString'.-- The 'Builder' inserts large chunks of the 'L.LazyByteString' directly,-- but copies small ones to ensure that the generated chunks are large on-- average.--{-# INLINElazyByteString #-}lazyByteString ::L.LazyByteString ->Builder lazyByteString :: LazyByteString -> Builder
lazyByteString =Int -> LazyByteString -> Builder
lazyByteStringThreshold Int
maximalCopySize -- FIXME: also insert the small chunk for [large,small,large] directly.-- Perhaps it makes even sense to concatenate the small chunks in-- [large,small,small,small,large] and insert them directly afterwards to avoid-- unnecessary buffer spilling. Hmm, but that uncontrollably increases latency-- => no good!-- | The maximal size of a 'S.StrictByteString' that is copied.-- @2 * 'L.smallChunkSize'@ to guarantee that on average a chunk is of-- 'L.smallChunkSize'.maximalCopySize ::IntmaximalCopySize :: Int
maximalCopySize =Int
2Int -> Int -> Int
forall a. Num a => a -> a -> a
*Int
L.smallChunkSize -------------------------------------------------------------------------------- Builder execution-------------------------------------------------------------------------------- | A buffer allocation strategy for executing 'Builder's.dataAllocationStrategy =AllocationStrategy (Maybe(Buffer ,Int)->IOBuffer ){-# UNPACK#-}!Int(Int->Int->Bool)-- | Create a custom allocation strategy. See the code for 'safeStrategy' and-- 'untrimmedStrategy' for examples.{-# INLINEcustomStrategy #-}customStrategy ::(Maybe(Buffer ,Int)->IOBuffer )-- ^ Buffer allocation function.---- * If 'Nothing' is given, then a new first buffer should be allocated.---- * If @'Just' (oldBuf, minSize)@ is given, then a buffer with minimal-- size @minSize@ must be returned. The strategy may reuse @oldBuf@ only if-- @oldBuf@ is large enough and the consumer can guarantee that this will-- not result in a violation of referential transparency.---- /Warning:/ for multithreaded programs, it is generally unsafe to reuse-- buffers when using the consumers of 'Builder' in this package. For-- example, if 'toLazyByteStringWith' is called with an-- 'AllocationStrategy' that reuses buffers, evaluating the result by-- multiple threads simultaneously may lead to corrupted output.->Int-- ^ Default buffer size.->(Int->Int->Bool)-- ^ A predicate @trim used allocated@ returning 'True', if the buffer-- should be trimmed before it is returned.->AllocationStrategy customStrategy :: (Maybe (Buffer, Int) -> IO Buffer)
-> Int -> (Int -> Int -> Bool) -> AllocationStrategy
customStrategy =(Maybe (Buffer, Int) -> IO Buffer)
-> Int -> (Int -> Int -> Bool) -> AllocationStrategy
AllocationStrategy -- | Sanitize a buffer size; i.e., make it at least the size of an 'Int'.{-# INLINEsanitize #-}sanitize ::Int->Intsanitize :: Int -> Int
sanitize =Int -> Int -> Int
forall a. Ord a => a -> a -> a
max(Int -> Int
forall a. Storable a => a -> Int
sizeOf(Int
forall a. HasCallStack => a
undefined::Int))-- | Use this strategy for generating 'L.LazyByteString's whose chunks are-- discarded right after they are generated. For example, if you just generate-- them to write them to a network socket.{-# INLINEuntrimmedStrategy #-}untrimmedStrategy ::Int-- ^ Size of the first buffer->Int-- ^ Size of successive buffers->AllocationStrategy -- ^ An allocation strategy that does not trim any of the-- filled buffers before converting it to a chunkuntrimmedStrategy :: Int -> Int -> AllocationStrategy
untrimmedStrategy Int
firstSize Int
bufSize =(Maybe (Buffer, Int) -> IO Buffer)
-> Int -> (Int -> Int -> Bool) -> AllocationStrategy
AllocationStrategy Maybe (Buffer, Int) -> IO Buffer
forall {a}. Maybe (a, Int) -> IO Buffer
nextBuffer (Int -> Int
sanitize Int
bufSize )(\Int
_Int
_->Bool
False)where{-# INLINEnextBuffer #-}nextBuffer :: Maybe (a, Int) -> IO Buffer
nextBuffer Maybe (a, Int)
Nothing=Int -> IO Buffer
newBuffer (Int -> IO Buffer) -> Int -> IO Buffer
forall a b. (a -> b) -> a -> b
$Int -> Int
sanitize Int
firstSize nextBuffer (Just(a
_,Int
minSize ))=Int -> IO Buffer
newBuffer Int
minSize -- | Use this strategy for generating 'L.LazyByteString's whose chunks are-- likely to survive one garbage collection. This strategy trims buffers-- that are filled less than half in order to avoid spilling too much memory.{-# INLINEsafeStrategy #-}safeStrategy ::Int-- ^ Size of first buffer->Int-- ^ Size of successive buffers->AllocationStrategy -- ^ An allocation strategy that guarantees that at least half-- of the allocated memory is used for live datasafeStrategy :: Int -> Int -> AllocationStrategy
safeStrategy Int
firstSize Int
bufSize =(Maybe (Buffer, Int) -> IO Buffer)
-> Int -> (Int -> Int -> Bool) -> AllocationStrategy
AllocationStrategy Maybe (Buffer, Int) -> IO Buffer
forall {a}. Maybe (a, Int) -> IO Buffer
nextBuffer (Int -> Int
sanitize Int
bufSize )Int -> Int -> Bool
forall {a}. (Ord a, Num a) => a -> a -> Bool
trim wheretrim :: a -> a -> Bool
trim a
used a
size =a
2a -> a -> a
forall a. Num a => a -> a -> a
*a
used a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<a
size {-# INLINEnextBuffer #-}nextBuffer :: Maybe (a, Int) -> IO Buffer
nextBuffer Maybe (a, Int)
Nothing=Int -> IO Buffer
newBuffer (Int -> IO Buffer) -> Int -> IO Buffer
forall a b. (a -> b) -> a -> b
$Int -> Int
sanitize Int
firstSize nextBuffer (Just(a
_,Int
minSize ))=Int -> IO Buffer
newBuffer Int
minSize -- | Execute a 'Builder' and return the generated chunks as a 'L.LazyByteString'.-- The work is performed lazy, i.e., only when a chunk of the 'L.LazyByteString'-- is forced.{-# NOINLINEtoLazyByteString #-}-- ensure code is sharedtoLazyByteString ::Builder ->L.LazyByteString toLazyByteString :: Builder -> LazyByteString
toLazyByteString =AllocationStrategy -> LazyByteString -> Builder -> LazyByteString
toLazyByteStringWith (Int -> Int -> AllocationStrategy
safeStrategy Int
L.smallChunkSize Int
L.defaultChunkSize )LazyByteString
L.Empty -- | /Heavy inlining./ Execute a 'Builder' with custom execution parameters.---- This function is inlined despite its heavy code-size to allow fusing with-- the allocation strategy. For example, the default 'Builder' execution-- function 'Data.ByteString.Builder.Internal.toLazyByteString' is defined as follows.---- @-- {-\# NOINLINE toLazyByteString \#-}-- toLazyByteString =-- toLazyByteStringWith ('safeStrategy' 'L.smallChunkSize' 'L.defaultChunkSize') L.Empty-- @---- where @L.Empty@ is the zero-length 'L.LazyByteString'.---- In most cases, the parameters used by 'Data.ByteString.Builder.toLazyByteString' give good-- performance. A sub-performing case of 'Data.ByteString.Builder.toLazyByteString' is executing short-- (<128 bytes) 'Builder's. In this case, the allocation overhead for the first-- 4kb buffer and the trimming cost dominate the cost of executing the-- 'Builder'. You can avoid this problem using---- >toLazyByteStringWith (safeStrategy 128 smallChunkSize) L.Empty---- This reduces the allocation and trimming overhead, as all generated-- 'L.LazyByteString's fit into the first buffer and there is no trimming-- required, if more than 64 bytes and less than 128 bytes are written.--{-# INLINEtoLazyByteStringWith #-}toLazyByteStringWith ::AllocationStrategy -- ^ Buffer allocation strategy to use->L.LazyByteString -- ^ 'L.LazyByteString' to use as the tail of the generated lazy-- 'L.LazyByteString'->Builder -- ^ 'Builder' to execute->L.LazyByteString -- ^ Resulting 'L.LazyByteString'toLazyByteStringWith :: AllocationStrategy -> LazyByteString -> Builder -> LazyByteString
toLazyByteStringWith AllocationStrategy
strategy LazyByteString
k Builder
b =AllocationStrategy
-> LazyByteString -> ChunkIOStream () -> LazyByteString
ciosUnitToLazyByteString AllocationStrategy
strategy LazyByteString
k (ChunkIOStream () -> LazyByteString)
-> ChunkIOStream () -> LazyByteString
forall a b. (a -> b) -> a -> b
$IO (ChunkIOStream ()) -> ChunkIOStream ()
forall a. IO a -> a
unsafeDupablePerformIO(IO (ChunkIOStream ()) -> ChunkIOStream ())
-> IO (ChunkIOStream ()) -> ChunkIOStream ()
forall a b. (a -> b) -> a -> b
$AllocationStrategy -> BuildStep () -> IO (ChunkIOStream ())
forall a. AllocationStrategy -> BuildStep a -> IO (ChunkIOStream a)
buildStepToCIOS AllocationStrategy
strategy (Builder -> BuildStep ()
runBuilder Builder
b )-- | Convert a 'BuildStep' to a 'ChunkIOStream' stream by executing it on-- 'Buffer's allocated according to the given 'AllocationStrategy'.{-# INLINEbuildStepToCIOS #-}buildStepToCIOS ::foralla .AllocationStrategy -- ^ Buffer allocation strategy to use->BuildStep a -- ^ 'BuildStep' to execute->IO(ChunkIOStream a )buildStepToCIOS :: forall a. AllocationStrategy -> BuildStep a -> IO (ChunkIOStream a)
buildStepToCIOS (AllocationStrategy Maybe (Buffer, Int) -> IO Buffer
nextBuffer Int
bufSize Int -> Int -> Bool
trim )=\BuildStep a
step ->Maybe (Buffer, Int) -> IO Buffer
nextBuffer Maybe (Buffer, Int)
forall a. Maybe a
NothingIO Buffer
-> (Buffer -> IO (ChunkIOStream a)) -> IO (ChunkIOStream a)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=BuildStep a -> Buffer -> IO (ChunkIOStream a)
fill BuildStep a
step wherefill ::BuildStep a ->Buffer ->IO(ChunkIOStream a )fill :: BuildStep a -> Buffer -> IO (ChunkIOStream a)
fill !BuildStep a
step buf :: Buffer
buf @(Buffer ForeignPtr Word8
fpbuf br :: BufferRange
br @(BufferRange Ptr Word8
_Ptr Word8
pe ))=doChunkIOStream a
res <-BuildStep a
-> (Ptr Word8 -> a -> IO (ChunkIOStream a))
-> (Ptr Word8 -> Int -> BuildStep a -> IO (ChunkIOStream a))
-> (Ptr Word8
 -> StrictByteString -> BuildStep a -> IO (ChunkIOStream a))
-> BufferRange
-> IO (ChunkIOStream a)
forall a b.
BuildStep a
-> (Ptr Word8 -> a -> IO b)
-> (Ptr Word8 -> Int -> BuildStep a -> IO b)
-> (Ptr Word8 -> StrictByteString -> BuildStep a -> IO b)
-> BufferRange
-> IO b
fillWithBuildStep BuildStep a
step Ptr Word8 -> a -> IO (ChunkIOStream a)
doneH Ptr Word8 -> Int -> BuildStep a -> IO (ChunkIOStream a)
fullH Ptr Word8
-> StrictByteString -> BuildStep a -> IO (ChunkIOStream a)
insertChunkH BufferRange
br ForeignPtr Word8 -> IO ()
forall a. ForeignPtr a -> IO ()
touchForeignPtrForeignPtr Word8
fpbuf ChunkIOStream a -> IO (ChunkIOStream a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
returnChunkIOStream a
res wherepbuf ::PtrWord8pbuf :: Ptr Word8
pbuf =ForeignPtr Word8 -> Ptr Word8
forall a. ForeignPtr a -> Ptr a
unsafeForeignPtrToPtrForeignPtr Word8
fpbuf doneH ::PtrWord8->a ->IO(ChunkIOStream a )doneH :: Ptr Word8 -> a -> IO (ChunkIOStream a)
doneH Ptr Word8
op' a
x =ChunkIOStream a -> IO (ChunkIOStream a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(ChunkIOStream a -> IO (ChunkIOStream a))
-> ChunkIOStream a -> IO (ChunkIOStream a)
forall a b. (a -> b) -> a -> b
$Buffer -> a -> ChunkIOStream a
forall a. Buffer -> a -> ChunkIOStream a
Finished (ForeignPtr Word8 -> BufferRange -> Buffer
Buffer ForeignPtr Word8
fpbuf (Ptr Word8 -> Ptr Word8 -> BufferRange
BufferRange Ptr Word8
op' Ptr Word8
pe ))a
x fullH ::PtrWord8->Int->BuildStep a ->IO(ChunkIOStream a )fullH :: Ptr Word8 -> Int -> BuildStep a -> IO (ChunkIOStream a)
fullH Ptr Word8
op' Int
minSize BuildStep a
nextStep =Ptr Word8 -> (Bool -> IO (ChunkIOStream a)) -> IO (ChunkIOStream a)
wrapChunk Ptr Word8
op' ((Bool -> IO (ChunkIOStream a)) -> IO (ChunkIOStream a))
-> (Bool -> IO (ChunkIOStream a)) -> IO (ChunkIOStream a)
forall a b. (a -> b) -> a -> b
$IO (ChunkIOStream a) -> Bool -> IO (ChunkIOStream a)
forall a b. a -> b -> a
const(IO (ChunkIOStream a) -> Bool -> IO (ChunkIOStream a))
-> IO (ChunkIOStream a) -> Bool -> IO (ChunkIOStream a)
forall a b. (a -> b) -> a -> b
$Maybe (Buffer, Int) -> IO Buffer
nextBuffer ((Buffer, Int) -> Maybe (Buffer, Int)
forall a. a -> Maybe a
Just(Buffer
buf ,Int -> Int -> Int
forall a. Ord a => a -> a -> a
maxInt
minSize Int
bufSize ))IO Buffer
-> (Buffer -> IO (ChunkIOStream a)) -> IO (ChunkIOStream a)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=BuildStep a -> Buffer -> IO (ChunkIOStream a)
fill BuildStep a
nextStep insertChunkH ::PtrWord8->S.StrictByteString ->BuildStep a ->IO(ChunkIOStream a )insertChunkH :: Ptr Word8
-> StrictByteString -> BuildStep a -> IO (ChunkIOStream a)
insertChunkH Ptr Word8
op' StrictByteString
bs BuildStep a
nextStep =Ptr Word8 -> (Bool -> IO (ChunkIOStream a)) -> IO (ChunkIOStream a)
wrapChunk Ptr Word8
op' ((Bool -> IO (ChunkIOStream a)) -> IO (ChunkIOStream a))
-> (Bool -> IO (ChunkIOStream a)) -> IO (ChunkIOStream a)
forall a b. (a -> b) -> a -> b
$\Bool
isEmpty ->StrictByteString -> IO (ChunkIOStream a) -> IO (ChunkIOStream a)
forall a.
StrictByteString -> IO (ChunkIOStream a) -> IO (ChunkIOStream a)
yield1 StrictByteString
bs (IO (ChunkIOStream a) -> IO (ChunkIOStream a))
-> IO (ChunkIOStream a) -> IO (ChunkIOStream a)
forall a b. (a -> b) -> a -> b
$-- Checking for empty case avoids allocating 'n-1' empty-- buffers for 'n' insertChunkH right after each other.ifBool
isEmpty thenBuildStep a -> Buffer -> IO (ChunkIOStream a)
fill BuildStep a
nextStep Buffer
buf elsedoBuffer
buf' <-Maybe (Buffer, Int) -> IO Buffer
nextBuffer ((Buffer, Int) -> Maybe (Buffer, Int)
forall a. a -> Maybe a
Just(Buffer
buf ,Int
bufSize ))BuildStep a -> Buffer -> IO (ChunkIOStream a)
fill BuildStep a
nextStep Buffer
buf' -- Wrap and yield a chunk, trimming it if necesary{-# INLINEwrapChunk #-}wrapChunk ::PtrWord8->(Bool->IO(ChunkIOStream a ))->IO(ChunkIOStream a )wrapChunk :: Ptr Word8 -> (Bool -> IO (ChunkIOStream a)) -> IO (ChunkIOStream a)
wrapChunk !Ptr Word8
op' Bool -> IO (ChunkIOStream a)
mkCIOS |Int
chunkSize Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
==Int
0=Bool -> IO (ChunkIOStream a)
mkCIOS Bool
True|Int -> Int -> Bool
trim Int
chunkSize Int
size =doStrictByteString
bs <-Int -> (ForeignPtr Word8 -> IO ()) -> IO StrictByteString
S.createFp Int
chunkSize ((ForeignPtr Word8 -> IO ()) -> IO StrictByteString)
-> (ForeignPtr Word8 -> IO ()) -> IO StrictByteString
forall a b. (a -> b) -> a -> b
$\ForeignPtr Word8
fpbuf' ->ForeignPtr Word8 -> ForeignPtr Word8 -> Int -> IO ()
S.memcpyFp ForeignPtr Word8
fpbuf' ForeignPtr Word8
fpbuf Int
chunkSize -- It is not safe to re-use the old buffer (see #690),-- so we allocate a new buffer after trimming.ChunkIOStream a -> IO (ChunkIOStream a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(ChunkIOStream a -> IO (ChunkIOStream a))
-> ChunkIOStream a -> IO (ChunkIOStream a)
forall a b. (a -> b) -> a -> b
$StrictByteString -> IO (ChunkIOStream a) -> ChunkIOStream a
forall a.
StrictByteString -> IO (ChunkIOStream a) -> ChunkIOStream a
Yield1 StrictByteString
bs (Bool -> IO (ChunkIOStream a)
mkCIOS Bool
False)|Bool
otherwise=ChunkIOStream a -> IO (ChunkIOStream a)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return(ChunkIOStream a -> IO (ChunkIOStream a))
-> ChunkIOStream a -> IO (ChunkIOStream a)
forall a b. (a -> b) -> a -> b
$StrictByteString -> IO (ChunkIOStream a) -> ChunkIOStream a
forall a.
StrictByteString -> IO (ChunkIOStream a) -> ChunkIOStream a
Yield1 (ForeignPtr Word8 -> Int -> StrictByteString
S.BS ForeignPtr Word8
fpbuf Int
chunkSize )(Bool -> IO (ChunkIOStream a)
mkCIOS Bool
False)wherechunkSize :: Int
chunkSize =Ptr Word8
op' Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr`Ptr Word8
pbuf size :: Int
size =Ptr Word8
pe Ptr Word8 -> Ptr Word8 -> Int
forall a b. Ptr a -> Ptr b -> Int
`minusPtr`Ptr Word8
pbuf 

AltStyle によって変換されたページ (->オリジナル) /