/haskell/src/Data/MessagePack/Unpack.hs

https://github.com/netconstructor/msgpack · Haskell · 323 lines · 251 code · 46 blank · 26 comment · 15 complexity · 51d569fcb911bc599888e71d4c669c2a MD5 · raw file

  1. {-# Language FlexibleInstances #-}
  2. {-# Language IncoherentInstances #-}
  3. {-# Language TypeSynonymInstances #-}
  4. {-# Language DeriveDataTypeable #-}
  5. --------------------------------------------------------------------
  6. -- |
  7. -- Module : Data.MessagePack.Unpack
  8. -- Copyright : (c) Hideyuki Tanaka, 2009-2010
  9. -- License : BSD3
  10. --
  11. -- Maintainer: tanaka.hideyuki@gmail.com
  12. -- Stability : experimental
  13. -- Portability: portable
  14. --
  15. -- MessagePack Deserializer using @Data.Attoparsec@
  16. --
  17. --------------------------------------------------------------------
  18. module Data.MessagePack.Unpack(
  19. -- * MessagePack deserializer
  20. Unpackable(..),
  21. -- * Simple function to unpack a Haskell value
  22. unpack,
  23. tryUnpack,
  24. -- * Unpack exception
  25. UnpackError(..),
  26. -- * ByteString utils
  27. IsByteString(..),
  28. ) where
  29. import Control.Exception
  30. import Control.Monad
  31. import qualified Data.Attoparsec as A
  32. import Data.Binary.Get
  33. import Data.Binary.IEEE754
  34. import Data.Bits
  35. import qualified Data.ByteString as B
  36. import qualified Data.ByteString.Lazy as BL
  37. import qualified Data.Text as T
  38. import qualified Data.Text.Encoding as T
  39. import qualified Data.Text.Lazy as TL
  40. import qualified Data.Text.Lazy.Encoding as TL
  41. import Data.Int
  42. import Data.Typeable
  43. import qualified Data.Vector as V
  44. import Data.Word
  45. import Text.Printf
  46. import Data.MessagePack.Assoc
  47. import Data.MessagePack.Internal.Utf8
  48. -- | Deserializable class
  49. class Unpackable a where
  50. -- | Deserialize a value
  51. get :: A.Parser a
  52. class IsByteString s where
  53. toBS :: s -> B.ByteString
  54. instance IsByteString B.ByteString where
  55. toBS = id
  56. instance IsByteString BL.ByteString where
  57. toBS = B.concat . BL.toChunks
  58. -- | The exception of unpack
  59. data UnpackError =
  60. UnpackError String
  61. deriving (Show, Typeable)
  62. instance Exception UnpackError
  63. -- | Unpack MessagePack string to Haskell data.
  64. unpack :: (Unpackable a, IsByteString s) => s -> a
  65. unpack bs =
  66. case tryUnpack bs of
  67. Left err ->
  68. throw $ UnpackError err
  69. Right ret ->
  70. ret
  71. -- | Unpack MessagePack string to Haskell data.
  72. tryUnpack :: (Unpackable a, IsByteString s) => s -> Either String a
  73. tryUnpack bs =
  74. case A.parse get (toBS bs) of
  75. A.Fail _ _ err ->
  76. Left err
  77. A.Partial _ ->
  78. Left "not enough input"
  79. A.Done _ ret ->
  80. Right ret
  81. instance Unpackable Int where
  82. get = do
  83. c <- A.anyWord8
  84. case c of
  85. _ | c .&. 0x80 == 0x00 ->
  86. return $ fromIntegral c
  87. _ | c .&. 0xE0 == 0xE0 ->
  88. return $ fromIntegral (fromIntegral c :: Int8)
  89. 0xCC ->
  90. return . fromIntegral =<< A.anyWord8
  91. 0xCD ->
  92. return . fromIntegral =<< parseUint16
  93. 0xCE ->
  94. return . fromIntegral =<< parseUint32
  95. 0xCF ->
  96. return . fromIntegral =<< parseUint64
  97. 0xD0 ->
  98. return . fromIntegral =<< parseInt8
  99. 0xD1 ->
  100. return . fromIntegral =<< parseInt16
  101. 0xD2 ->
  102. return . fromIntegral =<< parseInt32
  103. 0xD3 ->
  104. return . fromIntegral =<< parseInt64
  105. _ ->
  106. fail $ printf "invlid integer tag: 0x%02X" c
  107. instance Unpackable () where
  108. get = do
  109. c <- A.anyWord8
  110. case c of
  111. 0xC0 ->
  112. return ()
  113. _ ->
  114. fail $ printf "invlid nil tag: 0x%02X" c
  115. instance Unpackable Bool where
  116. get = do
  117. c <- A.anyWord8
  118. case c of
  119. 0xC3 ->
  120. return True
  121. 0xC2 ->
  122. return False
  123. _ ->
  124. fail $ printf "invlid bool tag: 0x%02X" c
  125. instance Unpackable Float where
  126. get = do
  127. c <- A.anyWord8
  128. case c of
  129. 0xCA ->
  130. return . runGet getFloat32be . toLBS =<< A.take 4
  131. _ ->
  132. fail $ printf "invlid float tag: 0x%02X" c
  133. instance Unpackable Double where
  134. get = do
  135. c <- A.anyWord8
  136. case c of
  137. 0xCB ->
  138. return . runGet getFloat64be . toLBS =<< A.take 8
  139. _ ->
  140. fail $ printf "invlid double tag: 0x%02X" c
  141. instance Unpackable String where
  142. get = parseString (\n -> return . decodeUtf8 =<< A.take n)
  143. instance Unpackable B.ByteString where
  144. get = parseString A.take
  145. instance Unpackable BL.ByteString where
  146. get = parseString (\n -> return . toLBS =<< A.take n)
  147. instance Unpackable T.Text where
  148. get = parseString (\n -> return . T.decodeUtf8With skipChar =<< A.take n)
  149. instance Unpackable TL.Text where
  150. get = parseString (\n -> return . TL.decodeUtf8With skipChar . toLBS =<< A.take n)
  151. parseString :: (Int -> A.Parser a) -> A.Parser a
  152. parseString aget = do
  153. c <- A.anyWord8
  154. case c of
  155. _ | c .&. 0xE0 == 0xA0 ->
  156. aget . fromIntegral $ c .&. 0x1F
  157. 0xDA ->
  158. aget . fromIntegral =<< parseUint16
  159. 0xDB ->
  160. aget . fromIntegral =<< parseUint32
  161. _ ->
  162. fail $ printf "invlid raw tag: 0x%02X" c
  163. instance Unpackable a => Unpackable [a] where
  164. get = parseArray (flip replicateM get)
  165. instance Unpackable a => Unpackable (V.Vector a) where
  166. get = parseArray (flip V.replicateM get)
  167. instance (Unpackable a1, Unpackable a2) => Unpackable (a1, a2) where
  168. get = parseArray f where
  169. f 2 = get >>= \a1 -> get >>= \a2 -> return (a1, a2)
  170. f n = fail $ printf "wrong tupple size: expected 2 but got " n
  171. instance (Unpackable a1, Unpackable a2, Unpackable a3) => Unpackable (a1, a2, a3) where
  172. get = parseArray f where
  173. f 3 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> return (a1, a2, a3)
  174. f n = fail $ printf "wrong tupple size: expected 3 but got " n
  175. instance (Unpackable a1, Unpackable a2, Unpackable a3, Unpackable a4) => Unpackable (a1, a2, a3, a4) where
  176. get = parseArray f where
  177. f 4 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> return (a1, a2, a3, a4)
  178. f n = fail $ printf "wrong tupple size: expected 4 but got " n
  179. instance (Unpackable a1, Unpackable a2, Unpackable a3, Unpackable a4, Unpackable a5) => Unpackable (a1, a2, a3, a4, a5) where
  180. get = parseArray f where
  181. f 5 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> return (a1, a2, a3, a4, a5)
  182. f n = fail $ printf "wrong tupple size: expected 5 but got " n
  183. instance (Unpackable a1, Unpackable a2, Unpackable a3, Unpackable a4, Unpackable a5, Unpackable a6) => Unpackable (a1, a2, a3, a4, a5, a6) where
  184. get = parseArray f where
  185. f 6 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> return (a1, a2, a3, a4, a5, a6)
  186. f n = fail $ printf "wrong tupple size: expected 6 but got " n
  187. instance (Unpackable a1, Unpackable a2, Unpackable a3, Unpackable a4, Unpackable a5, Unpackable a6, Unpackable a7) => Unpackable (a1, a2, a3, a4, a5, a6, a7) where
  188. get = parseArray f where
  189. f 7 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> get >>= \a7 -> return (a1, a2, a3, a4, a5, a6, a7)
  190. f n = fail $ printf "wrong tupple size: expected 7 but got " n
  191. instance (Unpackable a1, Unpackable a2, Unpackable a3, Unpackable a4, Unpackable a5, Unpackable a6, Unpackable a7, Unpackable a8) => Unpackable (a1, a2, a3, a4, a5, a6, a7, a8) where
  192. get = parseArray f where
  193. f 8 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> get >>= \a7 -> get >>= \a8 -> return (a1, a2, a3, a4, a5, a6, a7, a8)
  194. f n = fail $ printf "wrong tupple size: expected 8 but got " n
  195. instance (Unpackable a1, Unpackable a2, Unpackable a3, Unpackable a4, Unpackable a5, Unpackable a6, Unpackable a7, Unpackable a8, Unpackable a9) => Unpackable (a1, a2, a3, a4, a5, a6, a7, a8, a9) where
  196. get = parseArray f where
  197. f 9 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> get >>= \a7 -> get >>= \a8 -> get >>= \a9 -> return (a1, a2, a3, a4, a5, a6, a7, a8, a9)
  198. f n = fail $ printf "wrong tupple size: expected 9 but got " n
  199. parseArray :: (Int -> A.Parser a) -> A.Parser a
  200. parseArray aget = do
  201. c <- A.anyWord8
  202. case c of
  203. _ | c .&. 0xF0 == 0x90 ->
  204. aget . fromIntegral $ c .&. 0x0F
  205. 0xDC ->
  206. aget . fromIntegral =<< parseUint16
  207. 0xDD ->
  208. aget . fromIntegral =<< parseUint32
  209. _ ->
  210. fail $ printf "invlid array tag: 0x%02X" c
  211. instance (Unpackable k, Unpackable v) => Unpackable (Assoc [(k,v)]) where
  212. get = liftM Assoc $ parseMap (flip replicateM parsePair)
  213. instance (Unpackable k, Unpackable v) => Unpackable (Assoc (V.Vector (k, v))) where
  214. get = liftM Assoc $ parseMap (flip V.replicateM parsePair)
  215. parsePair :: (Unpackable k, Unpackable v) => A.Parser (k, v)
  216. parsePair = do
  217. a <- get
  218. b <- get
  219. return (a, b)
  220. parseMap :: (Int -> A.Parser a) -> A.Parser a
  221. parseMap aget = do
  222. c <- A.anyWord8
  223. case c of
  224. _ | c .&. 0xF0 == 0x80 ->
  225. aget . fromIntegral $ c .&. 0x0F
  226. 0xDE ->
  227. aget . fromIntegral =<< parseUint16
  228. 0xDF ->
  229. aget . fromIntegral =<< parseUint32
  230. _ ->
  231. fail $ printf "invlid map tag: 0x%02X" c
  232. instance Unpackable a => Unpackable (Maybe a) where
  233. get =
  234. A.choice
  235. [ liftM Just get
  236. , liftM (\() -> Nothing) get ]
  237. parseUint16 :: A.Parser Word16
  238. parseUint16 = do
  239. b0 <- A.anyWord8
  240. b1 <- A.anyWord8
  241. return $ (fromIntegral b0 `shiftL` 8) .|. fromIntegral b1
  242. parseUint32 :: A.Parser Word32
  243. parseUint32 = do
  244. b0 <- A.anyWord8
  245. b1 <- A.anyWord8
  246. b2 <- A.anyWord8
  247. b3 <- A.anyWord8
  248. return $ (fromIntegral b0 `shiftL` 24) .|.
  249. (fromIntegral b1 `shiftL` 16) .|.
  250. (fromIntegral b2 `shiftL` 8) .|.
  251. fromIntegral b3
  252. parseUint64 :: A.Parser Word64
  253. parseUint64 = do
  254. b0 <- A.anyWord8
  255. b1 <- A.anyWord8
  256. b2 <- A.anyWord8
  257. b3 <- A.anyWord8
  258. b4 <- A.anyWord8
  259. b5 <- A.anyWord8
  260. b6 <- A.anyWord8
  261. b7 <- A.anyWord8
  262. return $ (fromIntegral b0 `shiftL` 56) .|.
  263. (fromIntegral b1 `shiftL` 48) .|.
  264. (fromIntegral b2 `shiftL` 40) .|.
  265. (fromIntegral b3 `shiftL` 32) .|.
  266. (fromIntegral b4 `shiftL` 24) .|.
  267. (fromIntegral b5 `shiftL` 16) .|.
  268. (fromIntegral b6 `shiftL` 8) .|.
  269. fromIntegral b7
  270. parseInt8 :: A.Parser Int8
  271. parseInt8 = return . fromIntegral =<< A.anyWord8
  272. parseInt16 :: A.Parser Int16
  273. parseInt16 = return . fromIntegral =<< parseUint16
  274. parseInt32 :: A.Parser Int32
  275. parseInt32 = return . fromIntegral =<< parseUint32
  276. parseInt64 :: A.Parser Int64
  277. parseInt64 = return . fromIntegral =<< parseUint64