diff options
author | joe <joe@jerkface.net> | 2017-01-18 20:13:45 -0500 |
---|---|---|
committer | joe <joe@jerkface.net> | 2017-01-18 20:13:45 -0500 |
commit | a4359d2c67811e71368524d17aeb3809dae657da (patch) | |
tree | e3e240de09b6b446a6e8ee38429aa23ef1ef396d | |
parent | 27957be6c747a9ce4a98273e0099f15dd1a6f163 (diff) |
Backported to older bytestring.
-rw-r--r-- | bencoding.cabal | 20 | ||||
-rw-r--r-- | src/Data/BEncode/Internal.hs | 57 | ||||
-rw-r--r-- | src/Data/BEncode/Types.hs | 6 | ||||
-rw-r--r-- | tests/properties.hs | 7 |
4 files changed, 66 insertions, 24 deletions
diff --git a/bencoding.cabal b/bencoding.cabal index c6fa2af..eddcd53 100644 --- a/bencoding.cabal +++ b/bencoding.cabal | |||
@@ -19,6 +19,10 @@ description: | |||
19 | extra-source-files: README.md | 19 | extra-source-files: README.md |
20 | , ChangeLog | 20 | , ChangeLog |
21 | 21 | ||
22 | flag builder | ||
23 | description: Use older bytestring package and bytestring-builder. | ||
24 | default: False | ||
25 | |||
22 | source-repository head | 26 | source-repository head |
23 | type: git | 27 | type: git |
24 | location: git://github.com/cobit/bencoding.git | 28 | location: git://github.com/cobit/bencoding.git |
@@ -41,15 +45,16 @@ library | |||
41 | build-depends: base == 4.* | 45 | build-depends: base == 4.* |
42 | , ghc-prim | 46 | , ghc-prim |
43 | , integer-gmp | 47 | , integer-gmp |
44 | , deepseq == 1.3.* | 48 | , deepseq >= 1.3 |
45 | |||
46 | , mtl | 49 | , mtl |
47 | |||
48 | , attoparsec >= 0.10 | 50 | , attoparsec >= 0.10 |
49 | , bytestring >= 0.10 | ||
50 | , text >= 0.11 | 51 | , text >= 0.11 |
51 | , pretty | 52 | , pretty |
52 | ghc-options: -Wall -O2 -fno-warn-unused-do-bind | 53 | ghc-options: -Wall -O2 -fno-warn-unused-do-bind |
54 | if flag(builder) | ||
55 | build-depends: bytestring >= 0.9, bytestring-builder | ||
56 | else | ||
57 | build-depends: bytestring >= 0.10 | ||
53 | 58 | ||
54 | 59 | ||
55 | test-suite properties | 60 | test-suite properties |
@@ -61,12 +66,15 @@ test-suite properties | |||
61 | , ghc-prim | 66 | , ghc-prim |
62 | 67 | ||
63 | , containers >= 0.4 | 68 | , containers >= 0.4 |
64 | , bytestring >= 0.10 | ||
65 | , attoparsec >= 0.10 | 69 | , attoparsec >= 0.10 |
66 | 70 | ||
67 | , bencoding | 71 | , bencoding |
68 | , hspec | 72 | , hspec |
69 | , QuickCheck | 73 | , QuickCheck |
74 | if flag(builder) | ||
75 | build-depends: bytestring >= 0.9, bytestring-builder | ||
76 | else | ||
77 | build-depends: bytestring >= 0.10 | ||
70 | 78 | ||
71 | ghc-options: -Wall -fno-warn-orphans | 79 | ghc-options: -Wall -fno-warn-orphans |
72 | 80 | ||
@@ -81,7 +89,7 @@ benchmark bench-comparison | |||
81 | , deepseq | 89 | , deepseq |
82 | 90 | ||
83 | , attoparsec >= 0.10 | 91 | , attoparsec >= 0.10 |
84 | , bytestring >= 0.10 | 92 | , bytestring >= 0.9 |
85 | 93 | ||
86 | , criterion | 94 | , criterion |
87 | 95 | ||
diff --git a/src/Data/BEncode/Internal.hs b/src/Data/BEncode/Internal.hs index e5ba89c..1532fe6 100644 --- a/src/Data/BEncode/Internal.hs +++ b/src/Data/BEncode/Internal.hs | |||
@@ -9,6 +9,7 @@ | |||
9 | -- don't need to import this module, use 'Data.BEncode' instead. | 9 | -- don't need to import this module, use 'Data.BEncode' instead. |
10 | -- | 10 | -- |
11 | {-# LANGUAGE MagicHash #-} | 11 | {-# LANGUAGE MagicHash #-} |
12 | {-# LANGUAGE CPP #-} | ||
12 | module Data.BEncode.Internal | 13 | module Data.BEncode.Internal |
13 | ( -- * Parsing | 14 | ( -- * Parsing |
14 | parser | 15 | parser |
@@ -26,12 +27,20 @@ import qualified Data.Attoparsec.ByteString.Char8 as P | |||
26 | import Data.ByteString as B | 27 | import Data.ByteString as B |
27 | import Data.ByteString.Internal as B (c2w, w2c) | 28 | import Data.ByteString.Internal as B (c2w, w2c) |
28 | import qualified Data.ByteString.Lazy as Lazy | 29 | import qualified Data.ByteString.Lazy as Lazy |
30 | #if MIN_VERSION_bytestring(0,10,0) | ||
29 | import qualified Data.ByteString.Lazy.Builder as B | 31 | import qualified Data.ByteString.Lazy.Builder as B |
30 | import qualified Data.ByteString.Lazy.Builder.ASCII as B | 32 | import qualified Data.ByteString.Lazy.Builder.ASCII as B |
33 | #else | ||
34 | import qualified Data.ByteString.Builder as B | ||
35 | -- import qualified Data.ByteString.Builder.ASCII as B | ||
36 | -- import qualified Data.ByteString.Builder.Internal as B | ||
37 | #endif | ||
31 | import Data.Foldable | 38 | import Data.Foldable |
32 | import Data.List as L | 39 | import Data.List as L |
33 | import Data.Monoid | 40 | import Data.Monoid |
34 | import Text.PrettyPrint hiding ((<>)) | 41 | import Text.PrettyPrint hiding ((<>)) |
42 | import Data.Char | ||
43 | import Data.Maybe | ||
35 | 44 | ||
36 | import Data.BEncode.Types | 45 | import Data.BEncode.Types |
37 | import Data.BEncode.BDict as BD | 46 | import Data.BEncode.BDict as BD |
@@ -74,6 +83,9 @@ builder = go | |||
74 | build :: BValue -> Lazy.ByteString | 83 | build :: BValue -> Lazy.ByteString |
75 | build = B.toLazyByteString . builder | 84 | build = B.toLazyByteString . builder |
76 | 85 | ||
86 | |||
87 | sample = "lld10:xOo@-ovQ\b}i8eeded12:]\ENQ89gJp\DC1Y\t!]17:\SOHRQ8\DLE\ESC\NULiUSRo\t.M<gei18eldede8:VX^ejm\SO_d12:.J*\DLEIc\SIV\ESCun\SOHdeede8:tg!\"lU\SOH\DEL1:Pe16:X\EMk\ESCGaek)\DC4'\t+\ESChhei-7e16:<OJ\v9\".i;\DC4[=]_D9de16:$-giCtwedm!\CAN\aA\DC3{dee" | ||
88 | |||
77 | {-------------------------------------------------------------------- | 89 | {-------------------------------------------------------------------- |
78 | -- Deserialization | 90 | -- Deserialization |
79 | --------------------------------------------------------------------} | 91 | --------------------------------------------------------------------} |
@@ -81,45 +93,56 @@ build = B.toLazyByteString . builder | |||
81 | -- TODO try to replace peekChar with something else | 93 | -- TODO try to replace peekChar with something else |
82 | -- | BEncode format parser according to specification. | 94 | -- | BEncode format parser according to specification. |
83 | parser :: Parser BValue | 95 | parser :: Parser BValue |
84 | parser = valueP | 96 | parser = valueP Nothing |
85 | where | 97 | where |
86 | valueP = do | 98 | valueP prior = do |
87 | mc <- P.peekChar | 99 | mc <- maybe (optional P.anyChar) (return . Just) prior |
88 | case mc of | 100 | case mc of |
89 | Nothing -> fail "end of input" | 101 | Nothing -> fail "end of input" |
90 | Just c -> | 102 | Just c -> |
91 | case c of | 103 | case c of |
92 | -- if we have digit it always should be string length | 104 | -- if we have digit it always should be string length |
93 | di | di <= '9' -> BString <$> stringP | 105 | di | '0' <= di && di <= '9' -> BString <$> stringP c |
94 | 'i' -> P.anyChar *> ((BInteger <$> integerP) <* P.anyChar) | 106 | 'i' -> ((BInteger <$> integerP) <* P.char 'e') -- P.anyChar) |
95 | 'l' -> P.anyChar *> ((BList <$> listBodyP) <* P.anyChar) | 107 | 'l' -> ((BList <$> listBodyP) ) -- <* P.anyChar) |
96 | 'd' -> P.anyChar *> (BDict <$> dictBodyP) <* P.anyChar | 108 | 'd' -> (BDict <$> dictBodyP) -- <* P.anyChar |
97 | t -> fail ("bencode unknown tag: " ++ [t]) | 109 | t -> fail ("bencode unknown tag: " ++ [t]) |
98 | 110 | ||
99 | dictBodyP :: Parser BDict | 111 | dictBodyP :: Parser BDict |
100 | dictBodyP = Cons <$> stringP <*> valueP <*> dictBodyP | 112 | dictBodyP = |
101 | <|> pure Nil | 113 | (P.char 'e' *> pure Nil) |
114 | <|> do c <- P.satisfy isDigit -- P.anyChar | ||
115 | Cons <$> stringP c <*> valueP Nothing <*> dictBodyP | ||
102 | 116 | ||
103 | listBodyP = do | 117 | listBodyP = do |
104 | c <- P.peekChar | 118 | c <- optional P.anyChar |
105 | case c of | 119 | case c of |
106 | Just 'e' -> return [] | 120 | Just 'e' -> return [] |
107 | _ -> (:) <$> valueP <*> listBodyP | 121 | _ -> (:) <$> valueP c <*> listBodyP |
108 | 122 | ||
109 | stringP :: Parser ByteString | 123 | leadingDigit c zeros n0 |
110 | stringP = do | 124 | | n0==(-10) = d * 10^(fromIntegral (B.length zeros)) |
111 | n <- P.decimal :: Parser Int | 125 | | n0/=0 = d * 10^(fromIntegral (B.length zeros) + truncate (1+logBase 10 (fromIntegral n0))) + n0 |
126 | | otherwise = d * 10 | ||
127 | where d = fromIntegral $ ord c - 48 | ||
128 | |||
129 | stringP :: Char -> Parser ByteString | ||
130 | stringP c = do | ||
131 | zeros <- P.takeWhile (=='0') | ||
132 | n0 <- (P.decimal <|> pure (-10)) :: Parser Int | ||
133 | let n = leadingDigit c zeros n0 | ||
112 | P.char ':' | 134 | P.char ':' |
113 | P.take n | 135 | P.take n |
114 | {-# INLINE stringP #-} | 136 | {-# INLINE stringP #-} |
115 | 137 | ||
116 | integerP :: Parser Integer | 138 | integerP :: Parser Integer |
117 | integerP = do | 139 | integerP = do |
118 | c <- P.peekChar | 140 | c <- optional P.anyChar |
119 | case c of | 141 | case c of |
120 | Just '-' -> do | 142 | Just '-' -> do |
121 | P.anyChar | ||
122 | negate <$> P.decimal | 143 | negate <$> P.decimal |
144 | Just c' -> do zeros <- P.takeWhile (=='0') | ||
145 | leadingDigit c' zeros <$> (P.decimal <|> pure (-10)) | ||
123 | _ -> P.decimal | 146 | _ -> P.decimal |
124 | {-# INLINE integerP #-} | 147 | {-# INLINE integerP #-} |
125 | 148 | ||
diff --git a/src/Data/BEncode/Types.hs b/src/Data/BEncode/Types.hs index 15f570f..c1e1f01 100644 --- a/src/Data/BEncode/Types.hs +++ b/src/Data/BEncode/Types.hs | |||
@@ -7,6 +7,7 @@ | |||
7 | -- | 7 | -- |
8 | -- Types for working with bencode data. | 8 | -- Types for working with bencode data. |
9 | -- | 9 | -- |
10 | {-# LANGUAGE CPP #-} | ||
10 | module Data.BEncode.Types | 11 | module Data.BEncode.Types |
11 | ( -- * Types | 12 | ( -- * Types |
12 | BInteger | 13 | BInteger |
@@ -51,6 +52,11 @@ data BValue | |||
51 | | BDict BDict -- ^ bencode key-value dictionary. | 52 | | BDict BDict -- ^ bencode key-value dictionary. |
52 | deriving (Show, Read, Eq, Ord) | 53 | deriving (Show, Read, Eq, Ord) |
53 | 54 | ||
55 | #if !MIN_VERSION_bytestring(0,10,0) | ||
56 | instance NFData ByteString where | ||
57 | rnf s = seq s () | ||
58 | #endif | ||
59 | |||
54 | instance NFData BValue where | 60 | instance NFData BValue where |
55 | rnf (BInteger i) = rnf i | 61 | rnf (BInteger i) = rnf i |
56 | rnf (BString s) = rnf s | 62 | rnf (BString s) = rnf s |
diff --git a/tests/properties.hs b/tests/properties.hs index 876b954..478dd8c 100644 --- a/tests/properties.hs +++ b/tests/properties.hs | |||
@@ -1,4 +1,5 @@ | |||
1 | {-# LANGUAGE DeriveGeneric #-} | 1 | {-# LANGUAGE DeriveGeneric #-} |
2 | {-# LANGUAGE CPP #-} | ||
2 | {-# OPTIONS -fno-warn-unused-binds #-} | 3 | {-# OPTIONS -fno-warn-unused-binds #-} |
3 | module Main (main) where | 4 | module Main (main) where |
4 | 5 | ||
@@ -55,8 +56,12 @@ instance Arbitrary FileInfo where | |||
55 | 56 | ||
56 | data T a = T | 57 | data T a = T |
57 | 58 | ||
59 | #if !MIN_VERSION_bytestring(0,10,0) | ||
60 | toStrict bs = BS.concat $ BL.toChunks bs | ||
61 | #endif | ||
62 | |||
58 | prop_bencodable :: Eq a => BEncode a => T a -> a -> Bool | 63 | prop_bencodable :: Eq a => BEncode a => T a -> a -> Bool |
59 | prop_bencodable _ x = decode (BL.toStrict (encode x)) == Right x | 64 | prop_bencodable _ x = decode (toStrict (encode x)) == Right x |
60 | 65 | ||
61 | main :: IO () | 66 | main :: IO () |
62 | main = hspec $ do | 67 | main = hspec $ do |