ribosome-host-0.9.9.9: lib/Ribosome/Host/Class/Msgpack/Encode.hs
{-# options_haddock prune #-}
-- |Encoding values to MessagePack format
module Ribosome.Host.Class.Msgpack.Encode where
import qualified Data.List.NonEmpty as NonEmpty (toList)
import qualified Data.Map.Strict as Map (fromList, toList)
import Data.MessagePack (Object (..))
import GHC.Generics (
C1,
Constructor,
D1,
K1 (..),
M1 (..),
Rep,
S1,
Selector,
conIsRecord,
from,
selName,
(:*:) (..),
(:+:) (..),
)
import Path (Path, toFilePath)
import Time (MicroSeconds, MilliSeconds (unMilliSeconds), NanoSeconds (unNanoSeconds), Seconds, unMicroSeconds, unSeconds)
import qualified Ribosome.Host.Class.Msgpack.Util as Util (assembleMap, string, text)
-- |Class of values that can be encoded to MessagePack 'Object's.
class MsgpackEncode a where
-- |Convert a value to MessagePack.
--
-- The default implementation uses generic derivation.
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 (GMsgpackEncode f, GMsgpackEncode g) => GMsgpackEncode (f :+: g) where
gMsgpackEncode (L1 a) = gMsgpackEncode a
gMsgpackEncode (R1 a) = gMsgpackEncode a
instance (Selector s, GMsgpackEncode f) => MsgpackEncodeProd (S1 s f) where
msgpackEncodeRecord s@(M1 f) =
[(dropWhile ('_' ==) (selName s), gMsgpackEncode f), (selName s, gMsgpackEncode f)]
msgpackEncodeProd (M1 f) = [gMsgpackEncode f]
instance MsgpackEncode a => GMsgpackEncode (K1 i a) where
gMsgpackEncode = toMsgpack . unK1
instance (
MsgpackEncode k,
MsgpackEncode v
) => MsgpackEncode (Map k v) where
toMsgpack = ObjectMap . Map.fromList . fmap (bimap toMsgpack toMsgpack) . Map.toList
instance MsgpackEncode Integer where
toMsgpack = ObjectInt . fromInteger
instance MsgpackEncode Int where
toMsgpack = ObjectInt . fromIntegral
instance MsgpackEncode Int64 where
toMsgpack = ObjectInt
instance MsgpackEncode Float where
toMsgpack = ObjectFloat
instance MsgpackEncode Double where
toMsgpack = ObjectDouble
instance {-# overlapping #-} MsgpackEncode String where
toMsgpack = Util.string
instance {-# overlappable #-} MsgpackEncode a => MsgpackEncode [a] where
toMsgpack = ObjectArray . fmap toMsgpack
instance MsgpackEncode a => MsgpackEncode (NonEmpty a) where
toMsgpack = toMsgpack . NonEmpty.toList
instance MsgpackEncode a => MsgpackEncode (Seq a) where
toMsgpack = toMsgpack . toList
instance MsgpackEncode Text where
toMsgpack = Util.text
instance MsgpackEncode a => MsgpackEncode (Maybe a) where
toMsgpack = maybe ObjectNil toMsgpack
instance MsgpackEncode Bool where
toMsgpack = ObjectBool
instance MsgpackEncode () where
toMsgpack _ = ObjectNil
instance MsgpackEncode Object where
toMsgpack = id
instance MsgpackEncode ByteString where
toMsgpack = ObjectString
instance (MsgpackEncode a, MsgpackEncode b) => MsgpackEncode (a, b) where
toMsgpack (a, b) =
ObjectArray [toMsgpack a, toMsgpack b]
instance (MsgpackEncode a, MsgpackEncode b, MsgpackEncode c) => MsgpackEncode (a, b, c) where
toMsgpack (a, b, c) =
ObjectArray [toMsgpack a, toMsgpack b, toMsgpack c]
instance MsgpackEncode (Path b t) where
toMsgpack = ObjectString . encodeUtf8 . toFilePath
instance MsgpackEncode NanoSeconds where
toMsgpack =
toMsgpack . unNanoSeconds
instance MsgpackEncode MicroSeconds where
toMsgpack =
toMsgpack . unMicroSeconds
instance MsgpackEncode MilliSeconds where
toMsgpack =
toMsgpack . unMilliSeconds
instance MsgpackEncode Seconds where
toMsgpack =
toMsgpack . unSeconds