{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies          #-}

module HaskellWorks.Data.Bits.Word where

import Data.Word
import HaskellWorks.Data.Bits.BitLength
import HaskellWorks.Data.Bits.BitWise

class WordConcat a where
  type DoubleWords a
  -- | Concatenate two words in little-endian order of the same size into a
  -- word of twice the size.
  leConcat :: a -> a -> DoubleWords a

class WordSplit a where
  type HalfWords a
  -- | Split a word equally into two smaller words in little-endian order.
  leSplit :: a -> (HalfWords a, HalfWords a)

instance WordConcat Word8 where
  type DoubleWords Word8 = Word16
  leConcat :: Word8 -> Word8 -> DoubleWords Word8
leConcat Word8
a Word8
b = (Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
b Word16 -> Count -> Word16
forall a. Shift a => a -> Count -> a
.<. Word8 -> Count
forall v. BitLength v => v -> Count
bitLength Word8
a) Word16 -> Word16 -> Word16
forall a. BitWise a => a -> a -> a
.|. Word8 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
a

instance WordConcat Word16 where
  type DoubleWords Word16 = Word32
  leConcat :: Word16 -> Word16 -> DoubleWords Word16
leConcat Word16
a Word16
b = (Word16 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
b Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.<. Word16 -> Count
forall v. BitLength v => v -> Count
bitLength Word16
a) Word32 -> Word32 -> Word32
forall a. BitWise a => a -> a -> a
.|. Word16 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
a

instance WordConcat Word32 where
  type DoubleWords Word32 = Word64
  leConcat :: Word32 -> Word32 -> DoubleWords Word32
leConcat Word32
a Word32
b = (Word32 -> Count
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
b Count -> Count -> Count
forall a. Shift a => a -> Count -> a
.<. Word32 -> Count
forall v. BitLength v => v -> Count
bitLength Word32
a) Count -> Count -> Count
forall a. BitWise a => a -> a -> a
.|. Word32 -> Count
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
a

instance WordSplit Word64 where
  type HalfWords Word64 = Word32
  leSplit :: Count -> (HalfWords Count, HalfWords Count)
leSplit Count
a = (Count -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Count
a, Count -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Count
a Count -> Count -> Count
forall a. Shift a => a -> Count -> a
.>. Count
32))

instance WordSplit Word32 where
  type HalfWords Word32 = Word16
  leSplit :: Word32 -> (HalfWords Word32, HalfWords Word32)
leSplit Word32
a = (Word32 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
a, Word32 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word32
a Word32 -> Count -> Word32
forall a. Shift a => a -> Count -> a
.>. Count
16))

instance WordSplit Word16 where
  type HalfWords Word16 = Word8
  leSplit :: Word16 -> (HalfWords Word16, HalfWords Word16)
leSplit Word16
a = (Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word16
a, Word16 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word16
a Word16 -> Count -> Word16
forall a. Shift a => a -> Count -> a
.>. Count
8))