diff options
author | Sam T <pxqr.sta@gmail.com> | 2013-08-26 03:27:42 +0400 |
---|---|---|
committer | Sam T <pxqr.sta@gmail.com> | 2013-08-26 03:27:42 +0400 |
commit | 8f275335d35dc56de90874825d9205e2c84dbd07 (patch) | |
tree | 3826055c2269c9dfe1550d4b210fabf85d52ab6f /src | |
parent | df5f9f41ed7d29be6c008198aba85d132c1339c6 (diff) |
+ Add generics support.
Diffstat (limited to 'src')
-rw-r--r-- | src/Data/BEncode.hs | 140 |
1 files changed, 134 insertions, 6 deletions
diff --git a/src/Data/BEncode.hs b/src/Data/BEncode.hs index 22adbb4..aab814a 100644 --- a/src/Data/BEncode.hs +++ b/src/Data/BEncode.hs | |||
@@ -47,6 +47,20 @@ | |||
47 | -- | 47 | -- |
48 | {-# LANGUAGE FlexibleInstances #-} | 48 | {-# LANGUAGE FlexibleInstances #-} |
49 | {-# LANGUAGE Trustworthy #-} | 49 | {-# LANGUAGE Trustworthy #-} |
50 | {-# LANGUAGE CPP #-} | ||
51 | |||
52 | #if __GLASGOW_HASKELL__ >= 702 | ||
53 | {-# LANGUAGE TypeOperators #-} | ||
54 | {-# LANGUAGE DefaultSignatures #-} | ||
55 | {-# LANGUAGE FlexibleContexts #-} | ||
56 | {-# LANGUAGE FlexibleInstances #-} | ||
57 | |||
58 | -- TODO use TF | ||
59 | {-# LANGUAGE MultiParamTypeClasses #-} | ||
60 | {-# LANGUAGE FunctionalDependencies #-} | ||
61 | {-# LANGUAGE UndecidableInstances #-} | ||
62 | #endif | ||
63 | |||
50 | module Data.BEncode | 64 | module Data.BEncode |
51 | ( -- * Datatype | 65 | ( -- * Datatype |
52 | BEncode(..) | 66 | BEncode(..) |
@@ -93,11 +107,12 @@ module Data.BEncode | |||
93 | import Control.Applicative | 107 | import Control.Applicative |
94 | import Control.Monad | 108 | import Control.Monad |
95 | import Data.Int | 109 | import Data.Int |
96 | import Data.Maybe (mapMaybe) | 110 | import Data.List as L |
97 | import Data.Monoid ((<>)) | 111 | import Data.Maybe (mapMaybe) |
98 | import Data.Foldable (foldMap) | 112 | import Data.Monoid -- (mempty, (<>)) |
99 | import Data.Traversable (traverse) | 113 | import Data.Foldable (foldMap) |
100 | import Data.Word (Word8, Word16, Word32, Word64, Word) | 114 | import Data.Traversable (traverse) |
115 | import Data.Word (Word8, Word16, Word32, Word64, Word) | ||
101 | import Data.Map (Map) | 116 | import Data.Map (Map) |
102 | import qualified Data.Map as M | 117 | import qualified Data.Map as M |
103 | import Data.Set (Set) | 118 | import Data.Set (Set) |
@@ -117,7 +132,9 @@ import Data.Version | |||
117 | import Text.PrettyPrint hiding ((<>)) | 132 | import Text.PrettyPrint hiding ((<>)) |
118 | import qualified Text.ParserCombinators.ReadP as ReadP | 133 | import qualified Text.ParserCombinators.ReadP as ReadP |
119 | 134 | ||
120 | 135 | #if __GLASGOW_HASKELL__ >= 702 | |
136 | import GHC.Generics | ||
137 | #endif | ||
121 | 138 | ||
122 | type Dict = Map ByteString BEncode | 139 | type Dict = Map ByteString BEncode |
123 | 140 | ||
@@ -137,13 +154,124 @@ type Result = Either String | |||
137 | 154 | ||
138 | class BEncodable a where | 155 | class BEncodable a where |
139 | toBEncode :: a -> BEncode | 156 | toBEncode :: a -> BEncode |
157 | |||
158 | #if __GLASGOW_HASKELL__ >= 702 | ||
159 | default toBEncode | ||
160 | :: Generic a | ||
161 | => GBEncodable (Rep a) BEncode | ||
162 | => a -> BEncode | ||
163 | |||
164 | toBEncode = gto . from | ||
165 | #endif | ||
166 | |||
140 | fromBEncode :: BEncode -> Result a | 167 | fromBEncode :: BEncode -> Result a |
141 | 168 | ||
169 | #if __GLASGOW_HASKELL__ >= 702 | ||
170 | default fromBEncode :: GBEncodable (Rep a) BEncode => BEncode -> Result a | ||
171 | fromBEncode = error "default fromBEncode: not implemented" | ||
172 | #endif | ||
142 | 173 | ||
143 | decodingError :: String -> Result a | 174 | decodingError :: String -> Result a |
144 | decodingError s = Left ("fromBEncode: unable to decode " ++ s) | 175 | decodingError s = Left ("fromBEncode: unable to decode " ++ s) |
145 | {-# INLINE decodingError #-} | 176 | {-# INLINE decodingError #-} |
146 | 177 | ||
178 | {-------------------------------------------------------------------- | ||
179 | Generics | ||
180 | --------------------------------------------------------------------} | ||
181 | |||
182 | {- NOTE: SELECTORS FOLDING/UNFOLDING | ||
183 | Both List and Map are monoids: | ||
184 | |||
185 | * if fields are named, we fold record to the map; | ||
186 | * otherwise we collect fields using list; | ||
187 | |||
188 | and then unify them using BDict and BList constrs. | ||
189 | -} | ||
190 | |||
191 | #if __GLASGOW_HASKELL__ >= 702 | ||
192 | |||
193 | class GBEncodable f e where | ||
194 | gto :: f a -> e | ||
195 | gfrom :: e -> Result (f a) | ||
196 | |||
197 | instance BEncodable f | ||
198 | => GBEncodable (K1 R f) BEncode where | ||
199 | {-# INLINE gto #-} | ||
200 | gto (K1 x) = toBEncode x | ||
201 | |||
202 | {-# INLINE gfrom #-} | ||
203 | gfrom = undefined | ||
204 | |||
205 | instance Monoid e | ||
206 | => GBEncodable U1 e where | ||
207 | {-# INLINE gto #-} | ||
208 | gto U1 = mempty | ||
209 | |||
210 | {-# INLINE gfrom #-} | ||
211 | gfrom = undefined | ||
212 | |||
213 | instance (GBEncodable a e, GBEncodable b e, Monoid e) | ||
214 | => GBEncodable (a :*: b) e where | ||
215 | {-# INLINE gto #-} | ||
216 | gto (a :*: b) = gto a <> gto b | ||
217 | |||
218 | {-# INLINE gfrom #-} | ||
219 | gfrom = undefined | ||
220 | |||
221 | instance (GBEncodable a e, GBEncodable b e) | ||
222 | => GBEncodable (a :+: b) e where | ||
223 | {-# INLINE gto #-} | ||
224 | gto (L1 x) = gto x | ||
225 | gto (R1 x) = gto x | ||
226 | |||
227 | {-# INLINE gfrom #-} | ||
228 | gfrom = undefined | ||
229 | |||
230 | instance (Selector s, GBEncodable f BEncode) | ||
231 | => GBEncodable (M1 S s f) Dict where | ||
232 | {-# INLINE gto #-} | ||
233 | gto s @ (M1 x) | ||
234 | | True || L.null sel = BC.pack sel `M.singleton` gto x | ||
235 | -- | otherwise = undefined | ||
236 | where | ||
237 | sel = selName s | ||
238 | |||
239 | {-# INLINE gfrom #-} | ||
240 | gfrom = undefined | ||
241 | |||
242 | -- TODO DList | ||
243 | instance GBEncodable f BEncode | ||
244 | => GBEncodable (M1 S s f) [BEncode] where | ||
245 | {-# INLINE gto #-} | ||
246 | gto (M1 x) = [gto x] | ||
247 | |||
248 | gfrom = undefined | ||
249 | {-# INLINE gfrom #-} | ||
250 | |||
251 | instance (Constructor c, GBEncodable f Dict, GBEncodable f [BEncode]) | ||
252 | => GBEncodable (M1 C c f) BEncode where | ||
253 | {-# INLINE gto #-} | ||
254 | gto con @ (M1 x) | ||
255 | | conIsRecord con = BDict (gto x) | ||
256 | | otherwise = BList (gto x) | ||
257 | |||
258 | {-# INLINE gfrom #-} | ||
259 | gfrom = undefined | ||
260 | |||
261 | instance GBEncodable f e | ||
262 | => GBEncodable (M1 D d f) e where | ||
263 | {-# INLINE gto #-} | ||
264 | gto (M1 x) = gto x | ||
265 | |||
266 | {-# INLINE gfrom #-} | ||
267 | gfrom = undefined | ||
268 | |||
269 | #endif | ||
270 | |||
271 | {-------------------------------------------------------------------- | ||
272 | Basic instances | ||
273 | --------------------------------------------------------------------} | ||
274 | |||
147 | instance BEncodable BEncode where | 275 | instance BEncodable BEncode where |
148 | {-# SPECIALIZE instance BEncodable BEncode #-} | 276 | {-# SPECIALIZE instance BEncodable BEncode #-} |
149 | toBEncode = id | 277 | toBEncode = id |