module Data.Bits.Pretty
  (
  -- * Show in base
    showBin
  , showDec
  , showHex
  , formatHex
  -- * Show binary groups
  , showBinGroups
  -- * Size of Int
  , platformSizeOfInt
  -- * Shorthand
  , showHex8
  , showHex16
  , showHex32
  ) where

import Data.Bits (FiniteBits, (.&.), shiftR)
import Data.Word (Word8, Word16, Word32)
import Text.Printf (PrintfArg, printf)
import qualified Data.Bits

-- * Show in base

-- | Format number using binary notation with leading 0b,
-- padded according to its bit size
showBin :: (PrintfArg t, FiniteBits t) => t -> String
showBin :: forall t. (PrintfArg t, FiniteBits t) => t -> String
showBin t
x =
  forall r. PrintfType r => String -> r
printf
    (String
"0b%0"
    forall a. [a] -> [a] -> [a]
++ (forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$ forall b. FiniteBits b => b -> Int
Data.Bits.finiteBitSize t
x)
    forall a. [a] -> [a] -> [a]
++ String
"b"
    )
    t
x

-- | Format number using decimal
showDec :: (PrintfArg t, FiniteBits t) => t -> String
showDec :: forall t. (PrintfArg t, FiniteBits t) => t -> String
showDec t
x =
  forall r. PrintfType r => String -> r
printf (String
"%0" forall a. [a] -> [a] -> [a]
++ (forall a. Show a => a -> String
show Int
decSize) forall a. [a] -> [a] -> [a]
++ String
"u") t
x
  where
    decSize :: Int
    decSize :: Int
decSize =
      forall a b. (RealFrac a, Integral b) => a -> b
ceiling
      forall a b. (a -> b) -> a -> b
$ forall a. Floating a => a -> a -> a
logBase
          (Double
10 :: Double)
          (Double
2 forall a b. (Num a, Integral b) => a -> b -> a
^ (forall b. FiniteBits b => b -> Int
Data.Bits.finiteBitSize t
x))

-- | Format number using hexadecimal notation with leading 0x,
-- padded according to its bit size
showHex :: (PrintfArg t, FiniteBits t) => t -> String
showHex :: forall t. (PrintfArg t, FiniteBits t) => t -> String
showHex t
x =
  forall r. PrintfType r => String -> r
printf
    (String
"0x%0"
    forall a. [a] -> [a] -> [a]
++ (forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$ forall b. FiniteBits b => b -> Int
Data.Bits.finiteBitSize t
x forall a. Integral a => a -> a -> a
`div` Int
4)
    forall a. [a] -> [a] -> [a]
++ String
"X"
    )
    t
x

-- | Format number using hexadecimal notation with leading 0x
formatHex :: PrintfArg t => t -> String
formatHex :: forall t. PrintfArg t => t -> String
formatHex = forall r. PrintfType r => String -> r
printf String
"0x%x"

-- * Show binary groups

-- | Print number in binary with bits grouped by `groupSize`
-- e.g. with `groupSize = 4` we would get `0000 1010 0000 0101`
showBinGroups :: (PrintfArg b, Num b, FiniteBits b) => Int -> b -> String
showBinGroups :: forall b. (PrintfArg b, Num b, FiniteBits b) => Int -> b -> String
showBinGroups Int
groupSize b
x =
  [String] -> String
unwords
    forall a b. (a -> b) -> a -> b
$ forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a b. (a -> b) -> [a] -> [b]
map [Int
gs forall a. Num a => a -> a -> a
-Int
1 ,Int
gs forall a. Num a => a -> a -> a
- Int
2 .. Int
0]
    forall a b. (a -> b) -> a -> b
$ \Int
g -> ((forall r. PrintfType r => String -> r
printf (String
"%0" forall a. [a] -> [a] -> [a]
++ (forall a. Show a => a -> String
show Int
groupSize) forall a. [a] -> [a] -> [a]
++ String
"b") (forall {a}. (Bits a, Num a) => Int -> a -> a
mask Int
g b
x)) :: String)
  where
    mask :: Int -> a -> a
mask Int
g a
n = (a
2forall a b. (Num a, Integral b) => a -> b -> a
^Int
groupSize forall a. Num a => a -> a -> a
- a
1) forall a. Bits a => a -> a -> a
.&. (a
n forall a. Bits a => a -> Int -> a
`shiftR` (forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
g forall a. Num a => a -> a -> a
* Int
groupSize)))
    gs :: Int
gs = Int
sz forall a. Integral a => a -> a -> a
`div` Int
groupSize
    sz :: Int
sz = forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall b. FiniteBits b => b -> Int
Data.Bits.finiteBitSize b
x

-- * Size of Int

-- | Size of `Int` at the current platform
platformSizeOfInt :: Int
platformSizeOfInt :: Int
platformSizeOfInt = forall b. FiniteBits b => b -> Int
Data.Bits.finiteBitSize (Int
0 :: Int)

-- * Shorthand

-- | Format Int as 32-bit unsigned hexadecimal string
showHex32 :: Int -> String
showHex32 :: Int -> String
showHex32 = forall t. (PrintfArg t, FiniteBits t) => t -> String
showHex forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a b. (Integral a, Num b) => a -> b
fromIntegral :: Int -> Word32)

-- | Format Int as 16-bit unsigned hexadecimal string
showHex16 :: Int -> String
showHex16 :: Int -> String
showHex16 = forall t. (PrintfArg t, FiniteBits t) => t -> String
showHex forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a b. (Integral a, Num b) => a -> b
fromIntegral :: Int -> Word16)

-- | Format Int as 8-bit unsigned hexadecimal string
showHex8 :: Int -> String
showHex8 :: Int -> String
showHex8  = forall t. (PrintfArg t, FiniteBits t) => t -> String
showHex forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall a b. (Integral a, Num b) => a -> b
fromIntegral :: Int -> Word8)