sqel-0.0.1.0: lib/Sqel/Codec/Product.hs
module Sqel.Codec.Product where
import Generics.SOP (
All,
I,
K (K),
NP,
NS (Z),
Projection,
SOP (SOP),
Top,
hcmap,
hcollapse,
hsequence,
hzipWith,
projections,
unI,
unSOP,
unZ,
type (-.->) (Fn),
)
import Generics.SOP.GGP (gfrom, gto)
import Lens.Micro.Extras (view)
import qualified Sqel.Data.Codec as Codec
import Sqel.Data.Codec (Codec (Codec), Decoder, Encoder, FullCodec)
import Sqel.SOP.Constraint (ConstructProd, ReifyProd)
prodParams ::
∀ as b .
Contravariant b =>
(∀ x . Monoid (b x)) =>
All Top as =>
NP b as ->
b (NP I as)
prodParams np =
mconcat (hcollapse qps)
where
qps :: NP (K (b (NP I as))) as
qps =
hzipWith qp np (projections :: NP (Projection I as) as)
{-# inline qps #-}
qp :: ∀ a . b a -> Projection I as a -> K (b (NP I as)) a
qp par (Fn proj) =
K (contramap (unI . proj . K) par)
{-# inline qp #-}
{-# inline prodParams #-}
type GetEncoder :: (Type -> Type) -> Type -> Constraint
class GetEncoder b a where
getEncoder :: b a -> Encoder a
instance GetEncoder FullCodec a where
getEncoder = view #encoder
instance GetEncoder Encoder a where
getEncoder = id
type GetDecoder :: (Type -> Type) -> Type -> Constraint
class GetDecoder b a where
getDecoder :: b a -> Decoder a
instance GetDecoder FullCodec a where
getDecoder = view #decoder
type ProdEncoder :: (Type -> Type) -> Type -> [Type] -> Constraint
class ProdEncoder b a as | a -> as where
prodEncoder :: NP b as -> Encoder a
instance (
ConstructProd a as,
All (GetEncoder b) as
) => ProdEncoder b a as where
prodEncoder np = unZ . unSOP . gfrom >$< prodParams (hcmap (Proxy @(GetEncoder b)) getEncoder np)
type ProdDecoder :: (Type -> Type) -> Type -> [Type] -> Constraint
class ProdDecoder b a as | a -> as where
prodDecoder :: NP b as -> Decoder a
instance (
ReifyProd a as,
All (GetDecoder b) as
) => ProdDecoder b a as where
prodDecoder np = gto . SOP . Z <$> hsequence (hcmap (Proxy @(GetDecoder b)) getDecoder np)
type ProdCodec :: (Type -> Type) -> Type -> [Type] -> Constraint
class ProdCodec b a as | a -> as where
prodCodec :: NP b as -> b a
instance (
ProdDecoder FullCodec a as,
ProdEncoder FullCodec a as
) => ProdCodec FullCodec a as where
prodCodec np =
Codec {
decoder = prodDecoder np,
encoder = prodEncoder np
}
instance (
ProdEncoder Encoder a as
) => ProdCodec Encoder a as where
prodCodec = prodEncoder