packages feed

ribosome-host-0.9.9.9: lib/Ribosome/Host/Class/Msgpack/DecodeSOP.hs

module Ribosome.Host.Class.Msgpack.DecodeSOP where

import Data.MessagePack (Object (..))
import Generics.SOP (All2, I (I), NP (Nil, (:*)), NS (Z), SOP (SOP), Top)
import Generics.SOP.GGP (GCode, GDatatypeInfoOf, GFrom, GTo, gto)
import Generics.SOP.Type.Metadata (ConstructorInfo, DatatypeInfo (ADT, Newtype))

type ReifySOP (d :: Type) (dss :: [[Type]]) =
  (Generic d, GTo d, GCode d ~ dss, All2 Top dss)

type ConstructSOP (d :: Type) (dss :: [[Type]]) =
  (Generic d, GFrom d, GCode d ~ dss, All2 Top dss)

class MsgpackCtor (ctor :: ConstructorInfo) (as :: [Type]) where

class MsgpackCtors (ctors :: [ConstructorInfo]) (ass :: [[Type]]) where
  msgpackCtors :: Object -> Either Text (SOP I ass)

class GMsgpackDecode (dt :: DatatypeInfo) (ass :: [[Type]]) where
  gMsgpackDecode :: Object -> Either Text (SOP I ass)

instance (
    MsgpackDecode a
  ) => GMsgpackDecode ('Newtype mod name ctor) '[ '[a]] where
    gMsgpackDecode o = do
      a <- fromMsgpack o
      pure (SOP (Z (I a :* Nil)))

instance (
    MsgpackCtors ctors ass
  ) => GMsgpackDecode ('ADT mod name ctors strictness) ass where
  gMsgpackDecode =
      msgpackCtors @ctors

class MsgpackDecode a where
  fromMsgpack :: Object -> Either Text a
  default fromMsgpack ::
    ConstructSOP a ass =>
    ReifySOP a ass =>
    GMsgpackDecode (GDatatypeInfoOf a) (GCode a) =>
    Object ->
    Either Text a
  fromMsgpack =
    fmap gto . gMsgpackDecode @(GDatatypeInfoOf a)

  -- missingKey :: String -> Object -> Either Text a
  -- missingKey = Util.missingRecordKey

pattern Msgpack :: ∀ a . MsgpackDecode a => a -> Object
pattern Msgpack a <- (fromMsgpack -> Right a)