msgpack-1.0.1.0: src/Data/MessagePack/Object.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE TypeSynonymInstances #-}
--------------------------------------------------------------------
-- |
-- Module : Data.MessagePack.Object
-- Copyright : © Hideyuki Tanaka 2009-2015
-- , © Herbert Valerio Riedel 2019
-- License : BSD3
--
-- MessagePack object definition
--
--------------------------------------------------------------------
module Data.MessagePack.Object(
-- * MessagePack Object
Object(..),
-- * MessagePack Serializable Types
MessagePack(..),
) where
import Control.Applicative
import Control.Arrow
import Control.DeepSeq
import Data.Binary
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Short as SBS
import Data.Hashable (Hashable)
import qualified Data.HashMap.Strict as HashMap
import qualified Data.IntMap.Strict as IntMap
import qualified Data.Map as Map
import qualified Data.Text as T
import qualified Data.Text.Lazy as LT
import Data.Typeable
import qualified Data.Vector as V
import GHC.Generics (Generic)
import Data.MessagePack.Assoc
import Data.MessagePack.Get
import Data.MessagePack.Put
import Prelude hiding (putStr)
-- | Object Representation of MessagePack data.
data Object
= ObjectNil
-- ^ represents nil
| ObjectBool !Bool
-- ^ represents true or false
| ObjectInt {-# UNPACK #-} !Int
-- ^ represents an integer
| ObjectFloat {-# UNPACK #-} !Float
-- ^ represents a floating point number
| ObjectDouble {-# UNPACK #-} !Double
-- ^ represents a floating point number
| ObjectStr !T.Text
-- ^ extending Raw type represents a UTF-8 string
| ObjectBin !S.ByteString
-- ^ extending Raw type represents a byte array
| ObjectArray !(V.Vector Object)
-- ^ represents a sequence of objects
| ObjectMap !(V.Vector (Object, Object))
-- ^ represents key-value pairs of objects
| ObjectExt {-# UNPACK #-} !Word8 !S.ByteString
-- ^ represents a tuple of an integer and a byte array where
-- the integer represents type information and the byte array represents data.
deriving (Show, Read, Eq, Ord, Typeable, Generic)
instance NFData Object where
rnf obj = case obj of
ObjectArray a -> rnf a
ObjectMap m -> rnf m
_ -> ()
getObject :: Get Object
getObject =
ObjectNil <$ getNil
<|> ObjectBool <$> getBool
<|> ObjectInt <$> getInt
<|> ObjectFloat <$> getFloat
<|> ObjectDouble <$> getDouble
<|> ObjectStr <$> getStr
<|> ObjectBin <$> getBin
<|> ObjectArray <$> getArray getObject
<|> ObjectMap <$> getMap getObject getObject
<|> uncurry ObjectExt <$> getExt
putObject :: Object -> Put
putObject = \case
ObjectNil -> putNil
ObjectBool b -> putBool b
ObjectInt n -> putInt n
ObjectFloat f -> putFloat f
ObjectDouble d -> putDouble d
ObjectStr t -> putStr t
ObjectBin b -> putBin b
ObjectArray a -> putArray putObject a
ObjectMap m -> putMap putObject putObject m
ObjectExt b r -> putExt b r
-- | This 'Binary' instance encodes\/decodes to\/from MessagePack format
instance Binary Object where
get = getObject
put = putObject
-- | Class for converting between MessagePack 'Object's and native Haskell types.
class MessagePack a where
toObject :: a -> Object
fromObject :: Object -> Maybe a
-- core instances
-- | The trivial identity 'MessagePack' instance
instance MessagePack Object where
toObject = id
fromObject = Just
-- | Encodes as 'ObjectNil'
instance MessagePack () where
toObject _ = ObjectNil
fromObject = \case
ObjectNil -> Just ()
_ -> Nothing
instance MessagePack Int where
toObject = ObjectInt
fromObject = \case
ObjectInt n -> Just n
_ -> Nothing
instance MessagePack Bool where
toObject = ObjectBool
fromObject = \case
ObjectBool b -> Just b
_ -> Nothing
instance MessagePack Float where
toObject = ObjectFloat
fromObject = \case
ObjectInt n -> Just $ fromIntegral n
ObjectFloat f -> Just f
ObjectDouble d -> Just $ realToFrac d
_ -> Nothing
instance MessagePack Double where
toObject = ObjectDouble
fromObject = \case
ObjectInt n -> Just $ fromIntegral n
ObjectFloat f -> Just $ realToFrac f
ObjectDouble d -> Just d
_ -> Nothing
instance MessagePack S.ByteString where
toObject = ObjectBin
fromObject = \case
ObjectBin r -> Just r
_ -> Nothing
-- Because of overlapping instance, this must be above [a]
instance MessagePack String where
toObject = toObject . T.pack
fromObject obj = T.unpack <$> fromObject obj
instance MessagePack a => MessagePack (V.Vector a) where
toObject = ObjectArray . V.map toObject
fromObject = \case
ObjectArray xs -> V.mapM fromObject xs
_ -> Nothing
instance (MessagePack a, MessagePack b) => MessagePack (Assoc (V.Vector (a, b))) where
toObject (Assoc xs) = ObjectMap $ V.map (toObject *** toObject) xs
fromObject = \case
ObjectMap xs ->
Assoc <$> V.mapM (\(k, v) -> (,) <$> fromObject k <*> fromObject v) xs
_ ->
Nothing
-- util instances
-- nullable
-- | 'Maybe's are encoded as nullable types, i.e. 'Nothing' is encoded as @nil@.
--
-- __NOTE__: Encoding nested 'Maybe's or 'Maybe's enclosing types which encode to @nil@ (such as '()') will break round-tripping
instance MessagePack a => MessagePack (Maybe a) where
toObject = \case
Just a -> toObject a
Nothing -> ObjectNil
fromObject = \case
ObjectNil -> Just Nothing
obj -> Just <$> fromObject obj
-- UTF8 string like
instance MessagePack L.ByteString where
toObject = ObjectBin . L.toStrict
fromObject obj = L.fromStrict <$> fromObject obj
-- | @since 1.0.1.0
instance MessagePack SBS.ShortByteString where
toObject = ObjectBin . SBS.fromShort
fromObject obj = SBS.toShort <$> fromObject obj
instance MessagePack T.Text where
toObject = ObjectStr
fromObject = \case
ObjectStr s -> Just s
_ -> Nothing
instance MessagePack LT.Text where
toObject = toObject . LT.toStrict
fromObject obj = LT.fromStrict <$> fromObject obj
-- array like
instance MessagePack a => MessagePack [a] where
toObject = toObject . V.fromList
fromObject obj = V.toList <$> fromObject obj
-- map like
instance (MessagePack k, MessagePack v) => MessagePack (Assoc [(k, v)]) where
toObject = toObject . Assoc . V.fromList . unAssoc
fromObject obj = Assoc . V.toList . unAssoc <$> fromObject obj
instance (MessagePack k, MessagePack v, Ord k) => MessagePack (Map.Map k v) where
toObject = toObject . Assoc . Map.toList
fromObject obj = Map.fromList . unAssoc <$> fromObject obj
instance MessagePack v => MessagePack (IntMap.IntMap v) where
toObject = toObject . Assoc . IntMap.toList
fromObject obj = IntMap.fromList . unAssoc <$> fromObject obj
instance (MessagePack k, MessagePack v, Hashable k, Eq k) => MessagePack (HashMap.HashMap k v) where
toObject = toObject . Assoc . HashMap.toList
fromObject obj = HashMap.fromList . unAssoc <$> fromObject obj
-- tuples
instance (MessagePack a1, MessagePack a2) => MessagePack (a1, a2) where
toObject (a1, a2) = ObjectArray [toObject a1, toObject a2]
fromObject (ObjectArray [a1, a2]) = (,) <$> fromObject a1 <*> fromObject a2
fromObject _ = Nothing
instance (MessagePack a1, MessagePack a2, MessagePack a3) => MessagePack (a1, a2, a3) where
toObject (a1, a2, a3) = ObjectArray [toObject a1, toObject a2, toObject a3]
fromObject (ObjectArray [a1, a2, a3]) = (,,) <$> fromObject a1 <*> fromObject a2 <*> fromObject a3
fromObject _ = Nothing
instance (MessagePack a1, MessagePack a2, MessagePack a3, MessagePack a4) => MessagePack (a1, a2, a3, a4) where
toObject (a1, a2, a3, a4) = ObjectArray [toObject a1, toObject a2, toObject a3, toObject a4]
fromObject (ObjectArray [a1, a2, a3, a4]) = (,,,) <$> fromObject a1 <*> fromObject a2 <*> fromObject a3 <*> fromObject a4
fromObject _ = Nothing
instance (MessagePack a1, MessagePack a2, MessagePack a3, MessagePack a4, MessagePack a5) => MessagePack (a1, a2, a3, a4, a5) where
toObject (a1, a2, a3, a4, a5) = ObjectArray [toObject a1, toObject a2, toObject a3, toObject a4, toObject a5]
fromObject (ObjectArray [a1, a2, a3, a4, a5]) = (,,,,) <$> fromObject a1 <*> fromObject a2 <*> fromObject a3 <*> fromObject a4 <*> fromObject a5
fromObject _ = Nothing
instance (MessagePack a1, MessagePack a2, MessagePack a3, MessagePack a4, MessagePack a5, MessagePack a6) => MessagePack (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]
fromObject (ObjectArray [a1, a2, a3, a4, a5, a6]) = (,,,,,) <$> fromObject a1 <*> fromObject a2 <*> fromObject a3 <*> fromObject a4 <*> fromObject a5 <*> fromObject a6
fromObject _ = Nothing
instance (MessagePack a1, MessagePack a2, MessagePack a3, MessagePack a4, MessagePack a5, MessagePack a6, MessagePack a7) => MessagePack (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]
fromObject (ObjectArray [a1, a2, a3, a4, a5, a6, a7]) = (,,,,,,) <$> fromObject a1 <*> fromObject a2 <*> fromObject a3 <*> fromObject a4 <*> fromObject a5 <*> fromObject a6 <*> fromObject a7
fromObject _ = Nothing
instance (MessagePack a1, MessagePack a2, MessagePack a3, MessagePack a4, MessagePack a5, MessagePack a6, MessagePack a7, MessagePack a8) => MessagePack (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]
fromObject (ObjectArray [a1, a2, a3, a4, a5, a6, a7, a8]) = (,,,,,,,) <$> fromObject a1 <*> fromObject a2 <*> fromObject a3 <*> fromObject a4 <*> fromObject a5 <*> fromObject a6 <*> fromObject a7 <*> fromObject a8
fromObject _ = Nothing
instance (MessagePack a1, MessagePack a2, MessagePack a3, MessagePack a4, MessagePack a5, MessagePack a6, MessagePack a7, MessagePack a8, MessagePack a9) => MessagePack (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]
fromObject (ObjectArray [a1, a2, a3, a4, a5, a6, a7, a8, a9]) = (,,,,,,,,) <$> fromObject a1 <*> fromObject a2 <*> fromObject a3 <*> fromObject a4 <*> fromObject a5 <*> fromObject a6 <*> fromObject a7 <*> fromObject a8 <*> fromObject a9
fromObject _ = Nothing