binary-parsers 0.1.0.0 → 0.2.0.0
raw patch · 19 files changed
+451/−41 lines, 19 filesdep +case-insensitivedep +http-typesPVP ok
version bump matches the API change (PVP)
Dependencies added: case-insensitive, http-types
API changes (from Hackage documentation)
- Data.Binary.Parser: infix 0 <?>
+ Data.Binary.Parser.Word8: endOfLine :: Get ()
Files
- ChangeLog.md +5/−2
- Data/Binary/Parser.hs +3/−2
- Data/Binary/Parser/Char8.hs +1/−1
- Data/Binary/Parser/Numeric.hs +9/−9
- Data/Binary/Parser/Word8.hs +14/−2
- README.md +21/−1
- bench/Aeson.hs +1/−7
- bench/AesonBP.hs +1/−10
- bench/Bench.hs +4/−0
- bench/Common.hs +43/−0
- bench/HttpReq.hs +84/−0
- bench/Network/Wai/Handler/Warp/ReadInt.hs +67/−0
- bench/Network/Wai/Handler/Warp/RequestHeader.hs +172/−0
- bench/http-request.txt +9/−0
- binary-parsers.cabal +9/−1
- tests/AesonBP.hs +0/−3
- tests/JSON.hs +1/−1
- tests/QC/ByteString.hs +7/−1
- tests/QC/Common.hs +0/−1
ChangeLog.md view
@@ -1,5 +1,8 @@ # Revision history for binary-parsec -## 0.1.0.0 -- YYYY-mm-dd+## 0.2.0.0 -- 2016-09-21 -* First version. Released on an unsuspecting world.+* Add `endOfLine` combinator.+* Add http request parsing benchmark.+* Fix a numeric parser bug.+* Fix wrong documents.
Data/Binary/Parser.hs view
@@ -33,6 +33,7 @@ -- count == replicateM -- atEnd == isEmpty -- take == getByteString+-- many1 == some -- @ -- -- For fast byte set operations, please use <http://hackage.haskell.org/package/charset charset>@@ -164,11 +165,11 @@ some_p = liftM2' (:) p many_p {-# INLINE many' #-} --- | @many1' p@ applies the action @p@ /one/ or more times. Returns a+-- | @some' p@ applies the action @p@ /one/ or more times. Returns a -- list of the returned values of @p@. The value returned by @p@ is -- forced to WHNF. ----- > word = many1' letter+-- > word = some' letter some' :: (MonadPlus m) => m a -> m [a] some' p = liftM2' (:) p (many' p) {-# INLINE some' #-}
Data/Binary/Parser/Char8.hs view
@@ -76,7 +76,7 @@ anyChar = w2c <$> BG.getWord8 {-# INLINE anyChar #-} --- | The parser @skip p@ succeeds for any char for which the predicate @p@ returns 'True'.+-- | The parser @skipChar p@ succeeds for any char for which the predicate @p@ returns 'True'. -- skipChar :: (Char -> Bool) -> Get () skipChar p = W.skipWord8 (p . w2c)
Data/Binary/Parser/Numeric.hs view
@@ -112,20 +112,20 @@ -- Examples with behaviour identical to 'read', if you feed an empty -- continuation to the first result: ----- >double "3" == Done 3.0 ""--- >double "3.1" == Done 3.1 ""--- >double "3e4" == Done 30000.0 ""--- >double "3.1e4" == Done 31000.0, ""+-- >runGetOrFail double "3" == Right ("",1,3.0)+-- >runGetOrFail double "3.1" == Right ("",3,3.1)+-- >runGetOrFail double "3e4" == Right ("",3,30000.0)+-- >runGetOrFail double "3.1e4" == Right ("",5,31000.0) -- -- Examples with behaviour identical to 'read': ----- >double ".3" == Fail "input does not start with a digit"--- >double "e3" == Fail "input does not start with a digit"+-- >runGetOrFail double ".3" == Left (".3",0,"takeWhile1")+-- >runGetOrFail double "e3" == Left ("e3",0,"takeWhile1") -- -- Examples of differences from 'read': ----- >double "3.foo" == Done 3.0 ".foo"--- >double "3e" == Done 3.0 "e"+-- >runGetOrFail double "3.foo" == Right (".foo",1,3.0)+-- >runGetOrFail double "3e" == Right ("e",1,3.0) -- -- This function does not accept string representations of \"NaN\" or -- \"Infinity\".@@ -154,7 +154,7 @@ intPart' = intPart * (10 ^ B.length fracDigits) fracPart = LexInt.readDecimal_ fracDigits parseE (intPart' + fracPart) e'- ) <|> (pure (Sci.scientific intPart 0))+ ) <|> (parseE intPart 0) if sign /= MINUS then return $! h sci else return $! h (negate sci) where
Data/Binary/Parser/Word8.hs view
@@ -107,7 +107,7 @@ anyWord8 = getWord8 {-# INLINE anyWord8 #-} --- | The parser @skip p@ succeeds for any byte for which the predicate @p@ returns 'True'.+-- | The parser @skipWord8 p@ succeeds for any byte for which the predicate @p@ returns 'True'. -- skipWord8 :: (Word8 -> Bool) -> Get () skipWord8 p = do@@ -148,7 +148,7 @@ put rest if B.null rest then do- e <- isEmpty+ e <- isEmpty -- isEmpty will draw input here if e then return acc' else go acc' else return acc' {-# INLINE takeTill #-}@@ -295,3 +295,15 @@ isEndOfLine :: Word8 -> Bool isEndOfLine w = w == 13 || w == 10 {-# INLINE isEndOfLine #-}++--------------------------------------------------------------------------------++-- | Match either a single newline byte @\'\\n\'@, or a carriage+-- return followed by a newline byte @\"\\r\\n\"@.+endOfLine :: Get ()+endOfLine = do+ w <- getWord8+ case w of+ 10 -> return ()+ 13 -> word8 10+ _ -> fail "endOfLine"
README.md view
@@ -32,7 +32,27 @@ --------- ```-Benchmark criterion: RUNNING...+benchmarking http-req/attoparsec+time 2.240 μs (2.216 μs .. 2.264 μs)+ 0.998 R² (0.996 R² .. 0.999 R²)+mean 2.320 μs (2.251 μs .. 2.702 μs)+std dev 417.9 ns (60.72 ns .. 1.012 μs)+variance introduced by outliers: 96% (severely inflated)++benchmarking http-req/binary-parsers+time 1.552 μs (1.533 μs .. 1.577 μs)+ 0.980 R² (0.942 R² .. 0.999 R²)+mean 1.673 μs (1.549 μs .. 1.984 μs)+std dev 583.2 ns (53.70 ns .. 1.115 μs)+variance introduced by outliers: 99% (severely inflated)++benchmarking http-req/warp+time 903.0 ns (894.7 ns .. 911.2 ns)+ 0.999 R² (0.998 R² .. 0.999 R²)+mean 906.6 ns (896.2 ns .. 918.4 ns)+std dev 36.38 ns (28.49 ns .. 51.58 ns)+variance introduced by outliers: 56% (severely inflated)+ benchmarking attoparsec/buffer-builder time 4.025 ms (3.965 ms .. 4.097 ms) 0.998 R² (0.997 R² .. 0.999 R²)
bench/Aeson.hs view
@@ -40,6 +40,7 @@ import qualified Data.ByteString.Unsafe as B import qualified Data.HashMap.Strict as H import Criterion.Main+import Common (pathTo) #define BACKSLASH 92 #define CLOSE_CURLY 125@@ -56,13 +57,6 @@ #define C_f 102 #define C_n 110 #define C_t 116--pathTo :: String -> IO FilePath-pathTo wat = do- exists <- doesDirectoryExist "bench"- return $ if exists- then "bench" </> wat- else wat data Result a = Error String | Success a
bench/AesonBP.hs view
@@ -33,14 +33,12 @@ import qualified Data.Attoparsec.Zepto as Z import Data.Binary.Get (Get) import qualified Data.Binary.Parser as BP-import qualified Data.Binary.Get as BG-import qualified Data.Binary.Parser.Word8 as BP-import qualified Data.Binary.Parser.Numeric as BP import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Unsafe as B import qualified Data.HashMap.Strict as H import Criterion.Main+import Common (pathTo) #define BACKSLASH 92 #define CLOSE_CURLY 125@@ -58,13 +56,6 @@ #define C_f 102 #define C_n 110 #define C_t 116--pathTo :: String -> IO FilePath-pathTo wat = do- exists <- doesDirectoryExist "bench"- return $ if exists- then "bench" </> wat- else wat data Result a = Error String | Success a
bench/Bench.hs view
@@ -5,10 +5,14 @@ import Criterion.Main import qualified Aeson import qualified AesonBP+import qualified HttpReq import Data.List main :: IO () main = do+ http <- HttpReq.headers+ defaultMain http+ aeson <- Aeson.aeson aesonbp <- AesonBP.aeson aesonLazy <- Aeson.aesonLazy
+ bench/Common.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE CPP #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Common (+ chunksOf+ , pathTo+ , rechunkBS+ , rechunkT+ ) where++import Control.DeepSeq (NFData(rnf))+import System.Directory (doesDirectoryExist)+import System.FilePath ((</>))+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+import qualified Data.Text as T+import qualified Data.Text.Lazy as TL++#if !MIN_VERSION_bytestring(0,10,0)+import Data.ByteString.Internal (ByteString(..))++instance NFData ByteString where+ rnf (PS _ _ _) = ()+#endif++chunksOf :: Int -> [a] -> [[a]]+chunksOf k = go+ where go xs = case splitAt k xs of+ ([],_) -> []+ (y, ys) -> y : go ys++rechunkBS :: Int -> B.ByteString -> BL.ByteString+rechunkBS n = BL.fromChunks . map B.pack . chunksOf n . B.unpack++rechunkT :: Int -> T.Text -> TL.Text+rechunkT n = TL.fromChunks . map T.pack . chunksOf n . T.unpack++pathTo :: String -> IO FilePath+pathTo wat = do+ exists <- doesDirectoryExist "bench"+ return $ if exists+ then "bench" </> wat+ else wat
+ bench/HttpReq.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}+module HttpReq (headers) where++import Common (pathTo, rechunkBS)+import Control.Applicative+import Criterion.Main (bench, bgroup, nf, nfIO)+import Control.DeepSeq (NFData(..))+import Criterion.Types (Benchmark)+import Network.Wai.Handler.Warp.RequestHeader (parseHeaderLines)+import qualified Data.Attoparsec.ByteString as AP+import qualified Data.Attoparsec.ByteString.Char8 as APC+import qualified Data.ByteString.Char8 as BC+import qualified Data.Binary.Parser as BP+import qualified Data.Binary.Parser.Char8 as BPC+import Network.HTTP.Types.Version (HttpVersion, http11)++headers :: IO [Benchmark]+headers = do+ req <- BC.readFile =<< pathTo "http-request.txt"+ return [+ bench "http-req/attoparsec" $ nf (AP.parseOnly attoRequest) req+ , bench "http-req/binary-parsers" $ nf (BP.parseOnly bpRequest) req+ , bench "http-req/warp" $ nfIO (parseHeaderLines (BC.lines req))+ ]++--------------------------------------------------------------------------------++instance NFData HttpVersion where+ rnf !_ = ()++attoHeader = do+ name <- APC.takeWhile1 (APC.inClass "a-zA-Z0-9_-") <* APC.char ':' <* APC.skipSpace+ body <- attoBodyLine+ return (name, body)++attoBodyLine = APC.takeTill (\c -> c == '\r' || c == '\n') <* APC.endOfLine++attoReqLine = do+ m <- (APC.takeTill APC.isSpace <* APC.char ' ')+ (p,q) <- BC.break (=='?') <$> (APC.takeTill APC.isSpace <* APC.char ' ')+ v <- attoHttpVersion+ return (m,p,q,v)++attoHttpVersion = http11 <$ APC.string "HTTP/1.1"++attoRequest = (,) <$> (attoReqLine <* APC.endOfLine) <*> attoManyHeader++attoManyHeader = do+ c <- APC.peekChar'+ if c == '\r' || c == '\n'+ then return []++ else (:) <$> attoHeader <*> attoManyHeader++--------------------------------------------------------------------------------++bpHeader = do+ name <- BPC.takeWhile1 isHeaderChar <* BPC.char ':' <* BP.skipSpaces+ body <- bpBodyLine+ return (name, body)+ where+ isHeaderChar c = ('a' <= c && c <= 'z')+ || ('A' <= c && c <= 'Z')+ || ('0' <= c && c <= '0')+ || c == '_' || c == '-'++bpBodyLine = BPC.takeTill (\c -> c == '\r' || c == '\n') <* BP.satisfy BP.isEndOfLine++bpReqLine = do+ m <- (BPC.takeTill BPC.isSpace <* BPC.char ' ')+ (p,q) <- BC.break (=='?') <$> (BPC.takeTill BPC.isSpace <* BPC.char ' ')+ v <- bpHttpVersion+ return (m,p,q,v)++bpHttpVersion = http11 <$ BP.string "HTTP/1.1"++bpRequest = (,) <$> (bpReqLine <* BP.satisfy BP.isEndOfLine) <*> bpManyHeader++bpManyHeader = do+ c <- BPC.peek+ if c == '\r' || c == '\n'+ then return []+ else (:) <$> bpHeader <*> bpManyHeader
+ bench/Network/Wai/Handler/Warp/ReadInt.hs view
@@ -0,0 +1,67 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE BangPatterns #-}++-- Copyright : Erik de Castro Lopo <erikd@mega-nerd.com>+-- License : BSD3++module Network.Wai.Handler.Warp.ReadInt (+ readInt+ , readInt64+ ) where++-- This function lives in its own file because the MagicHash pragma interacts+-- poorly with the CPP pragma.++import Data.ByteString (ByteString)+import qualified Data.ByteString as S+import Data.Int (Int64)+import GHC.Prim+import GHC.Types+import GHC.Word++{-# INLINE readInt #-}+readInt :: Integral a => ByteString -> a+readInt bs = fromIntegral $ readInt64 bs++-- This function is used to parse the Content-Length field of HTTP headers and+-- is a performance hot spot. It should only be replaced with something+-- significantly and provably faster.+--+-- It needs to be able work correctly on 32 bit CPUs for file sizes > 2G so we+-- use Int64 here and then make a generic 'readInt' that allows conversion to+-- Int and Integer.++{-# NOINLINE readInt64 #-}+readInt64 :: ByteString -> Int64+readInt64 bs = S.foldl' (\ !i !c -> i * 10 + fromIntegral (mhDigitToInt c)) 0+ $ S.takeWhile isDigit bs++data Table = Table !Addr#++{-# NOINLINE mhDigitToInt #-}+mhDigitToInt :: Word8 -> Int+mhDigitToInt (W8# i) = I# (word2Int# (indexWord8OffAddr# addr (word2Int# i)))+ where+ !(Table addr) = table+ table :: Table+ table = Table+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\+ \\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"#++isDigit :: Word8 -> Bool+isDigit w = w >= 48 && w <= 57
+ bench/Network/Wai/Handler/Warp/RequestHeader.hs view
@@ -0,0 +1,172 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BangPatterns #-}++module Network.Wai.Handler.Warp.RequestHeader (+ parseHeaderLines+ , parseByteRanges+ ) where++import Control.Exception (Exception, throwIO)+import Control.Monad (when)+import Data.Typeable (Typeable)+import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as B (unpack, readInteger)+import Data.ByteString.Internal (ByteString(..), memchr)+import qualified Data.CaseInsensitive as CI+import Data.Word (Word8)+import Foreign.ForeignPtr (withForeignPtr)+import Foreign.Ptr (Ptr, plusPtr, minusPtr, nullPtr)+import Foreign.Storable (peek)+import qualified Network.HTTP.Types as H+-- import Network.Wai.Handler.Warp.Types+import qualified Network.HTTP.Types.Header as HH+-- $setup+-- >>> :set -XOverloadedStrings++data InvalidRequest = NotEnoughLines [String]+ | BadFirstLine String+ | NonHttp+ | IncompleteHeaders+ | ConnectionClosedByPeer+ | OverLargeHeader+ deriving (Eq, Typeable, Show)++instance Exception InvalidRequest++----------------------------------------------------------------++parseHeaderLines :: [ByteString]+ -> IO (H.Method+ ,ByteString -- Path+ ,ByteString -- Path, parsed+ ,ByteString -- Query+ ,H.HttpVersion+ ,H.RequestHeaders+ )+parseHeaderLines [] = throwIO $ NotEnoughLines []+parseHeaderLines (firstLine:otherLines) = do+ (method, path', query, httpversion) <- parseRequestLine firstLine+ let path = H.extractPath path'+ hdr = map parseHeader otherLines+ return (method, path', path, query, httpversion, hdr)++----------------------------------------------------------------++-- |+--+-- >>> parseRequestLine "GET / HTTP/1.1"+-- ("GET","/","",HTTP/1.1)+-- >>> parseRequestLine "POST /cgi/search.cgi?key=foo HTTP/1.0"+-- ("POST","/cgi/search.cgi","?key=foo",HTTP/1.0)+-- >>> parseRequestLine "GET "+-- *** Exception: Warp: Invalid first line of request: "GET "+-- >>> parseRequestLine "GET /NotHTTP UNKNOWN/1.1"+-- *** Exception: Warp: Request line specified a non-HTTP request+parseRequestLine :: ByteString+ -> IO (H.Method+ ,ByteString -- Path+ ,ByteString -- Query+ ,H.HttpVersion)+parseRequestLine requestLine@(PS fptr off len) = withForeignPtr fptr $ \ptr -> do+ when (len < 14) $ throwIO baderr+ let methodptr = ptr `plusPtr` off+ limptr = methodptr `plusPtr` len+ lim0 = fromIntegral len++ pathptr0 <- memchr methodptr 32 lim0 -- ' '+ when (pathptr0 == nullPtr || (limptr `minusPtr` pathptr0) < 11) $+ throwIO baderr+ let pathptr = pathptr0 `plusPtr` 1+ lim1 = fromIntegral (limptr `minusPtr` pathptr0)++ httpptr0 <- memchr pathptr 32 lim1 -- ' '+ when (httpptr0 == nullPtr || (limptr `minusPtr` httpptr0) < 9) $+ throwIO baderr+ let httpptr = httpptr0 `plusPtr` 1+ lim2 = fromIntegral (httpptr0 `minusPtr` pathptr)++ checkHTTP httpptr+ !hv <- httpVersion httpptr+ queryptr <- memchr pathptr 63 lim2 -- '?'++ let !method = bs ptr methodptr pathptr0+ !path+ | queryptr == nullPtr = bs ptr pathptr httpptr0+ | otherwise = bs ptr pathptr queryptr+ !query+ | queryptr == nullPtr = S.empty+ | otherwise = bs ptr queryptr httpptr0++ return (method,path,query,hv)+ where+ baderr = BadFirstLine $ B.unpack requestLine+ check :: Ptr Word8 -> Int -> Word8 -> IO ()+ check p n w = do+ w0 <- peek $ p `plusPtr` n+ when (w0 /= w) $ throwIO NonHttp+ checkHTTP httpptr = do+ check httpptr 0 72 -- 'H'+ check httpptr 1 84 -- 'T'+ check httpptr 2 84 -- 'T'+ check httpptr 3 80 -- 'P'+ check httpptr 4 47 -- '/'+ check httpptr 6 46 -- '.'+ httpVersion httpptr = do+ major <- peek $ httpptr `plusPtr` 5+ minor <- peek $ httpptr `plusPtr` 7+ return $ if major == (49 :: Word8) && minor == (49 :: Word8) then+ H.http11+ else+ H.http10+ bs ptr p0 p1 = PS fptr o l+ where+ o = p0 `minusPtr` ptr+ l = p1 `minusPtr` p0++----------------------------------------------------------------++-- |+--+-- >>> parseHeader "Content-Length:47"+-- ("Content-Length","47")+-- >>> parseHeader "Accept-Ranges: bytes"+-- ("Accept-Ranges","bytes")+-- >>> parseHeader "Host: example.com:8080"+-- ("Host","example.com:8080")+-- >>> parseHeader "NoSemiColon"+-- ("NoSemiColon","")++parseHeader :: ByteString -> H.Header+parseHeader s =+ let (k, rest) = S.break (== 58) s -- ':'+ rest' = S.dropWhile (\c -> c == 32 || c == 9) $ S.drop 1 rest+ in (CI.mk k, rest')++parseByteRanges :: S.ByteString -> Maybe HH.ByteRanges+parseByteRanges bs1 = do+ bs2 <- stripPrefix "bytes=" bs1+ (r, bs3) <- range bs2+ ranges (r:) bs3+ where+ range bs2 =+ case stripPrefix "-" bs2 of+ Just bs3 -> do+ (i, bs4) <- B.readInteger bs3+ Just (HH.ByteRangeSuffix i, bs4)+ Nothing -> do+ (i, bs3) <- B.readInteger bs2+ bs4 <- stripPrefix "-" bs3+ case B.readInteger bs4 of+ Nothing -> Just (HH.ByteRangeFrom i, bs4)+ Just (j, bs5) -> Just (HH.ByteRangeFromTo i j, bs5)+ ranges front bs3 =+ case stripPrefix "," bs3 of+ Nothing -> Just (front [])+ Just bs4 -> do+ (r, bs5) <- range bs4+ ranges (front . (r:)) bs5++ stripPrefix x y+ | x `S.isPrefixOf` y = Just (S.drop (S.length x) y)+ | otherwise = Nothing
+ bench/http-request.txt view
@@ -0,0 +1,9 @@+GET / HTTP/1.1+Host: twitter.com+Accept: text/html, application/xhtml+xml, application/xml; q=0.9, image/webp, */*; q=0.8+Accept-Encoding: gzip,deflate,sdch+Accept-Language: en-GB,en-US;q=0.8,en;q=0.6+Cache-Control: max-age=0+Cookie: guest_id=v1%3A139; _twitter_sess=BAh7CSIKZmxhc2hJQz-e1e1; __utma=43838368.452555194.1399611824.1; __utmb=43838368; __utmc=43838368; __utmz=1399611824.1.1.utmcsr=(direct)|utmcmd=(none)+User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.86 Safari/537.36+
binary-parsers.cabal view
@@ -1,5 +1,5 @@ name: binary-parsers-version: 0.1.0.0+version: 0.2.0.0 synopsis: Extends binary with parsec/attoparsec style parsing combinators. description: Extends binary with parsec/attoparsec style parsing combinators. license: BSD3@@ -13,6 +13,7 @@ , README.md , bench/json-data/*.json , tests/json-data/*.json+ , bench/http-request.txt cabal-version: >=1.10 homepage: https://github.com/winterland1989/binary-parsers@@ -40,6 +41,11 @@ benchmark criterion other-modules: Aeson , AesonBP+ , Common+ , HttpReq+ , Network.Wai.Handler.Warp.ReadInt+ , Network.Wai.Handler.Warp.RequestHeader+ build-depends: base , deepseq , bytestring@@ -53,6 +59,8 @@ , directory , filepath , unordered-containers+ , http-types+ , case-insensitive default-language: Haskell2010 hs-source-dirs: bench
tests/AesonBP.hs view
@@ -28,9 +28,6 @@ import qualified Data.Attoparsec.Zepto as Z import Data.Binary.Get (Get) import qualified Data.Binary.Parser as BP-import qualified Data.Binary.Get as BG-import qualified Data.Binary.Parser.Word8 as BP-import qualified Data.Binary.Parser.Numeric as BP import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Unsafe as B
tests/JSON.hs view
@@ -6,7 +6,7 @@ import Test.Tasty.HUnit import Test.Tasty (TestTree) import System.Directory (getDirectoryContents, doesDirectoryExist)-import System.FilePath ((</>), dropExtension)+import System.FilePath ((</>)) import qualified Aeson as A import qualified Data.Attoparsec.ByteString as A import qualified AesonBP as B
tests/QC/ByteString.hs view
@@ -126,7 +126,7 @@ endOfLine :: L.ByteString -> Property endOfLine s =- case (parseBS (P.satisfy P.isEndOfLine) s, L8.uncons s) of+ case (parseBS P.endOfLine s, L8.uncons s) of (Nothing, mcs) -> maybe (property True) (expectFailure . eol) mcs (Just _, mcs) -> maybe (property False) eol mcs where eol (c,s') = c === '\n' .||.@@ -137,6 +137,11 @@ where p = P.scan k $ \ n _ -> if n > 0 then let !n' = n - 1 in Just n' else Nothing +decimal :: Integer -> Property+decimal d =+ let dBS = BB.toLazyByteString $ BB.integerDec d+ in parseBS (P.signed P.decimal) dBS === Just d+ double :: Double -> Property double d = let dBS = BB.toLazyByteString $ BB.doubleDec d@@ -170,6 +175,7 @@ , testProperty "takeWhile1" takeWhile1 , testProperty "takeWhile1_empty" takeWhile1_empty , testProperty "word8" word8+ , testProperty "decimal" decimal , testProperty "double" double , testProperty "scientific" scientific ]
tests/QC/Common.hs view
@@ -17,7 +17,6 @@ #endif import Data.Char (isAlpha) import Test.QuickCheck-import Test.QuickCheck.Unicode (shrinkChar, string) import Test.QuickCheck.Instances () import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as BL