{-# LANGUAGE DataKinds            #-}
{-# LANGUAGE FlexibleContexts     #-}
{-# LANGUAGE TypeFamilies         #-}
{-# LANGUAGE TypeOperators        #-}
{-# LANGUAGE UndecidableInstances #-}
module CLaSH.Class.BitVector where

import CLaSH.Bit
import CLaSH.Sized.Vector
import GHC.TypeLits

-- | Convert types from and to a 'Vec'tor of 'Bit's
class BitVector a where
  -- | Number of 'Bit's needed to represents elements of type @a@
  type BitSize a :: Nat
  -- | Convert element of type @a@ to a 'Vec' of 'Bit's
  toBV   :: KnownNat (BitSize a) => a -> Vec (BitSize a) Bit
  -- | Convert a 'Vec' of 'Bit's to an element of type @a@
  fromBV :: KnownNat (BitSize a) => Vec (BitSize a) Bit -> a

instance BitVector Bit where
  type BitSize Bit = 1
  toBV   = (:> Nil)
  fromBV = vhead

instance BitVector Bool where
  type BitSize Bool = 1
  toBV   = (:> Nil) . toBit
    where
      toBit True  = H
      toBit False = L
  fromBV = fromBit . vhead
    where
      fromBit H = True
      fromBit L = False

instance (KnownNat (BitSize a), KnownNat (BitSize b), BitVector a, BitVector b) => BitVector (a,b) where
  type BitSize (a,b) = (BitSize a) + (BitSize b)
  toBV (a,b) = toBV a <++> toBV b
  fromBV bv  = (fromBV (vtakeI bv), fromBV (vdropI bv))

instance (KnownNat n, KnownNat (BitSize a), BitVector a) => BitVector (Vec n a) where
  type BitSize (Vec n a) = n * (BitSize a)
  toBV   = vconcat . vmap toBV
  fromBV = vmap fromBV . vunconcatI