{-# LANGUAGE BangPatterns #-}

module Data.Bytes.Internal.Show
  ( showsSlice
  ) where

import Data.Bits (unsafeShiftR, (.&.))
import Data.Char (ord)
import Data.Primitive (ByteArray)
import Data.Word (Word8)
import GHC.Base (unsafeChr)

import qualified Data.Primitive as PM

showsSlice :: ByteArray -> Int -> Int -> String -> String
showsSlice :: ByteArray -> Int -> Int -> String -> String
showsSlice ByteArray
arr Int
off Int
len String
s =
  if Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0
    then String -> String -> String
showString String
"[]" String
s
    else
      String -> String -> String
showString String
"[0x" (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$
        Word8 -> String -> String
showHexDigitsWord8 (ByteArray -> Int -> Word8
forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray ByteArray
arr Int
off) (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$
          Int -> Int -> ByteArray -> String -> String
showHexLoop (Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) ByteArray
arr (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$
            Char -> String -> String
showChar Char
']' (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$
              String
s

showHexLoop :: Int -> Int -> ByteArray -> String -> String
showHexLoop :: Int -> Int -> ByteArray -> String -> String
showHexLoop !Int
ix !Int
len !ByteArray
arr String
s =
  if Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0
    then Char
',' Char -> String -> String
forall a. a -> [a] -> [a]
: Char
'0' Char -> String -> String
forall a. a -> [a] -> [a]
: Char
'x' Char -> String -> String
forall a. a -> [a] -> [a]
: Word8 -> String -> String
showHexDigitsWord8 (ByteArray -> Int -> Word8
forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray ByteArray
arr Int
ix) (Int -> Int -> ByteArray -> String -> String
showHexLoop (Int
ix Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) (Int
len Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1) ByteArray
arr String
s)
    else String
s

showHexDigitsWord8 :: Word8 -> String -> String
showHexDigitsWord8 :: Word8 -> String -> String
showHexDigitsWord8 !Word8
w String
s = Word8 -> Char
word4ToChar (Word8 -> Int -> Word8
forall a. Bits a => a -> Int -> a
unsafeShiftR Word8
w Int
4) Char -> String -> String
forall a. a -> [a] -> [a]
: Word8 -> Char
word4ToChar (Word8
0x0F Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
w) Char -> String -> String
forall a. a -> [a] -> [a]
: String
s

word4ToChar :: Word8 -> Char
word4ToChar :: Word8 -> Char
word4ToChar Word8
w =
  if Word8
w Word8 -> Word8 -> Bool
forall a. Ord a => a -> a -> Bool
< Word8
10
    then Int -> Char
unsafeChr (Char -> Int
ord Char
'0' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
w)
    else Int -> Char
unsafeChr (Char -> Int
ord Char
'a' Int -> Int -> Int
forall a. Num a => a -> a -> a
+ (Word8 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
w) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
10)