    {-|
    Copyright  :  (C) 2013-2016, University of Twente
                      2022-2024, Google Inc.
    License    :  BSD2 (see the file LICENSE)
    Maintainer :  Christiaan Baaij <christiaan.baaij@gmail.com>
    -}

    {-# LANGUAGE Trustworthy #-}
    {-# LANGUAGE TypeFamilies #-}

    {-# OPTIONS_HADDOCK show-extensions #-}

    module Clash.Sized.BitVector
      ( -- * Bit
        Bit
        -- ** Construction
        -- *** Initialisation
      , high
      , low
        -- * BitVector
      , BitVector
        -- ** Accessors
        -- *** Length information
      , size#
      , maxIndex#
        -- ** Construction
      , bLit
      , hLit
      , oLit
        -- ** Concatenation
      , (++#)
        -- * Modification
      , (+>>.)
      , (.<<+)
        -- ** Pattern matching
      , bitPattern
      )
    where

    import Clash.Sized.Internal.BitVector
    import Clash.Promoted.Nat (SNat(..), SNatLE(..), compareSNat, natToNum)
    import Data.Bits (shiftL, shiftR)
    import GHC.TypeNats (KnownNat)

    {- $setup
    >>> :set -XNumericUnderscores
    -}

    infixr 4 +>>.
    -- | Shift in a bit from the MSB side of a 'BitVector'. Equal to right shifting
    -- the 'BitVector' by one and replacing the MSB with the bit to be shifted in.
    --
    -- >>> 1 +>>. 0b1111_0000 :: BitVector 8
    -- 0b1111_1000
    -- >>> 0 +>>. 0b1111_0000 :: BitVector 8
    -- 0b0111_1000
    --
    (+>>.) :: forall n. KnownNat n => Bit -> BitVector n -> BitVector n
    Bit
    b +>>. :: forall (n :: Nat). KnownNat n => Bit -> BitVector n -> BitVector n
    +>>. BitVector n
    bv = case SNat n -> SNat 0 -> SNatLE n 0
    forall (a :: Nat) (b :: Nat). SNat a -> SNat b -> SNatLE a b
    compareSNat (forall (n :: Nat). KnownNat n => SNat n
    SNat @n) (forall (n :: Nat). KnownNat n => SNat n
    SNat @0) of
      SNatLE n 0
    SNatGT -> BitVector n -> Int -> Bit -> BitVector n
    forall (n :: Nat).
    KnownNat n =>
    BitVector n -> Int -> Bit -> BitVector n
    replaceBit# (BitVector n -> Int -> BitVector n
    forall a. Bits a => a -> Int -> a
    shiftR BitVector n
    bv Int
    1) (forall (n :: Nat) a. (Num a, KnownNat n) => a
    natToNum @n Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Int
    1) Bit
    b
      SNatLE n 0
    SNatLE -> BitVector n
    bv

    infixr 4 .<<+
    -- | Shift in a bit from the LSB side of a 'BitVector'. Equal to left shifting
    -- the 'BitVector' by one and replacing the LSB with the bit to be shifted in.
    --
    -- >>> 0b1111_0000 .<<+ 0 :: BitVector 8
    -- 0b1110_0000
    -- >>> 0b1111_0000 .<<+ 1 :: BitVector 8
    -- 0b1110_0001
    --
    (.<<+) :: forall n. KnownNat n => BitVector n -> Bit -> BitVector n
    BitVector n
    bv .<<+ :: forall (n :: Nat). KnownNat n => BitVector n -> Bit -> BitVector n
    .<<+ Bit
    b = case SNat n -> SNat 0 -> SNatLE n 0
    forall (a :: Nat) (b :: Nat). SNat a -> SNat b -> SNatLE a b
    compareSNat (forall (n :: Nat). KnownNat n => SNat n
    SNat @n) (forall (n :: Nat). KnownNat n => SNat n
    SNat @0) of
      SNatLE n 0
    SNatGT -> BitVector n -> Int -> Bit -> BitVector n
    forall (n :: Nat).
    KnownNat n =>
    BitVector n -> Int -> Bit -> BitVector n
    replaceBit# (BitVector n -> Int -> BitVector n
    forall a. Bits a => a -> Int -> a
    shiftL BitVector n
    bv Int
    1) Int
    0 Bit
    b
      SNatLE n 0
    SNatLE -> BitVector n
    bv