diff options
-rw-r--r-- | src/Data/BEncode.hs | 67 |
1 files changed, 59 insertions, 8 deletions
diff --git a/src/Data/BEncode.hs b/src/Data/BEncode.hs index d2cc144..4a80e47 100644 --- a/src/Data/BEncode.hs +++ b/src/Data/BEncode.hs | |||
@@ -1,28 +1,36 @@ | |||
1 | -- | This module is intented to be imported qualified. | 1 | -- | This module is intented to be imported qualified. |
2 | {-# LANGUAGE FlexibleInstances #-} | 2 | {-# LANGUAGE FlexibleInstances #-} |
3 | module Data.BEncode | 3 | module Data.BEncode |
4 | ( -- ^ Datatype | 4 | ( -- * Datatype |
5 | BEncode(..) | 5 | BEncode(..) |
6 | 6 | ||
7 | -- ^ Construction && Destructuring | 7 | -- * Construction && Destructuring |
8 | , BEncodable (..), dictAssoc | 8 | , BEncodable (..), dictAssoc, Result |
9 | 9 | ||
10 | -- ^ Serialization | 10 | -- ** Dictionaries |
11 | -- *** Building | ||
12 | , (-->), (-->?), fromAssocs, fromAscAssocs | ||
13 | |||
14 | -- *** Extraction | ||
15 | , reqKey, optKey, (>--), (>--?) | ||
16 | |||
17 | -- * Serialization | ||
11 | , encode, decode | 18 | , encode, decode |
12 | 19 | ||
13 | -- ^ Extra | 20 | -- * Extra |
14 | , builder, parser, printPretty | 21 | , builder, parser, decodingError, printPretty |
15 | 22 | ||
16 | -- ^ Predicates | 23 | -- * Predicates |
17 | , isInteger, isString, isList, isDict | 24 | , isInteger, isString, isList, isDict |
18 | ) where | 25 | ) where |
19 | 26 | ||
20 | 27 | ||
21 | import Control.Applicative | 28 | import Control.Applicative |
22 | import Data.Int | 29 | import Data.Int |
30 | import Data.Maybe (mapMaybe) | ||
31 | import Data.Monoid ((<>)) | ||
23 | import Data.Foldable (foldMap) | 32 | import Data.Foldable (foldMap) |
24 | import Data.Traversable (traverse) | 33 | import Data.Traversable (traverse) |
25 | import Data.Monoid ((<>)) | ||
26 | import Data.Map (Map) | 34 | import Data.Map (Map) |
27 | import qualified Data.Map as M | 35 | import qualified Data.Map as M |
28 | import Data.Attoparsec.ByteString.Char8 (Parser) | 36 | import Data.Attoparsec.ByteString.Char8 (Parser) |
@@ -142,7 +150,50 @@ dictAssoc :: [(ByteString, BEncode)] -> BEncode | |||
142 | dictAssoc = BDict . M.fromList | 150 | dictAssoc = BDict . M.fromList |
143 | {-# INLINE dictAssoc #-} | 151 | {-# INLINE dictAssoc #-} |
144 | 152 | ||
153 | ------------------------------------- Building dictionaries -------------------- | ||
154 | data Assoc = Required ByteString BEncode | ||
155 | | Optional ByteString (Maybe BEncode) | ||
145 | 156 | ||
157 | (-->) :: BEncodable a => ByteString -> a -> Assoc | ||
158 | key --> val = Required key (toBEncode val) | ||
159 | {-# INLINE (-->) #-} | ||
160 | |||
161 | (-->?) :: BEncodable a => ByteString -> Maybe a -> Assoc | ||
162 | key -->? mval = Optional key (toBEncode <$> mval) | ||
163 | {-# INLINE (-->?) #-} | ||
164 | |||
165 | fromAssocs :: [Assoc] -> BEncode | ||
166 | fromAssocs = BDict . M.fromList . mapMaybe unpackAssoc | ||
167 | where | ||
168 | unpackAssoc (Required n v) = Just (n, v) | ||
169 | unpackAssoc (Optional n (Just v)) = Just (n, v) | ||
170 | unpackAssoc (Optional _ Nothing) = Nothing | ||
171 | |||
172 | -- | A faster version of 'fromAssocs'. | ||
173 | -- Should be used only when keys are sorted by ascending. | ||
174 | fromAscAssocs :: [Assoc] -> BEncode | ||
175 | fromAscAssocs = error "fromAscAssocs" | ||
176 | |||
177 | ------------------------------------ Extraction -------------------------------- | ||
178 | reqKey :: BEncodable a => Map ByteString BEncode -> ByteString -> Result a | ||
179 | reqKey d key | ||
180 | | Just b <- M.lookup key d = fromBEncode b | ||
181 | | otherwise = Left ("required field `" ++ show key ++ " not found") | ||
182 | |||
183 | optKey :: BEncodable a => Map ByteString BEncode -> ByteString -> Result (Maybe a) | ||
184 | optKey d key | ||
185 | | Just b <- M.lookup key d = Just <$> fromBEncode b | ||
186 | | otherwise = return Nothing | ||
187 | |||
188 | (>--) :: BEncodable a => Map ByteString BEncode -> ByteString -> Result a | ||
189 | (>--) = reqKey | ||
190 | {-# INLINE (>--) #-} | ||
191 | |||
192 | (>--?) :: BEncodable a => Map ByteString BEncode -> ByteString -> Result (Maybe a) | ||
193 | (>--?) = optKey | ||
194 | {-# INLINE (>--?) #-} | ||
195 | |||
196 | ------------------------------------- Predicates ------------------------------- | ||
146 | isInteger :: BEncode -> Bool | 197 | isInteger :: BEncode -> Bool |
147 | isInteger (BInteger _) = True | 198 | isInteger (BInteger _) = True |
148 | isInteger _ = False | 199 | isInteger _ = False |