{-# 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 #-} -- |Generics-based generation of Flat instances module Data.Flat.Class ( -- * The 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) -- import GHC.Magic(inline) -- |Class of types that can be encoded/decoded 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 -- |Calculate the size in bits of the serialisation of the value getSize :: Flat a => a -> NumBits getSize a = size a 0 -- |Generic Encoder class GEncode f where gencode :: f t -> Encoding -- Metadata (constructor name, etc) instance {-# OVERLAPPABLE #-} GEncode a => GEncode (M1 i c a) where gencode = gencode . unM1 {-# INLINE gencode #-} -- Special case, single constructor datatype instance {-# OVERLAPPING #-} (GEncoders a) => GEncode (D1 i (C1 c a)) where gencode !x = encodersS $ gencoders x id [] {-# INLINE gencode #-} -- Type without constructors instance GEncode V1 where gencode _ = unused {-# INLINE gencode #-} -- Constructor without arguments instance GEncode U1 where gencode U1 = mempty {-# INLINE gencode #-} -- Product: constructor with parameters instance GEncode (a :*: b) where gencode _ = unused {-# INLINE gencode #-} -- Constants, additional parameters, and rank-1 recursion instance Flat a => GEncode (K1 i a) where --gencode = inline encode . unK1 gencode = encode . unK1 {-# INLINE gencode #-} -- Build constructor representation as single tag 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 -- |Determine the list of encoders corresponding to a type 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 #-} -- Type without constructors instance GEncoders V1 where gencoders _ _ = unused -- Constructor without arguments instance GEncoders U1 where gencoders U1 !l = l {-# INLINE gencoders #-} -- Constants, additional parameters, and rank-1 recursion instance Flat a => GEncoders (K1 i a) where gencoders k !l = l . (gencode k :) {-# INLINE gencoders #-} -- Product: constructor with parameters 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)) -- |Calculate number of constructors type family NumConstructors (a :: * -> *) :: Nat where NumConstructors (C1 c a) = 1 NumConstructors (x :+: y) = NumConstructors x + NumConstructors y -- Generic Decoding class GDecode f where gget :: Get (f t) -- Metadata (constructor name, etc) instance GDecode a => GDecode (M1 i c a) where gget = M1 <$> gget {-# INLINE gget #-} -- Type without constructors instance GDecode V1 where gget = unused {-# INLINE gget #-} -- Constructor without arguments instance GDecode U1 where gget = pure U1 {-# INLINE gget #-} -- Product: constructor with parameters instance (GDecode a, GDecode b) => GDecode (a :*: b) where gget = (:*:) <$> gget <*> gget {-# INLINE gget #-} -- Constants, additional parameters, and rank-1 recursion instance Flat a => GDecode (K1 i a) where gget = K1 <$> decode {-# INLINE gget #-} -- Build constructor representation as single tag 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 #-} -- |Calculate the size of a value in bits 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 #-} -- Type without constructors instance GSize V1 where gsize !n _ = n {-# INLINE gsize #-} -- Constructor without arguments 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 #-} -- |Calculate size in bits of constructor 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.."