{-# LANGUAGE UndecidableInstances #-}

module Z.Data.Generics.Utils
  ( ProductSize(..)
  , productSize
  ) where

import GHC.Generics
import GHC.TypeNats
import GHC.Exts (Proxy#, proxy#)

-- | type class for calculating product size.
class KnownNat (PSize f) => ProductSize (f :: * -> *) where
    type PSize f :: Nat

instance ProductSize (S1 s a) where
    type PSize (S1 s a) = 1
instance (KnownNat (PSize a + PSize b), ProductSize a, ProductSize b) => ProductSize (a :*: b) where
    type PSize (a :*: b) = PSize a + PSize b

productSize :: forall f. KnownNat (PSize f) => Proxy# f -> Int
productSize _ = fromIntegral (natVal' (proxy# :: Proxy# (PSize f)))