ribosome-0.2.2.0: lib/Ribosome/Msgpack/Encode.hs
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE TypeOperators #-}
module Ribosome.Msgpack.Encode(
MsgpackEncode(..),
) where
import Data.Bifunctor (bimap)
import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map (fromList, toList)
import Data.MessagePack (Object(..))
import GHC.Generics (
Generic,
Rep,
(:*:)(..),
M1(..),
D1,
C1,
S1,
K1(..),
Selector,
Constructor,
selName,
from,
conIsRecord,
)
import qualified Ribosome.Msgpack.Util as Util (string, assembleMap)
class MsgpackEncode a where
toMsgpack :: a -> Object
default toMsgpack :: (Generic a, GMsgpackEncode (Rep a)) => a -> Object
toMsgpack = gMsgpackEncode . from
class GMsgpackEncode f where
gMsgpackEncode :: f a -> Object
class MsgpackEncodeProd f where
msgpackEncodeRecord :: f a -> [(String, Object)]
msgpackEncodeProd :: f a -> [Object]
instance GMsgpackEncode f => GMsgpackEncode (D1 c f) where
gMsgpackEncode = gMsgpackEncode . unM1
prodOrNewtype :: MsgpackEncodeProd f => f a -> Object
prodOrNewtype =
wrap . msgpackEncodeProd
where
wrap [a] = a
wrap as = ObjectArray as
instance (Constructor c, MsgpackEncodeProd f) => GMsgpackEncode (C1 c f) where
gMsgpackEncode c =
f $ unM1 c
where
f = if conIsRecord c then Util.assembleMap . msgpackEncodeRecord else prodOrNewtype
instance (MsgpackEncodeProd f, MsgpackEncodeProd g) => MsgpackEncodeProd (f :*: g) where
msgpackEncodeRecord (f :*: g) = msgpackEncodeRecord f ++ msgpackEncodeRecord g
msgpackEncodeProd (f :*: g) = msgpackEncodeProd f ++ msgpackEncodeProd g
instance (Selector s, GMsgpackEncode f) => MsgpackEncodeProd (S1 s f) where
msgpackEncodeRecord s@(M1 f) = [(selName s, gMsgpackEncode f)]
msgpackEncodeProd (M1 f) = [gMsgpackEncode f]
instance MsgpackEncode a => GMsgpackEncode (K1 i a) where
gMsgpackEncode = toMsgpack . unK1
instance (Ord k, MsgpackEncode k, MsgpackEncode v) => MsgpackEncode (Map k v) where
toMsgpack = ObjectMap . Map.fromList . fmap (bimap toMsgpack toMsgpack) . Map.toList
instance MsgpackEncode Int where
toMsgpack = ObjectInt . fromIntegral
instance {-# OVERLAPPING #-} MsgpackEncode String where
toMsgpack = Util.string
instance {-# OVERLAPPABLE #-} MsgpackEncode a => MsgpackEncode [a] where
toMsgpack = ObjectArray . fmap toMsgpack
instance MsgpackEncode a => MsgpackEncode (Maybe a) where
toMsgpack = maybe ObjectNil toMsgpack
instance MsgpackEncode Bool where
toMsgpack = ObjectBool