{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Flat.Class (
Flat(..)
,getSize
,module GHC.Generics
) where
import Data.Flat.Decoder (Get, dBool)
import Data.Flat.Encoder
import Data.Proxy
import GHC.Generics
import GHC.TypeLits
import Prelude hiding (mempty)
class Flat a where
{-# INLINE encode #-}
encode :: a -> Encoding
default encode :: (Generic a, GEncode (Rep a)) => a -> Encoding
encode = genericEncode
{-# INLINE decode #-}
decode :: Get a
default decode :: (Generic a, GDecode (Rep a)) => Get a
decode = genericDecode
{-# INLINE size #-}
size :: a -> NumBits -> NumBits
default size :: (Generic a, GSize (Rep a)) => a -> NumBits -> NumBits
size = genericSize
{-# INLINE genericEncode #-}
genericEncode :: (GEncode (Rep a), Generic a) => a -> Encoding
genericEncode = gencode . from
{-# INLINE genericDecode #-}
genericDecode :: (GDecode (Rep b), Generic b) => Get b
genericDecode = to `fmap` gget
{-# INLINE genericSize #-}
genericSize :: (GSize (Rep a), Generic a) => a -> NumBits -> NumBits
genericSize !x !n = gsize n $ from x
getSize :: Flat a => a -> NumBits
getSize a = size a 0
class GEncode f where
gencode :: f t -> Encoding
instance {-# OVERLAPPABLE #-} GEncode a => GEncode (M1 i c a) where
gencode = gencode . unM1
{-# INLINE gencode #-}
instance {-# OVERLAPPING #-} (GEncoders a) => GEncode (D1 i (C1 c a)) where
gencode !x = encodersS $ gencoders x id []
{-# INLINE gencode #-}
instance GEncode V1 where
gencode _ = unused
{-# INLINE gencode #-}
instance GEncode U1 where
gencode U1 = mempty
{-# INLINE gencode #-}
instance GEncode (a :*: b) where
gencode _ = unused
{-# INLINE gencode #-}
instance Flat a => GEncode (K1 i a) where
gencode = encode . unK1
{-# INLINE gencode #-}
instance (NumConstructors (a :+: b) <= 255, GEncodeSum 0 0 (a :+: b)) => GEncode (a :+: b) where
gencode x = gencodeSum x (Proxy :: Proxy 0) (Proxy :: Proxy 0)
{-# INLINE gencode #-}
class GEncoders f where
gencoders :: f t -> ([Encoding] -> [Encoding]) -> ([Encoding] -> [Encoding])
instance {-# OVERLAPPABLE #-} GEncoders a => GEncoders (M1 i c a) where
gencoders m !l = gencoders (unM1 m) l
{-# INLINE gencoders #-}
instance {-# OVERLAPPING #-} GEncoders a => GEncoders (D1 i (C1 c a)) where
gencoders x !l = gencoders (unM1 . unM1 $ x) l
{-# INLINE gencoders #-}
instance GEncoders V1 where
gencoders _ _ = unused
instance GEncoders U1 where
gencoders U1 !l = l
{-# INLINE gencoders #-}
instance Flat a => GEncoders (K1 i a) where
gencoders k !l = l . (gencode k :)
{-# INLINE gencoders #-}
instance (GEncoders a, GEncoders b) => GEncoders (a :*: b) where
gencoders (x :*: y) !l = gencoders y (gencoders x l)
{-# INLINE gencoders #-}
class (KnownNat code, KnownNat numBits) =>
GEncodeSum (numBits:: Nat) (code :: Nat) (f :: * -> *) where
gencodeSum :: f a -> Proxy numBits -> Proxy code -> Encoding
instance (GEncodeSum (n+1) (m*2) a,GEncodeSum (n+1) (m*2+1) b, KnownNat n,KnownNat m)
=> GEncodeSum n m (a :+: b) where
gencodeSum !x _ _ = case x of
L1 l -> gencodeSum l (Proxy :: Proxy (n+1)) (Proxy :: Proxy (m*2))
R1 r -> gencodeSum r (Proxy :: Proxy (n+1)) (Proxy :: Proxy (m*2+1))
{-# INLINE gencodeSum #-}
instance (GEncoders a, KnownNat n,KnownNat m) => GEncodeSum n m (C1 c a) where
{-# INLINE gencodeSum #-}
gencodeSum !x _ _ = encodersS $ gencoders x (eBits numBits code:) []
where
numBits = fromInteger (natVal (Proxy :: Proxy n))
code = fromInteger (natVal (Proxy :: Proxy m))
type family NumConstructors (a :: * -> *) :: Nat where
NumConstructors (C1 c a) = 1
NumConstructors (x :+: y) = NumConstructors x + NumConstructors y
class GDecode f where
gget :: Get (f t)
instance GDecode a => GDecode (M1 i c a) where
gget = M1 <$> gget
{-# INLINE gget #-}
instance GDecode V1 where
gget = unused
{-# INLINE gget #-}
instance GDecode U1 where
gget = pure U1
{-# INLINE gget #-}
instance (GDecode a, GDecode b) => GDecode (a :*: b) where
gget = (:*:) <$> gget <*> gget
{-# INLINE gget #-}
instance Flat a => GDecode (K1 i a) where
gget = K1 <$> decode
{-# INLINE gget #-}
instance (GDecode a, GDecode b) => GDecode (a :+: b) where
gget = do
!tag <- dBool
!r <- if tag then R1 <$> gget else L1 <$> gget
return r
{-# INLINE gget #-}
class GSize f where gsize :: NumBits -> f a -> NumBits
instance GSize f => GSize (M1 i c f) where
gsize !n = gsize n . unM1
{-# INLINE gsize #-}
instance GSize V1 where
gsize !n _ = n
{-# INLINE gsize #-}
instance GSize U1 where
gsize !n _ = n
{-# INLINE gsize #-}
instance Flat a => GSize (K1 i a) where
gsize !n x = size (unK1 x) n
{-# INLINE gsize #-}
instance (GSize a, GSize b) => GSize (a :*: b) where
gsize !n (x :*: y) = gsize (gsize n x) y
{-# INLINE gsize #-}
instance (NumConstructors (a :+: b) <= 255, GSizeSum 0 (a :+: b)) => GSize (a :+: b) where
gsize !n x = gsizeSum n x (Proxy :: Proxy 0)
{-# INLINE gsize #-}
class KnownNat n => GSizeSum (n :: Nat) (f :: * -> *) where gsizeSum :: NumBits -> f a -> Proxy n -> NumBits
instance (GSizeSum (n + 1) a, GSizeSum (n + 1) b, KnownNat n)
=> GSizeSum n (a :+: b) where
gsizeSum !n x _ = case x of
L1 !l -> gsizeSum n l (Proxy :: Proxy (n+1))
R1 !r -> gsizeSum n r (Proxy :: Proxy (n+1))
{-# INLINE gsizeSum #-}
instance (GSize a, KnownNat n) => GSizeSum n (C1 c a) where
{-# INLINE gsizeSum #-}
gsizeSum !n !x _ = gsize (constructorSize + n) x
where
constructorSize = fromInteger (natVal (Proxy :: Proxy n))
unused :: forall a . a
unused = error $ "Now, now, you could not possibly have meant this.."