{-|
Module:      Z.Data.Builder.UUID
Description : Builders for UUID.
Copyright:   (c) 2021 Dong Han
License:     BSD3
Maintainer:  Dong <winterland1989@gmail.com>
Stability:   experimental
Portability: portable

Builders for UUID.
-}

module Z.Data.Builder.UUID
    ( uuid, uuidUpper
    , encodeUUID
    ) where

import           Data.UUID.Types.Internal
import           Data.Word
import           Data.Bits
import           Z.Data.ASCII
import qualified Z.Data.Builder.Base         as B
import qualified Z.Data.Builder.Numeric      as B

-- | Write texutal UUID bytes, e.g. @550e8400-e29b-41d4-a716-446655440000@
uuid :: UUID -> B.Builder ()
{-# INLINABLE uuid #-}
uuid :: UUID -> Builder ()
uuid (UUID Word64
wh Word64
wl) =  do
    let !w1 :: Word32
w1 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word32 forall a b. (a -> b) -> a -> b
$ Word64
wh forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
32
        !w2 :: Word16
w2 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word16 forall a b. (a -> b) -> a -> b
$ Word64
wh forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
16 forall a. Bits a => a -> a -> a
.&. Word64
0xFFFF
        !w3 :: Word16
w3 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word16 forall a b. (a -> b) -> a -> b
$ Word64
wh forall a. Bits a => a -> a -> a
.&. Word64
0xFFFF
        !w4 :: Word16
w4 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word16 forall a b. (a -> b) -> a -> b
$ Word64
wl forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
48
        !w5 :: Word16
w5 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word16 forall a b. (a -> b) -> a -> b
$ Word64
wl forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
32 forall a. Bits a => a -> a -> a
.&. Word64
0xFFFF
        !w6 :: Word32
w6 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word32 forall a b. (a -> b) -> a -> b
$ Word64
wl forall a. Bits a => a -> a -> a
.&. Word64
0xFFFFFFFF
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hex Word32
w1
    Word8 -> Builder ()
B.word8 Word8
HYPHEN
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hex Word16
w2
    Word8 -> Builder ()
B.word8 Word8
HYPHEN
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hex Word16
w3
    Word8 -> Builder ()
B.word8 Word8
HYPHEN
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hex Word16
w4
    Word8 -> Builder ()
B.word8 Word8
HYPHEN
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hex Word16
w5
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hex Word32
w6

-- | Write texutal UUID bytes in UPPERCASE, e.g. @550E8400-E29B-41D4-A716-446655440000@
uuidUpper :: UUID -> B.Builder ()
{-# INLINABLE uuidUpper #-}
uuidUpper :: UUID -> Builder ()
uuidUpper (UUID Word64
wh Word64
wl) =  do
    let !w1 :: Word32
w1 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word32 forall a b. (a -> b) -> a -> b
$ Word64
wh forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
32
        !w2 :: Word16
w2 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word16 forall a b. (a -> b) -> a -> b
$ Word64
wh forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
16 forall a. Bits a => a -> a -> a
.&. Word64
0xFFFF
        !w3 :: Word16
w3 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word16 forall a b. (a -> b) -> a -> b
$ Word64
wh forall a. Bits a => a -> a -> a
.&. Word64
0xFFFF
        !w4 :: Word16
w4 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word16 forall a b. (a -> b) -> a -> b
$ Word64
wl forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
48
        !w5 :: Word16
w5 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word16 forall a b. (a -> b) -> a -> b
$ Word64
wl forall a. Bits a => a -> Int -> a
`unsafeShiftR` Int
32 forall a. Bits a => a -> a -> a
.&. Word64
0xFFFF
        !w6 :: Word32
w6 = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Word64 @Word32 forall a b. (a -> b) -> a -> b
$ Word64
wl forall a. Bits a => a -> a -> a
.&. Word64
0xFFFFFFFF
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hexUpper Word32
w1
    Word8 -> Builder ()
B.word8 Word8
HYPHEN
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hexUpper Word16
w2
    Word8 -> Builder ()
B.word8 Word8
HYPHEN
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hexUpper Word16
w3
    Word8 -> Builder ()
B.word8 Word8
HYPHEN
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hexUpper Word16
w4
    Word8 -> Builder ()
B.word8 Word8
HYPHEN
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hexUpper Word16
w5
    forall a. (FiniteBits a, Integral a) => a -> Builder ()
B.hexUpper Word32
w6


-- | Encode binary UUID(two 64-bits word in big-endian), as described in <https://datatracker.ietf.org/doc/html/rfc4122 RFC 4122>. 
encodeUUID :: UUID -> B.Builder ()
{-# INLINABLE  encodeUUID #-}
encodeUUID :: UUID -> Builder ()
encodeUUID (UUID Word64
wh Word64
wl) = do 
    Word64 -> Builder ()
B.encodeWord64BE Word64
wh
    Word64 -> Builder ()
B.encodeWord64BE Word64
wl