msgpack 0.3.1.1 → 0.4.0
raw patch · 11 files changed
+927/−530 lines, 11 filesdep +template-haskell
Dependencies added: template-haskell
Files
- msgpack.cabal +10/−4
- src/Data/MessagePack.hs +6/−29
- src/Data/MessagePack/Derive.hs +100/−0
- src/Data/MessagePack/Iteratee.hs +2/−2
- src/Data/MessagePack/Object.hs +206/−29
- src/Data/MessagePack/Pack.hs +186/−0
- src/Data/MessagePack/Parser.hs +0/−270
- src/Data/MessagePack/Put.hs +0/−196
- src/Data/MessagePack/Unpack.hs +308/−0
- test/Test.hs +64/−0
- test/UserData.hs +45/−0
msgpack.cabal view
@@ -1,5 +1,5 @@ Name: msgpack-Version: 0.3.1.1+Version: 0.4.0 Synopsis: A Haskell binding to MessagePack Description: A Haskell binding to MessagePack <http://msgpack.org/>@@ -15,6 +15,10 @@ Cabal-Version: >= 1.6 Build-Type: Simple +Extra-source-files:+ test/Test.hs+ test/UserData.hs+ Library Build-depends: base >=4 && <5, transformers >= 0.2.1 && < 0.2.2,@@ -25,17 +29,19 @@ attoparsec >= 0.8.1 && < 0.8.2, binary >= 0.5.0 && < 0.5.1, data-binary-ieee754 >= 0.4 && < 0.5,- deepseq >= 1.1 && <1.2+ deepseq >= 1.1 && <1.2,+ template-haskell >= 2.4 && < 2.5 Ghc-options: -Wall Hs-source-dirs: src Exposed-modules: Data.MessagePack+ Data.MessagePack.Pack+ Data.MessagePack.Unpack Data.MessagePack.Object- Data.MessagePack.Put- Data.MessagePack.Parser Data.MessagePack.Iteratee+ Data.MessagePack.Derive Source-repository head Type: git
src/Data/MessagePack.hs view
@@ -13,14 +13,11 @@ -------------------------------------------------------------------- module Data.MessagePack(+ module Data.MessagePack.Pack,+ module Data.MessagePack.Unpack, module Data.MessagePack.Object,- module Data.MessagePack.Put,- module Data.MessagePack.Parser, module Data.MessagePack.Iteratee,- - -- * Simple functions of Pack and Unpack- pack,- unpack,+ module Data.MessagePack.Derive, -- * Pack functions packToString,@@ -44,37 +41,17 @@ import Data.Binary.Put import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L-import Data.Functor.Identity import qualified Data.Iteratee as I import System.IO +import Data.MessagePack.Pack+import Data.MessagePack.Unpack import Data.MessagePack.Object-import Data.MessagePack.Put-import Data.MessagePack.Parser import Data.MessagePack.Iteratee+import Data.MessagePack.Derive bufferSize :: Int bufferSize = 4 * 1024--class IsByteString s where- toBS :: s -> B.ByteString--instance IsByteString B.ByteString where- toBS = id--instance IsByteString L.ByteString where- toBS = B.concat . L.toChunks---- | Pack Haskell data to MessagePack string.-pack :: ObjectPut a => a -> L.ByteString-pack = packToString . put---- | Unpack MessagePack string to Haskell data.-unpack :: (ObjectGet a, IsByteString s) => s -> a-unpack bs =- runIdentity $ I.run $ I.joinIM $ I.enumPure1Chunk (toBS bs) getI---- TODO: tryUnpack -- | Pack to ByteString. packToString :: Put -> L.ByteString
+ src/Data/MessagePack/Derive.hs view
@@ -0,0 +1,100 @@+{-# Language TemplateHaskell #-}++module Data.MessagePack.Derive (+ derivePack,+ deriveUnpack,+ deriveObject,+ ) where++import Control.Applicative+import Language.Haskell.TH++import Data.MessagePack.Pack+import Data.MessagePack.Unpack+import Data.MessagePack.Object++deriveUnpack :: Name -> Q [Dec]+deriveUnpack typName = do+ TyConI (DataD _ name _ cons _) <- reify typName+ + return+ [ InstanceD [] (AppT (ConT ''Unpackable) (ConT name))+ [ FunD 'get [Clause [] (NormalB $ ch $ map body cons) []]+ ]]+ + where+ body (NormalC conName elms) =+ DoE+ [ BindS (tupOrListP $ map VarP names) (VarE 'get)+ , NoBindS $ AppE (VarE 'return) $ foldl AppE (ConE conName) $ map VarE names ]+ where+ names = zipWith (\ix _ -> mkName $ "a" ++ show (ix :: Int)) [1..] elms++ body (RecC conName elms) =+ body (NormalC conName $ map (\(_, b, c) -> (b, c)) elms)++ ch = foldl1 (\e f -> AppE (AppE (VarE '(<|>)) e) f)++derivePack :: Name -> Q [Dec]+derivePack typName = do+ TyConI (DataD _ name _ cons _) <- reify typName+ + return+ [ InstanceD [] (AppT (ConT ''Packable) (ConT name))+ [ FunD 'put (map body cons)+ ]]+ + where+ body (NormalC conName elms) =+ Clause+ [ ConP conName $ map VarP names ]+ (NormalB $ AppE (VarE 'put) $ tupOrListE $ map VarE names) []+ where+ names = zipWith (\ix _ -> mkName $ "a" ++ show (ix :: Int)) [1..] elms++ body (RecC conName elms) =+ body (NormalC conName $ map (\(_, b, c) -> (b, c)) elms)++deriveObject :: Name -> Q [Dec]+deriveObject typName = do+ g <- derivePack typName+ p <- deriveUnpack typName++ TyConI (DataD _ name _ cons _) <- reify typName+ let o = InstanceD [] (AppT (ConT ''OBJECT) (ConT name))+ [ FunD 'toObject (map toObjectBody cons),+ FunD 'tryFromObject [Clause [ VarP oname ]+ (NormalB $ ch $ map tryFromObjectBody cons) []]]++ return $ g ++ p ++ [o]+ where+ toObjectBody (NormalC conName elms) =+ Clause+ [ ConP conName $ map VarP names ]+ (NormalB $ AppE (VarE 'toObject) $ tupOrListE $ map VarE names) []+ where+ names = zipWith (\ix _ -> mkName $ "a" ++ show (ix :: Int)) [1..] elms+ toObjectBody (RecC conName elms) =+ toObjectBody (NormalC conName $ map (\(_, b, c) -> (b, c)) elms)++ tryFromObjectBody (NormalC conName elms) =+ DoE+ [ BindS (tupOrListP $ map VarP names) (AppE (VarE 'tryFromObject) (VarE oname))+ , NoBindS $ AppE (VarE 'return) $ foldl AppE (ConE conName) $ map VarE names ]+ where+ names = zipWith (\ix _ -> mkName $ "a" ++ show (ix :: Int)) [1..] elms+ tryFromObjectBody (RecC conName elms) =+ tryFromObjectBody (NormalC conName $ map (\(_, b, c) -> (b, c)) elms)++ oname = mkName "o"+ ch = foldl1 (\e f -> AppE (AppE (VarE '(<|>)) e) f)++tupOrListP :: [Pat] -> Pat+tupOrListP ls+ | length ls <= 1 = ListP ls+ | otherwise = TupP ls++tupOrListE :: [Exp] -> Exp+tupOrListE ls+ | length ls <= 1 = ListE ls+ | otherwise = TupE ls
src/Data/MessagePack/Iteratee.hs view
@@ -28,10 +28,10 @@ import qualified Data.Iteratee as I import System.IO -import Data.MessagePack.Parser+import Data.MessagePack.Unpack -- | Deserialize a value-getI :: (Monad m, ObjectGet a) => I.Iteratee B.ByteString m a+getI :: (Monad m, Unpackable a) => I.Iteratee B.ByteString m a getI = parserToIteratee get -- | Enumerator
src/Data/MessagePack/Object.hs view
@@ -1,6 +1,7 @@ {-# Language TypeSynonymInstances #-} {-# Language FlexibleInstances #-} {-# Language OverlappingInstances #-}+{-# Language IncoherentInstances #-} {-# Language DeriveDataTypeable #-} --------------------------------------------------------------------@@ -23,16 +24,21 @@ -- * Serialization to and from Object OBJECT(..),- Result,+ -- Result, ) where import Control.DeepSeq+import Control.Exception import Control.Monad import Control.Monad.Trans.Error ()+import qualified Data.Attoparsec as A import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as C8 import Data.Typeable +import Data.MessagePack.Pack+import Data.MessagePack.Unpack+ -- | Object Representation of MessagePack data. data Object = ObjectNil@@ -55,70 +61,241 @@ ObjectArray a -> rnf a ObjectMap m -> rnf m +instance Unpackable Object where+ get =+ A.choice+ [ liftM ObjectInteger get+ , liftM (\() -> ObjectNil) get+ , liftM ObjectBool get+ , liftM ObjectDouble get+ , liftM ObjectRAW get+ , liftM ObjectArray get+ , liftM ObjectMap get+ ]++instance Packable Object where+ put obj =+ case obj of+ ObjectInteger n ->+ put n+ ObjectNil ->+ put ()+ ObjectBool b ->+ put b+ ObjectDouble d ->+ put d+ ObjectRAW raw ->+ put raw+ ObjectArray arr ->+ put arr+ ObjectMap m ->+ put m+ -- | The class of types serializable to and from MessagePack object-class OBJECT a where+class (Unpackable a, Packable a) => OBJECT a where -- | Encode a value to MessagePack object toObject :: a -> Object+ toObject = unpack . pack+ -- | Decode a value from MessagePack object- fromObject :: Object -> Result a+ fromObject :: Object -> a+ fromObject a =+ case tryFromObject a of+ Left err ->+ throw $ UnpackError err+ Right ret ->+ ret --- | A type for parser results-type Result a = Either String a+ -- | Decode a value from MessagePack object+ tryFromObject :: Object -> Either String a+ tryFromObject = tryUnpack . pack instance OBJECT Object where toObject = id- fromObject = Right+ tryFromObject = Right -fromObjectError :: String-fromObjectError = "fromObject: cannot cast"+tryFromObjectError :: Either String a+tryFromObjectError = Left "tryFromObject: cannot cast" instance OBJECT () where toObject = const ObjectNil- fromObject ObjectNil = Right ()- fromObject _ = Left fromObjectError+ tryFromObject ObjectNil = Right ()+ tryFromObject _ = tryFromObjectError instance OBJECT Int where toObject = ObjectInteger- fromObject (ObjectInteger n) = Right n- fromObject _ = Left fromObjectError+ tryFromObject (ObjectInteger n) = Right n+ tryFromObject _ = tryFromObjectError instance OBJECT Bool where toObject = ObjectBool- fromObject (ObjectBool b) = Right b- fromObject _ = Left fromObjectError+ tryFromObject (ObjectBool b) = Right b+ tryFromObject _ = tryFromObjectError instance OBJECT Double where toObject = ObjectDouble- fromObject (ObjectDouble d) = Right d- fromObject _ = Left fromObjectError+ tryFromObject (ObjectDouble d) = Right d+ tryFromObject _ = tryFromObjectError instance OBJECT B.ByteString where toObject = ObjectRAW- fromObject (ObjectRAW bs) = Right bs- fromObject _ = Left fromObjectError+ tryFromObject (ObjectRAW bs) = Right bs+ tryFromObject _ = tryFromObjectError instance OBJECT String where toObject = toObject . C8.pack- fromObject obj = liftM C8.unpack $ fromObject obj+ tryFromObject obj = liftM C8.unpack $ tryFromObject obj instance OBJECT a => OBJECT [a] where toObject = ObjectArray . map toObject- fromObject (ObjectArray arr) =- mapM fromObject arr- fromObject _ =- Left fromObjectError+ tryFromObject (ObjectArray arr) =+ mapM tryFromObject arr+ tryFromObject _ =+ tryFromObjectError +instance (OBJECT a1, OBJECT a2) => OBJECT (a1, a2) where+ toObject (a1, a2) = ObjectArray [toObject a1, toObject a2]+ tryFromObject (ObjectArray arr) =+ case arr of+ [o1, o2] -> do+ v1 <- tryFromObject o1+ v2 <- tryFromObject o2+ return (v1, v2)+ _ ->+ tryFromObjectError+ tryFromObject _ =+ tryFromObjectError++instance (OBJECT a1, OBJECT a2, OBJECT a3) => OBJECT (a1, a2, a3) where+ toObject (a1, a2, a3) = ObjectArray [toObject a1, toObject a2, toObject a3]+ tryFromObject (ObjectArray arr) =+ case arr of+ [o1, o2, o3] -> do+ v1 <- tryFromObject o1+ v2 <- tryFromObject o2+ v3 <- tryFromObject o3+ return (v1, v2, v3)+ _ ->+ tryFromObjectError+ tryFromObject _ =+ tryFromObjectError++instance (OBJECT a1, OBJECT a2, OBJECT a3, OBJECT a4) => OBJECT (a1, a2, a3, a4) where+ toObject (a1, a2, a3, a4) = ObjectArray [toObject a1, toObject a2, toObject a3, toObject a4]+ tryFromObject (ObjectArray arr) =+ case arr of+ [o1, o2, o3, o4] -> do+ v1 <- tryFromObject o1+ v2 <- tryFromObject o2+ v3 <- tryFromObject o3+ v4 <- tryFromObject o4+ return (v1, v2, v3, v4)+ _ ->+ tryFromObjectError+ tryFromObject _ =+ tryFromObjectError++instance (OBJECT a1, OBJECT a2, OBJECT a3, OBJECT a4, OBJECT a5) => OBJECT (a1, a2, a3, a4, a5) where+ toObject (a1, a2, a3, a4, a5) = ObjectArray [toObject a1, toObject a2, toObject a3, toObject a4, toObject a5]+ tryFromObject (ObjectArray arr) =+ case arr of+ [o1, o2, o3, o4, o5] -> do+ v1 <- tryFromObject o1+ v2 <- tryFromObject o2+ v3 <- tryFromObject o3+ v4 <- tryFromObject o4+ v5 <- tryFromObject o5+ return (v1, v2, v3, v4, v5)+ _ ->+ tryFromObjectError+ tryFromObject _ =+ tryFromObjectError++instance (OBJECT a1, OBJECT a2, OBJECT a3, OBJECT a4, OBJECT a5, OBJECT a6) => OBJECT (a1, a2, a3, a4, a5, a6) where+ toObject (a1, a2, a3, a4, a5, a6) = ObjectArray [toObject a1, toObject a2, toObject a3, toObject a4, toObject a5, toObject a6]+ tryFromObject (ObjectArray arr) =+ case arr of+ [o1, o2, o3, o4, o5, o6] -> do+ v1 <- tryFromObject o1+ v2 <- tryFromObject o2+ v3 <- tryFromObject o3+ v4 <- tryFromObject o4+ v5 <- tryFromObject o5+ v6 <- tryFromObject o6+ return (v1, v2, v3, v4, v5, v6)+ _ ->+ tryFromObjectError+ tryFromObject _ =+ tryFromObjectError++instance (OBJECT a1, OBJECT a2, OBJECT a3, OBJECT a4, OBJECT a5, OBJECT a6, OBJECT a7) => OBJECT (a1, a2, a3, a4, a5, a6, a7) where+ toObject (a1, a2, a3, a4, a5, a6, a7) = ObjectArray [toObject a1, toObject a2, toObject a3, toObject a4, toObject a5, toObject a6, toObject a7]+ tryFromObject (ObjectArray arr) =+ case arr of+ [o1, o2, o3, o4, o5, o6, o7] -> do+ v1 <- tryFromObject o1+ v2 <- tryFromObject o2+ v3 <- tryFromObject o3+ v4 <- tryFromObject o4+ v5 <- tryFromObject o5+ v6 <- tryFromObject o6+ v7 <- tryFromObject o7+ return (v1, v2, v3, v4, v5, v6, v7)+ _ ->+ tryFromObjectError+ tryFromObject _ =+ tryFromObjectError++instance (OBJECT a1, OBJECT a2, OBJECT a3, OBJECT a4, OBJECT a5, OBJECT a6, OBJECT a7, OBJECT a8) => OBJECT (a1, a2, a3, a4, a5, a6, a7, a8) where+ toObject (a1, a2, a3, a4, a5, a6, a7, a8) = ObjectArray [toObject a1, toObject a2, toObject a3, toObject a4, toObject a5, toObject a6, toObject a7, toObject a8]+ tryFromObject (ObjectArray arr) =+ case arr of+ [o1, o2, o3, o4, o5, o6, o7, o8] -> do+ v1 <- tryFromObject o1+ v2 <- tryFromObject o2+ v3 <- tryFromObject o3+ v4 <- tryFromObject o4+ v5 <- tryFromObject o5+ v6 <- tryFromObject o6+ v7 <- tryFromObject o7+ v8 <- tryFromObject o8+ return (v1, v2, v3, v4, v5, v6, v7, v8)+ _ ->+ tryFromObjectError+ tryFromObject _ =+ tryFromObjectError++instance (OBJECT a1, OBJECT a2, OBJECT a3, OBJECT a4, OBJECT a5, OBJECT a6, OBJECT a7, OBJECT a8, OBJECT a9) => OBJECT (a1, a2, a3, a4, a5, a6, a7, a8, a9) where+ toObject (a1, a2, a3, a4, a5, a6, a7, a8, a9) = ObjectArray [toObject a1, toObject a2, toObject a3, toObject a4, toObject a5, toObject a6, toObject a7, toObject a8, toObject a9]+ tryFromObject (ObjectArray arr) =+ case arr of+ [o1, o2, o3, o4, o5, o6, o7, o8, o9] -> do+ v1 <- tryFromObject o1+ v2 <- tryFromObject o2+ v3 <- tryFromObject o3+ v4 <- tryFromObject o4+ v5 <- tryFromObject o5+ v6 <- tryFromObject o6+ v7 <- tryFromObject o7+ v8 <- tryFromObject o8+ v9 <- tryFromObject o9+ return (v1, v2, v3, v4, v5, v6, v7, v8, v9)+ _ ->+ tryFromObjectError+ tryFromObject _ =+ tryFromObjectError+ instance (OBJECT a, OBJECT b) => OBJECT [(a, b)] where toObject = ObjectMap . map (\(a, b) -> (toObject a, toObject b))- fromObject (ObjectMap mem) = do- mapM (\(a, b) -> liftM2 (,) (fromObject a) (fromObject b)) mem- fromObject _ =- Left fromObjectError+ tryFromObject (ObjectMap mem) = do+ mapM (\(a, b) -> liftM2 (,) (tryFromObject a) (tryFromObject b)) mem+ tryFromObject _ =+ tryFromObjectError instance OBJECT a => OBJECT (Maybe a) where toObject (Just a) = toObject a toObject Nothing = ObjectNil - fromObject ObjectNil = return Nothing- fromObject obj = liftM Just $ fromObject obj+ tryFromObject ObjectNil = return Nothing+ tryFromObject obj = liftM Just $ tryFromObject obj
+ src/Data/MessagePack/Pack.hs view
@@ -0,0 +1,186 @@+{-# Language FlexibleInstances #-}+{-# Language IncoherentInstances #-}+{-# Language OverlappingInstances #-}+{-# Language TypeSynonymInstances #-}++--------------------------------------------------------------------+-- |+-- Module : Data.MessagePack.Pack+-- Copyright : (c) Hideyuki Tanaka, 2009-2010+-- License : BSD3+--+-- Maintainer: tanaka.hideyuki@gmail.com+-- Stability : experimental+-- Portability: portable+--+-- MessagePack Serializer using @Data.Binary.Pack@+--+--------------------------------------------------------------------++module Data.MessagePack.Pack (+ -- * Serializable class+ Packable(..),+ -- * Simple function to pack a Haskell value+ pack,+ ) where++import Data.Binary.Put+import Data.Binary.IEEE754+import Data.Bits+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import qualified Data.ByteString.Lazy as L+import qualified Data.Vector as V++-- | Serializable class+class Packable a where+ -- | Serialize a value+ put :: a -> Put++-- | Pack Haskell data to MessagePack string.+pack :: Packable a => a -> L.ByteString+pack = runPut . put++instance Packable Int where+ put n =+ case n of+ _ | n >= 0 && n <= 127 ->+ putWord8 $ fromIntegral n+ _ | n >= -32 && n <= -1 ->+ putWord8 $ fromIntegral n+ _ | n >= 0 && n < 0x100 -> do+ putWord8 0xCC+ putWord8 $ fromIntegral n+ _ | n >= 0 && n < 0x10000 -> do+ putWord8 0xCD+ putWord16be $ fromIntegral n+ _ | n >= 0 && n < 0x100000000 -> do+ putWord8 0xCE+ putWord32be $ fromIntegral n+ _ | n >= 0 -> do+ putWord8 0xCF+ putWord64be $ fromIntegral n+ _ | n >= -0x80 -> do+ putWord8 0xD0+ putWord8 $ fromIntegral n+ _ | n >= -0x8000 -> do+ putWord8 0xD1+ putWord16be $ fromIntegral n+ _ | n >= -0x80000000 -> do+ putWord8 0xD2+ putWord32be $ fromIntegral n+ _ -> do+ putWord8 0xD3+ putWord64be $ fromIntegral n++instance Packable () where+ put _ = + putWord8 0xC0++instance Packable Bool where+ put True = putWord8 0xC3+ put False = putWord8 0xC2++instance Packable Double where+ put d = do+ putWord8 0xCB+ putFloat64be d++instance Packable String where+ put = putString length (putByteString . B8.pack)++instance Packable B.ByteString where+ put = putString B.length putByteString++instance Packable L.ByteString where+ put = putString (fromIntegral . L.length) putLazyByteString++putString :: (s -> Int) -> (s -> Put) -> s -> Put+putString lf pf str = do+ case lf str of+ len | len <= 31 -> do+ putWord8 $ 0xA0 .|. fromIntegral len+ len | len < 0x10000 -> do+ putWord8 0xDA+ putWord16be $ fromIntegral len+ len -> do+ putWord8 0xDB+ putWord32be $ fromIntegral len+ pf str++instance Packable a => Packable [a] where+ put = putArray length (mapM_ put)++instance Packable a => Packable (V.Vector a) where+ put = putArray V.length (V.mapM_ put)++instance (Packable a1, Packable a2) => Packable (a1, a2) where+ put = putArray (const 2) f where+ f (a1, a2) = put a1 >> put a2++instance (Packable a1, Packable a2, Packable a3) => Packable (a1, a2, a3) where+ put = putArray (const 3) f where+ f (a1, a2, a3) = put a1 >> put a2 >> put a3++instance (Packable a1, Packable a2, Packable a3, Packable a4) => Packable (a1, a2, a3, a4) where+ put = putArray (const 4) f where+ f (a1, a2, a3, a4) = put a1 >> put a2 >> put a3 >> put a4++instance (Packable a1, Packable a2, Packable a3, Packable a4, Packable a5) => Packable (a1, a2, a3, a4, a5) where+ put = putArray (const 5) f where+ f (a1, a2, a3, a4, a5) = put a1 >> put a2 >> put a3 >> put a4 >> put a5++instance (Packable a1, Packable a2, Packable a3, Packable a4, Packable a5, Packable a6) => Packable (a1, a2, a3, a4, a5, a6) where+ put = putArray (const 6) f where+ f (a1, a2, a3, a4, a5, a6) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6++instance (Packable a1, Packable a2, Packable a3, Packable a4, Packable a5, Packable a6, Packable a7) => Packable (a1, a2, a3, a4, a5, a6, a7) where+ put = putArray (const 7) f where+ f (a1, a2, a3, a4, a5, a6, a7) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6 >> put a7++instance (Packable a1, Packable a2, Packable a3, Packable a4, Packable a5, Packable a6, Packable a7, Packable a8) => Packable (a1, a2, a3, a4, a5, a6, a7, a8) where+ put = putArray (const 8) f where+ f (a1, a2, a3, a4, a5, a6, a7, a8) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6 >> put a7 >> put a8++instance (Packable a1, Packable a2, Packable a3, Packable a4, Packable a5, Packable a6, Packable a7, Packable a8, Packable a9) => Packable (a1, a2, a3, a4, a5, a6, a7, a8, a9) where+ put = putArray (const 9) f where+ f (a1, a2, a3, a4, a5, a6, a7, a8, a9) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6 >> put a7 >> put a8 >> put a9++putArray :: (a -> Int) -> (a -> Put) -> a -> Put+putArray lf pf arr = do+ case lf arr of+ len | len <= 15 ->+ putWord8 $ 0x90 .|. fromIntegral len+ len | len < 0x10000 -> do+ putWord8 0xDC+ putWord16be $ fromIntegral len+ len -> do+ putWord8 0xDD+ putWord32be $ fromIntegral len+ pf arr++instance (Packable k, Packable v) => Packable [(k, v)] where+ put = putMap length (mapM_ putPair)++instance (Packable k, Packable v) => Packable (V.Vector (k, v)) where+ put = putMap V.length (V.mapM_ putPair)++putPair :: (Packable a, Packable b) => (a, b) -> Put+putPair (a, b) = put a >> put b++putMap :: (a -> Int) -> (a -> Put) -> a -> Put+putMap lf pf m = do+ case lf m of+ len | len <= 15 ->+ putWord8 $ 0x80 .|. fromIntegral len+ len | len < 0x10000 -> do+ putWord8 0xDE+ putWord16be $ fromIntegral len+ len -> do+ putWord8 0xDF+ putWord32be $ fromIntegral len+ pf m++instance Packable a => Packable (Maybe a) where+ put Nothing = put ()+ put (Just a) = put a
− src/Data/MessagePack/Parser.hs
@@ -1,270 +0,0 @@-{-# Language FlexibleInstances #-}-{-# Language IncoherentInstances #-}-{-# Language OverlappingInstances #-}-{-# Language TypeSynonymInstances #-}------------------------------------------------------------------------- |--- Module : Data.MessagePack.Parser--- Copyright : (c) Hideyuki Tanaka, 2009-2010--- License : BSD3------ Maintainer: tanaka.hideyuki@gmail.com--- Stability : experimental--- Portability: portable------ MessagePack Deserializer using @Data.Attoparsec@--------------------------------------------------------------------------module Data.MessagePack.Parser(- -- * MessagePack deserializer- ObjectGet(..),- ) where--import Control.Monad-import qualified Data.Attoparsec as A-import Data.Binary.Get-import Data.Binary.IEEE754-import Data.Bits-import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as B8-import qualified Data.ByteString.Lazy as L-import Data.Int-import qualified Data.Vector as V-import Data.Word-import Text.Printf--import Data.MessagePack.Object---- | Deserializable class-class ObjectGet a where- -- | Deserialize a value- get :: A.Parser a--instance ObjectGet Object where- get =- A.choice- [ liftM ObjectInteger get- , liftM (\() -> ObjectNil) get- , liftM ObjectBool get- , liftM ObjectDouble get- , liftM ObjectRAW get- , liftM ObjectArray get- , liftM ObjectMap get- ]--instance ObjectGet Int where- get = do- c <- A.anyWord8- case c of- _ | c .&. 0x80 == 0x00 ->- return $ fromIntegral c- _ | c .&. 0xE0 == 0xE0 ->- return $ fromIntegral (fromIntegral c :: Int8)- 0xCC ->- return . fromIntegral =<< A.anyWord8- 0xCD ->- return . fromIntegral =<< parseUint16- 0xCE ->- return . fromIntegral =<< parseUint32- 0xCF ->- return . fromIntegral =<< parseUint64- 0xD0 ->- return . fromIntegral =<< parseInt8- 0xD1 ->- return . fromIntegral =<< parseInt16- 0xD2 ->- return . fromIntegral =<< parseInt32- 0xD3 ->- return . fromIntegral =<< parseInt64- _ ->- fail $ printf "invlid integer tag: 0x%02X" c--instance ObjectGet () where- get = do- c <- A.anyWord8- case c of- 0xC0 ->- return ()- _ ->- fail $ printf "invlid nil tag: 0x%02X" c--instance ObjectGet Bool where- get = do- c <- A.anyWord8- case c of- 0xC3 ->- return True- 0xC2 ->- return False- _ ->- fail $ printf "invlid bool tag: 0x%02X" c--instance ObjectGet Double where- get = do- c <- A.anyWord8- case c of- 0xCA ->- return . realToFrac . runGet getFloat32be . toLBS =<< A.take 4- 0xCB ->- return . runGet getFloat64be . toLBS =<< A.take 8- _ ->- fail $ printf "invlid double tag: 0x%02X" c--instance ObjectGet String where- get = parseString (\n -> return . B8.unpack =<< A.take n)--instance ObjectGet B.ByteString where- get = parseString A.take--instance ObjectGet L.ByteString where- get = parseString (\n -> do bs <- A.take n; return $ L.fromChunks [bs])--parseString :: (Int -> A.Parser a) -> A.Parser a-parseString aget = do- c <- A.anyWord8- case c of- _ | c .&. 0xE0 == 0xA0 ->- aget . fromIntegral $ c .&. 0x1F- 0xDA ->- aget . fromIntegral =<< parseUint16- 0xDB ->- aget . fromIntegral =<< parseUint32- _ ->- fail $ printf "invlid raw tag: 0x%02X" c--instance ObjectGet a => ObjectGet [a] where- get = parseArray (flip replicateM get)--instance ObjectGet a => ObjectGet (V.Vector a) where- get = parseArray (flip V.replicateM get)--instance (ObjectGet a1, ObjectGet a2) => ObjectGet (a1, a2) where- get = parseArray f where- f 2 = get >>= \a1 -> get >>= \a2 -> return (a1, a2)- f n = fail $ printf "wrong tupple size: expected 2 but got " n--instance (ObjectGet a1, ObjectGet a2, ObjectGet a3) => ObjectGet (a1, a2, a3) where- get = parseArray f where- f 3 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> return (a1, a2, a3)- f n = fail $ printf "wrong tupple size: expected 3 but got " n--instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4) => ObjectGet (a1, a2, a3, a4) where- get = parseArray f where- f 4 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> return (a1, a2, a3, a4)- f n = fail $ printf "wrong tupple size: expected 4 but got " n--instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4, ObjectGet a5) => ObjectGet (a1, a2, a3, a4, a5) where- get = parseArray f where- f 5 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> return (a1, a2, a3, a4, a5)- f n = fail $ printf "wrong tupple size: expected 5 but got " n--instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4, ObjectGet a5, ObjectGet a6) => ObjectGet (a1, a2, a3, a4, a5, a6) where- get = parseArray f where- f 6 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> return (a1, a2, a3, a4, a5, a6)- f n = fail $ printf "wrong tupple size: expected 6 but got " n--instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4, ObjectGet a5, ObjectGet a6, ObjectGet a7) => ObjectGet (a1, a2, a3, a4, a5, a6, a7) where- get = parseArray f where- f 7 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> get >>= \a7 -> return (a1, a2, a3, a4, a5, a6, a7)- f n = fail $ printf "wrong tupple size: expected 7 but got " n--instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4, ObjectGet a5, ObjectGet a6, ObjectGet a7, ObjectGet a8) => ObjectGet (a1, a2, a3, a4, a5, a6, a7, a8) where- get = parseArray f where- 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)- f n = fail $ printf "wrong tupple size: expected 8 but got " n--instance (ObjectGet a1, ObjectGet a2, ObjectGet a3, ObjectGet a4, ObjectGet a5, ObjectGet a6, ObjectGet a7, ObjectGet a8, ObjectGet a9) => ObjectGet (a1, a2, a3, a4, a5, a6, a7, a8, a9) where- get = parseArray f where- 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)- f n = fail $ printf "wrong tupple size: expected 9 but got " n--parseArray :: (Int -> A.Parser a) -> A.Parser a-parseArray aget = do- c <- A.anyWord8- case c of- _ | c .&. 0xF0 == 0x90 ->- aget . fromIntegral $ c .&. 0x0F- 0xDC ->- aget . fromIntegral =<< parseUint16- 0xDD ->- aget . fromIntegral =<< parseUint32- _ ->- fail $ printf "invlid array tag: 0x%02X" c--instance (ObjectGet k, ObjectGet v) => ObjectGet [(k, v)] where- get = parseMap (flip replicateM parsePair)--instance (ObjectGet k, ObjectGet v) => ObjectGet (V.Vector (k, v)) where- get = parseMap (flip V.replicateM parsePair)--parsePair :: (ObjectGet k, ObjectGet v) => A.Parser (k, v)-parsePair = do- a <- get- b <- get- return (a, b)--parseMap :: (Int -> A.Parser a) -> A.Parser a-parseMap aget = do- c <- A.anyWord8- case c of- _ | c .&. 0xF0 == 0x80 ->- aget . fromIntegral $ c .&. 0x0F- 0xDE ->- aget . fromIntegral =<< parseUint16- 0xDF ->- aget . fromIntegral =<< parseUint32- _ ->- fail $ printf "invlid map tag: 0x%02X" c--parseUint16 :: A.Parser Word16-parseUint16 = do- b0 <- A.anyWord8- b1 <- A.anyWord8- return $ (fromIntegral b0 `shiftL` 8) .|. fromIntegral b1--parseUint32 :: A.Parser Word32-parseUint32 = do- b0 <- A.anyWord8- b1 <- A.anyWord8- b2 <- A.anyWord8- b3 <- A.anyWord8- return $ (fromIntegral b0 `shiftL` 24) .|.- (fromIntegral b1 `shiftL` 16) .|.- (fromIntegral b2 `shiftL` 8) .|.- fromIntegral b3--parseUint64 :: A.Parser Word64-parseUint64 = do- b0 <- A.anyWord8- b1 <- A.anyWord8- b2 <- A.anyWord8- b3 <- A.anyWord8- b4 <- A.anyWord8- b5 <- A.anyWord8- b6 <- A.anyWord8- b7 <- A.anyWord8- return $ (fromIntegral b0 `shiftL` 56) .|.- (fromIntegral b1 `shiftL` 48) .|.- (fromIntegral b2 `shiftL` 40) .|.- (fromIntegral b3 `shiftL` 32) .|.- (fromIntegral b4 `shiftL` 24) .|.- (fromIntegral b5 `shiftL` 16) .|.- (fromIntegral b6 `shiftL` 8) .|.- fromIntegral b7--parseInt8 :: A.Parser Int8-parseInt8 = return . fromIntegral =<< A.anyWord8--parseInt16 :: A.Parser Int16-parseInt16 = return . fromIntegral =<< parseUint16--parseInt32 :: A.Parser Int32-parseInt32 = return . fromIntegral =<< parseUint32--parseInt64 :: A.Parser Int64-parseInt64 = return . fromIntegral =<< parseUint64--toLBS :: B.ByteString -> L.ByteString-toLBS bs = L.fromChunks [bs]
− src/Data/MessagePack/Put.hs
@@ -1,196 +0,0 @@-{-# Language FlexibleInstances #-}-{-# Language IncoherentInstances #-}-{-# Language OverlappingInstances #-}-{-# Language TypeSynonymInstances #-}------------------------------------------------------------------------- |--- Module : Data.MessagePack.Put--- Copyright : (c) Hideyuki Tanaka, 2009-2010--- License : BSD3------ Maintainer: tanaka.hideyuki@gmail.com--- Stability : experimental--- Portability: portable------ MessagePack Serializer using @Data.Binary.Put@--------------------------------------------------------------------------module Data.MessagePack.Put(- -- * Serializable class- ObjectPut(..),- ) where--import Data.Binary.Put-import Data.Binary.IEEE754-import Data.Bits-import qualified Data.ByteString as B-import qualified Data.ByteString.Char8 as B8-import qualified Data.ByteString.Lazy as L-import qualified Data.Vector as V--import Data.MessagePack.Object---- | Serializable class-class ObjectPut a where- -- | Serialize a value- put :: a -> Put--instance ObjectPut Object where- put obj =- case obj of- ObjectInteger n ->- put n- ObjectNil ->- put ()- ObjectBool b ->- put b- ObjectDouble d ->- put d- ObjectRAW raw ->- put raw- ObjectArray arr ->- put arr- ObjectMap m ->- put m--instance ObjectPut Int where- put n =- case n of- _ | n >= 0 && n <= 127 ->- putWord8 $ fromIntegral n- _ | n >= -32 && n <= -1 ->- putWord8 $ fromIntegral n- _ | n >= 0 && n < 0x100 -> do- putWord8 0xCC- putWord8 $ fromIntegral n- _ | n >= 0 && n < 0x10000 -> do- putWord8 0xCD- putWord16be $ fromIntegral n- _ | n >= 0 && n < 0x100000000 -> do- putWord8 0xCE- putWord32be $ fromIntegral n- _ | n >= 0 -> do- putWord8 0xCF- putWord64be $ fromIntegral n- _ | n >= -0x80 -> do- putWord8 0xD0- putWord8 $ fromIntegral n- _ | n >= -0x8000 -> do- putWord8 0xD1- putWord16be $ fromIntegral n- _ | n >= -0x80000000 -> do- putWord8 0xD2- putWord32be $ fromIntegral n- _ -> do- putWord8 0xD3- putWord64be $ fromIntegral n--instance ObjectPut () where- put _ = - putWord8 0xC0--instance ObjectPut Bool where- put True = putWord8 0xC3- put False = putWord8 0xC2--instance ObjectPut Double where- put d = do- putWord8 0xCB- putFloat64be d--instance ObjectPut String where- put = putString length (putByteString . B8.pack)--instance ObjectPut B.ByteString where- put = putString B.length putByteString--instance ObjectPut L.ByteString where- put = putString (fromIntegral . L.length) putLazyByteString--putString :: (s -> Int) -> (s -> Put) -> s -> Put-putString lf pf str = do- case lf str of- len | len <= 31 -> do- putWord8 $ 0xA0 .|. fromIntegral len- len | len < 0x10000 -> do- putWord8 0xDA- putWord16be $ fromIntegral len- len -> do- putWord8 0xDB- putWord32be $ fromIntegral len- pf str--instance ObjectPut a => ObjectPut [a] where- put = putArray length (mapM_ put)--instance ObjectPut a => ObjectPut (V.Vector a) where- put = putArray V.length (V.mapM_ put)--instance (ObjectPut a1, ObjectPut a2) => ObjectPut (a1, a2) where- put = putArray (const 2) f where- f (a1, a2) = put a1 >> put a2--instance (ObjectPut a1, ObjectPut a2, ObjectPut a3) => ObjectPut (a1, a2, a3) where- put = putArray (const 3) f where- f (a1, a2, a3) = put a1 >> put a2 >> put a3--instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4) => ObjectPut (a1, a2, a3, a4) where- put = putArray (const 4) f where- f (a1, a2, a3, a4) = put a1 >> put a2 >> put a3 >> put a4--instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4, ObjectPut a5) => ObjectPut (a1, a2, a3, a4, a5) where- put = putArray (const 5) f where- f (a1, a2, a3, a4, a5) = put a1 >> put a2 >> put a3 >> put a4 >> put a5--instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4, ObjectPut a5, ObjectPut a6) => ObjectPut (a1, a2, a3, a4, a5, a6) where- put = putArray (const 6) f where- f (a1, a2, a3, a4, a5, a6) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6--instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4, ObjectPut a5, ObjectPut a6, ObjectPut a7) => ObjectPut (a1, a2, a3, a4, a5, a6, a7) where- put = putArray (const 7) f where- f (a1, a2, a3, a4, a5, a6, a7) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6 >> put a7--instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4, ObjectPut a5, ObjectPut a6, ObjectPut a7, ObjectPut a8) => ObjectPut (a1, a2, a3, a4, a5, a6, a7, a8) where- put = putArray (const 8) f where- f (a1, a2, a3, a4, a5, a6, a7, a8) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6 >> put a7 >> put a8--instance (ObjectPut a1, ObjectPut a2, ObjectPut a3, ObjectPut a4, ObjectPut a5, ObjectPut a6, ObjectPut a7, ObjectPut a8, ObjectPut a9) => ObjectPut (a1, a2, a3, a4, a5, a6, a7, a8, a9) where- put = putArray (const 9) f where- f (a1, a2, a3, a4, a5, a6, a7, a8, a9) = put a1 >> put a2 >> put a3 >> put a4 >> put a5 >> put a6 >> put a7 >> put a8 >> put a9--putArray :: (a -> Int) -> (a -> Put) -> a -> Put-putArray lf pf arr = do- case lf arr of- len | len <= 15 ->- putWord8 $ 0x90 .|. fromIntegral len- len | len < 0x10000 -> do- putWord8 0xDC- putWord16be $ fromIntegral len- len -> do- putWord8 0xDD- putWord32be $ fromIntegral len- pf arr--instance (ObjectPut k, ObjectPut v) => ObjectPut [(k, v)] where- put = putMap length (mapM_ putPair)--instance (ObjectPut k, ObjectPut v) => ObjectPut (V.Vector (k, v)) where- put = putMap V.length (V.mapM_ putPair)--putPair :: (ObjectPut a, ObjectPut b) => (a, b) -> Put-putPair (a, b) = put a >> put b--putMap :: (a -> Int) -> (a -> Put) -> a -> Put-putMap lf pf m = do- case lf m of- len | len <= 15 ->- putWord8 $ 0x80 .|. fromIntegral len- len | len < 0x10000 -> do- putWord8 0xDE- putWord16be $ fromIntegral len- len -> do- putWord8 0xDF- putWord32be $ fromIntegral len- pf m
+ src/Data/MessagePack/Unpack.hs view
@@ -0,0 +1,308 @@+{-# Language FlexibleInstances #-}+{-# Language IncoherentInstances #-}+{-# Language OverlappingInstances #-}+{-# Language TypeSynonymInstances #-}+{-# Language DeriveDataTypeable #-}++--------------------------------------------------------------------+-- |+-- Module : Data.MessagePack.Unpack+-- Copyright : (c) Hideyuki Tanaka, 2009-2010+-- License : BSD3+--+-- Maintainer: tanaka.hideyuki@gmail.com+-- Stability : experimental+-- Portability: portable+--+-- MessagePack Deserializer using @Data.Attoparsec@+--+--------------------------------------------------------------------++module Data.MessagePack.Unpack(+ -- * MessagePack deserializer+ Unpackable(..),+ -- * Simple function to unpack a Haskell value+ unpack,+ tryUnpack,+ -- * Unpack exception+ UnpackError(..),+ -- * ByteString utils+ IsByteString(..),+ ) where++import Control.Exception+import Control.Monad+import qualified Data.Attoparsec as A+import Data.Binary.Get+import Data.Binary.IEEE754+import Data.Bits+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8+import qualified Data.ByteString.Lazy as L+import Data.Int+import Data.Typeable+import qualified Data.Vector as V+import Data.Word+import Text.Printf++-- | Deserializable class+class Unpackable a where+ -- | Deserialize a value+ get :: A.Parser a++class IsByteString s where+ toBS :: s -> B.ByteString++instance IsByteString B.ByteString where+ toBS = id++instance IsByteString L.ByteString where+ toBS = B.concat . L.toChunks++-- | The exception of unpack+data UnpackError =+ UnpackError String+ deriving (Show, Typeable)++instance Exception UnpackError++-- | Unpack MessagePack string to Haskell data.+unpack :: (Unpackable a, IsByteString s) => s -> a+unpack bs =+ case tryUnpack bs of+ Left err ->+ throw $ UnpackError err+ Right ret ->+ ret++-- | Unpack MessagePack string to Haskell data.+tryUnpack :: (Unpackable a, IsByteString s) => s -> Either String a+tryUnpack bs =+ case A.parse get (toBS bs) of+ A.Fail _ _ err ->+ Left err+ A.Partial _ ->+ Left "not enough input"+ A.Done _ ret ->+ Right ret++instance Unpackable Int where+ get = do+ c <- A.anyWord8+ case c of+ _ | c .&. 0x80 == 0x00 ->+ return $ fromIntegral c+ _ | c .&. 0xE0 == 0xE0 ->+ return $ fromIntegral (fromIntegral c :: Int8)+ 0xCC ->+ return . fromIntegral =<< A.anyWord8+ 0xCD ->+ return . fromIntegral =<< parseUint16+ 0xCE ->+ return . fromIntegral =<< parseUint32+ 0xCF ->+ return . fromIntegral =<< parseUint64+ 0xD0 ->+ return . fromIntegral =<< parseInt8+ 0xD1 ->+ return . fromIntegral =<< parseInt16+ 0xD2 ->+ return . fromIntegral =<< parseInt32+ 0xD3 ->+ return . fromIntegral =<< parseInt64+ _ ->+ fail $ printf "invlid integer tag: 0x%02X" c++instance Unpackable () where+ get = do+ c <- A.anyWord8+ case c of+ 0xC0 ->+ return ()+ _ ->+ fail $ printf "invlid nil tag: 0x%02X" c++instance Unpackable Bool where+ get = do+ c <- A.anyWord8+ case c of+ 0xC3 ->+ return True+ 0xC2 ->+ return False+ _ ->+ fail $ printf "invlid bool tag: 0x%02X" c++instance Unpackable Double where+ get = do+ c <- A.anyWord8+ case c of+ 0xCA ->+ return . realToFrac . runGet getFloat32be . toLBS =<< A.take 4+ 0xCB ->+ return . runGet getFloat64be . toLBS =<< A.take 8+ _ ->+ fail $ printf "invlid double tag: 0x%02X" c++instance Unpackable String where+ get = parseString (\n -> return . B8.unpack =<< A.take n)++instance Unpackable B.ByteString where+ get = parseString A.take++instance Unpackable L.ByteString where+ get = parseString (\n -> do bs <- A.take n; return $ L.fromChunks [bs])++parseString :: (Int -> A.Parser a) -> A.Parser a+parseString aget = do+ c <- A.anyWord8+ case c of+ _ | c .&. 0xE0 == 0xA0 ->+ aget . fromIntegral $ c .&. 0x1F+ 0xDA ->+ aget . fromIntegral =<< parseUint16+ 0xDB ->+ aget . fromIntegral =<< parseUint32+ _ ->+ fail $ printf "invlid raw tag: 0x%02X" c++instance Unpackable a => Unpackable [a] where+ get = parseArray (flip replicateM get)++instance Unpackable a => Unpackable (V.Vector a) where+ get = parseArray (flip V.replicateM get)++instance (Unpackable a1, Unpackable a2) => Unpackable (a1, a2) where+ get = parseArray f where+ f 2 = get >>= \a1 -> get >>= \a2 -> return (a1, a2)+ f n = fail $ printf "wrong tupple size: expected 2 but got " n++instance (Unpackable a1, Unpackable a2, Unpackable a3) => Unpackable (a1, a2, a3) where+ get = parseArray f where+ f 3 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> return (a1, a2, a3)+ f n = fail $ printf "wrong tupple size: expected 3 but got " n++instance (Unpackable a1, Unpackable a2, Unpackable a3, Unpackable a4) => Unpackable (a1, a2, a3, a4) where+ get = parseArray f where+ f 4 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> return (a1, a2, a3, a4)+ f n = fail $ printf "wrong tupple size: expected 4 but got " n++instance (Unpackable a1, Unpackable a2, Unpackable a3, Unpackable a4, Unpackable a5) => Unpackable (a1, a2, a3, a4, a5) where+ get = parseArray f where+ f 5 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> return (a1, a2, a3, a4, a5)+ f n = fail $ printf "wrong tupple size: expected 5 but got " n++instance (Unpackable a1, Unpackable a2, Unpackable a3, Unpackable a4, Unpackable a5, Unpackable a6) => Unpackable (a1, a2, a3, a4, a5, a6) where+ get = parseArray f where+ f 6 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> return (a1, a2, a3, a4, a5, a6)+ f n = fail $ printf "wrong tupple size: expected 6 but got " n++instance (Unpackable a1, Unpackable a2, Unpackable a3, Unpackable a4, Unpackable a5, Unpackable a6, Unpackable a7) => Unpackable (a1, a2, a3, a4, a5, a6, a7) where+ get = parseArray f where+ f 7 = get >>= \a1 -> get >>= \a2 -> get >>= \a3 -> get >>= \a4 -> get >>= \a5 -> get >>= \a6 -> get >>= \a7 -> return (a1, a2, a3, a4, a5, a6, a7)+ f n = fail $ printf "wrong tupple size: expected 7 but got " n++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+ get = parseArray f where+ 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)+ f n = fail $ printf "wrong tupple size: expected 8 but got " n++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+ get = parseArray f where+ 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)+ f n = fail $ printf "wrong tupple size: expected 9 but got " n++parseArray :: (Int -> A.Parser a) -> A.Parser a+parseArray aget = do+ c <- A.anyWord8+ case c of+ _ | c .&. 0xF0 == 0x90 ->+ aget . fromIntegral $ c .&. 0x0F+ 0xDC ->+ aget . fromIntegral =<< parseUint16+ 0xDD ->+ aget . fromIntegral =<< parseUint32+ _ ->+ fail $ printf "invlid array tag: 0x%02X" c++instance (Unpackable k, Unpackable v) => Unpackable [(k, v)] where+ get = parseMap (flip replicateM parsePair)++instance (Unpackable k, Unpackable v) => Unpackable (V.Vector (k, v)) where+ get = parseMap (flip V.replicateM parsePair)++parsePair :: (Unpackable k, Unpackable v) => A.Parser (k, v)+parsePair = do+ a <- get+ b <- get+ return (a, b)++parseMap :: (Int -> A.Parser a) -> A.Parser a+parseMap aget = do+ c <- A.anyWord8+ case c of+ _ | c .&. 0xF0 == 0x80 ->+ aget . fromIntegral $ c .&. 0x0F+ 0xDE ->+ aget . fromIntegral =<< parseUint16+ 0xDF ->+ aget . fromIntegral =<< parseUint32+ _ ->+ fail $ printf "invlid map tag: 0x%02X" c++instance Unpackable a => Unpackable (Maybe a) where+ get = + A.choice+ [ liftM Just get+ , liftM (\() -> Nothing) get ]++parseUint16 :: A.Parser Word16+parseUint16 = do+ b0 <- A.anyWord8+ b1 <- A.anyWord8+ return $ (fromIntegral b0 `shiftL` 8) .|. fromIntegral b1++parseUint32 :: A.Parser Word32+parseUint32 = do+ b0 <- A.anyWord8+ b1 <- A.anyWord8+ b2 <- A.anyWord8+ b3 <- A.anyWord8+ return $ (fromIntegral b0 `shiftL` 24) .|.+ (fromIntegral b1 `shiftL` 16) .|.+ (fromIntegral b2 `shiftL` 8) .|.+ fromIntegral b3++parseUint64 :: A.Parser Word64+parseUint64 = do+ b0 <- A.anyWord8+ b1 <- A.anyWord8+ b2 <- A.anyWord8+ b3 <- A.anyWord8+ b4 <- A.anyWord8+ b5 <- A.anyWord8+ b6 <- A.anyWord8+ b7 <- A.anyWord8+ return $ (fromIntegral b0 `shiftL` 56) .|.+ (fromIntegral b1 `shiftL` 48) .|.+ (fromIntegral b2 `shiftL` 40) .|.+ (fromIntegral b3 `shiftL` 32) .|.+ (fromIntegral b4 `shiftL` 24) .|.+ (fromIntegral b5 `shiftL` 16) .|.+ (fromIntegral b6 `shiftL` 8) .|.+ fromIntegral b7++parseInt8 :: A.Parser Int8+parseInt8 = return . fromIntegral =<< A.anyWord8++parseInt16 :: A.Parser Int16+parseInt16 = return . fromIntegral =<< parseUint16++parseInt32 :: A.Parser Int32+parseInt32 = return . fromIntegral =<< parseUint32++parseInt64 :: A.Parser Int64+parseInt64 = return . fromIntegral =<< parseUint64++toLBS :: B.ByteString -> L.ByteString+toLBS bs = L.fromChunks [bs]
+ test/Test.hs view
@@ -0,0 +1,64 @@+import Test.Framework+import Test.Framework.Providers.QuickCheck2+import Test.QuickCheck++import Control.Monad+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy.Char8 as L+import Data.MessagePack++mid :: (Packable a, Unpackable a) => a -> a+mid = unpack . pack++prop_mid_int a = a == mid a+ where types = a :: Int+prop_mid_nil a = a == mid a+ where types = a :: ()+prop_mid_bool a = a == mid a+ where types = a :: Bool+prop_mid_double a = a == mid a+ where types = a :: Double+prop_mid_string a = a == mid a+ where types = a :: String+prop_mid_bytestring a = B.pack a == mid (B.pack a)+ where types = a :: String+prop_mid_lazy_bytestring a = (L.pack a) == mid (L.pack a)+ where types = a :: String+prop_mid_array_int a = a == mid a+ where types = a :: [Int]+prop_mid_array_string a = a == mid a+ where types = a :: [String]+prop_mid_pair2 a = a == mid a+ where types = a :: (Int, Int)+prop_mid_pair3 a = a == mid a+ where types = a :: (Int, Int, Int)+prop_mid_pair4 a = a == mid a+ where types = a :: (Int, Int, Int, Int)+prop_mid_pair5 a = a == mid a+ where types = a :: (Int, Int, Int, Int, Int)+prop_mid_map_int_double a = a == mid a+ where types = a :: [(Int, Double)]+prop_mid_map_string_string a = a == mid a+ where types = a :: [(String, String)]++tests =+ [ testGroup "simple"+ [ testProperty "int" prop_mid_int+ , testProperty "nil" prop_mid_nil+ , testProperty "bool" prop_mid_bool+ , testProperty "double" prop_mid_double+ , testProperty "string" prop_mid_string+ , testProperty "bytestring" prop_mid_bytestring+ , testProperty "lazy-bytestring" prop_mid_lazy_bytestring+ , testProperty "[int]" prop_mid_array_int+ , testProperty "[string]" prop_mid_array_string+ , testProperty "(int, int)" prop_mid_pair2+ , testProperty "(int, int, int)" prop_mid_pair3+ , testProperty "(int, int, int, int)" prop_mid_pair4+ , testProperty "(int, int, int, int, int)" prop_mid_pair5+ , testProperty "[(int, double)]" prop_mid_map_int_double+ , testProperty "[(string, string)]" prop_mid_map_string_string+ ]+ ]++main = defaultMain tests
+ test/UserData.hs view
@@ -0,0 +1,45 @@+{-# Language TemplateHaskell #-}++import Data.MessagePack+import Data.MessagePack.Derive++data T+ = A Int String+ | B Double+ deriving (Show)++$(deriveObject ''T)++data U+ = C { c1 :: Int, c2 :: String }+ | D { d1 :: Double }+ deriving (Show)++$(deriveObject ''U)++main = do+ let bs = pack $ A 123 "hoge"+ print bs+ print (unpack bs :: T)+ let cs = pack $ B 3.14+ print cs+ print (unpack cs :: T)+ let oa = toObject $ A 123 "hoge"+ print oa+ print (fromObject oa :: T)+ let ob = toObject $ B 3.14+ print ob+ print (fromObject ob :: T)++ let ds = pack $ C 123 "hoge"+ print ds+ print (unpack ds :: U)+ let es = pack $ D 3.14+ print es+ print (unpack es :: U)+ let oc = toObject $ C 123 "hoge"+ print oc+ print (fromObject oc :: U)+ let od = toObject $ D 3.14+ print od+ print (fromObject od :: U)