content: {-|
  Copyright  :  (C) 2018, Google Inc.
  License    :  BSD2 (see the file LICENSE)
  Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
  
  Using /ANN/ pragma's you can tell the Clash compiler to use a custom
  bit representation for a data type. See @DataReprAnn@ for documentation.
  
  -}
  
  {-# LANGUAGE RankNTypes #-}
  
  {-# OPTIONS_GHC -Wno-orphans #-}
  
  module Clash.Annotations.BitRepresentation
   (
   -- * Data structures to express a custom bit representation
     DataReprAnn(..)
   , ConstrRepr(..)
   -- * Convenience type synonyms for Integer
   , BitMask
   , Value
   , Size
   , FieldAnn
  
   -- * Functions
   , liftQ
   ) where
  
  import           Data.Data                  (Data)
  import           Data.Typeable              (Typeable)
  import           Language.Haskell.TH.Instances ()
  import qualified Language.Haskell.TH.Lift   ()
  import qualified Language.Haskell.TH.Syntax as TH
  import           GHC.Generics               (Generic)
  
  type BitMask  = Integer
  type Value    = Integer
  type Size     = Int
  
  -- | BitMask used to mask fields
  type FieldAnn = BitMask
  
  -- | Lift values inside of 'TH.Q' to a Template Haskell expression
  liftQ :: TH.Lift a => TH.Q a -> TH.Q TH.Exp
  liftQ = (>>= TH.lift)
  
  -- NOTE: The following instances are imported from Language.Haskell.TH.Lift.
  -- This module also implements 'instance Lift Exp', which might make debugging
  -- template haskell more difficult. Please uncomment these instances and the
  -- import of TH.Lift whenever it suits you.
  --
  --deriving instance TH.Lift TH.Name
  --deriving instance TH.Lift TH.OccName
  --deriving instance TH.Lift TH.NameFlavour
  --deriving instance TH.Lift TH.ModName
  --deriving instance TH.Lift TH.NameSpace
  --deriving instance TH.Lift TH.PkgName
  
  
  -- | Annotation for custom bit representations of data types
  --
  -- Using /ANN/ pragma's you can tell the Clash compiler to use a custom
  -- bit-representation for a data type.
  --
  -- For example:
  --
  -- @
  -- data Color = R | G | B
  -- {-# ANN module ('DataReprAnn'
  --                   $('liftQ' [t|Color|])
  --                   2
  --                   [ 'ConstrRepr' 'R 0b11 0b00 []
  --                   , 'ConstrRepr' 'G 0b11 0b01 []
  --                   , 'ConstrRepr' 'B 0b11 0b10 []
  --                   ]) #-}
  -- @
  --
  -- This specifies that @R@ should be encoded as 0b00, @G@ as 0b01, and
  -- @B@ as 0b10. The first binary value in every @ConstrRepr@ in this example
  -- is a mask, indicating which bits in the data type are relevant. In this case
  -- all of the bits are.
  --
  -- Or if we want to annotate @Maybe Color@:
  --
  -- @
  -- {-# ANN module ( 'DataReprAnn'
  --                    $('liftQ' [t|Maybe Color|])
  --                    2
  --                    [ 'ConstrRepr' 'Nothing 0b11 0b11 []
  --                    , 'ConstrRepr' 'Just 0b00 0b00 [0b11]
  --                    ] ) #-}
  -- @
  --
  -- By default, @Maybe Color@ is a data type which consumes 3 bits. A single bit
  -- to indicate the constructor (either @Just@ or @Nothing@), and two bits to encode
  -- the first field of @Just@. Notice that we saved a single bit by exploiting
  -- the fact that @Color@ only uses three values (0, 1, 2), but takes two bits
  -- to encode it. We can therefore use the last - unused - value (3), to encode
  -- one of the constructors of @Maybe@. We indicate which bits encode the
  -- underlying @Color@ field of @Just@ by passing /[0b11]/ to ConstrRepr. This
  -- indicates that the first field is encoded in the first and second bit of the
  -- whole datatype (0b11).
  --
  -- __NB__: BitPack for a custom encoding can be derived using
  -- 'Clash.Annotations.BitRepresentation.Deriving.deriveBitPack'.
  data DataReprAnn =
    DataReprAnn
      -- Type this annotation is for:
      TH.Type
      -- Size of type:
      Size
      -- Constructors:
      [ConstrRepr]
        deriving (Show, Data, Typeable, Eq, Generic, TH.Lift)
  
  -- | Annotation for constructors. Indicates how to match this constructor based
  -- off of the whole datatype.
  data ConstrRepr =
    ConstrRepr
      -- Constructor name:
      TH.Name
      -- Bits relevant for this constructor:
      BitMask
      -- data & mask should be equal to..:
      Value
      -- Masks for fields. Indicates where fields are stored:
      [FieldAnn]
        deriving (Show, Data, Typeable, Eq, Generic, TH.Lift)
  