{-# LANGUAGE BangPatterns , ScopedTypeVariables , UnicodeSyntax #-} -- |This is an auxiliary parser utilities. You usually don't have to -- use this module directly. module Network.HTTP.Lucu.Parser ( atMost , manyOctetsTill ) where import Blaze.ByteString.Builder (Builder, Write) import qualified Blaze.ByteString.Builder as BB import qualified Blaze.ByteString.Builder.Internal as BI import Control.Applicative import Control.Applicative.Unicode hiding ((∅)) import Control.Monad.Unicode import qualified Data.ByteString as BS import qualified Data.ByteString.Lazy as LS import Data.Monoid import Data.Monoid.Unicode import Data.Word import Prelude.Unicode -- |@'atMost' n v@ is like @'P.many' v@ but accumulates @v@ at most -- @n@ times. atMost ∷ Alternative f ⇒ Int → f a → f [a] {-# INLINE atMost #-} atMost 0 _ = pure [] atMost n v = ( (:) <$> v ⊛ atMost (n-1) v ) <|> pure [] data OctetAccumState = OctetAccumState { casChunks ∷ !Builder , casLastChunk ∷ !Write } instance Monoid OctetAccumState where {-# INLINE mempty #-} mempty = OctetAccumState { casChunks = (∅) , casLastChunk = (∅) } {-# INLINEABLE mappend #-} mappend !a !b = b { casChunks = casChunks a ⊕ lastChunk a ⊕ casChunks b } lastChunk ∷ OctetAccumState → Builder {-# INLINEABLE lastChunk #-} lastChunk !s = case toChunk s of c → BB.insertByteString c where toChunk ∷ OctetAccumState → BS.ByteString {-# INLINE toChunk #-} toChunk = BB.toByteString ∘ BB.fromWrite ∘ casLastChunk snoc ∷ OctetAccumState → Word8 → OctetAccumState {-# INLINEABLE snoc #-} snoc !s !o | BI.getBound (casLastChunk s) ≥ BI.defaultBufferSize = s { casChunks = casChunks s ⊕ lastChunk s , casLastChunk = BB.writeWord8 o } | otherwise = s { casLastChunk = casLastChunk s ⊕ BB.writeWord8 o } finish ∷ OctetAccumState → LS.ByteString {-# INLINEABLE finish #-} finish = BB.toLazyByteString ∘ toChunks where toChunks ∷ OctetAccumState → Builder {-# INLINE toChunks #-} toChunks !s = casChunks s ⊕ lastChunk s -- |@'manyOctetsTill' p end@ takes as many octets untill @p@ succeeds. manyOctetsTill ∷ ∀m b. (Monad m, Alternative m) ⇒ m Word8 → m b → m LS.ByteString {-# INLINEABLE manyOctetsTill #-} manyOctetsTill p end = scan (∅) where scan ∷ OctetAccumState → m LS.ByteString {-# INLINE scan #-} scan !s = (end *> pure (finish s)) <|> (scan =≪ (snoc s <$> p))