{-|
Module    : Z.Data.MessagePack.Builder
Description : MessagePack builders
Copyright : (c) Hideyuki Tanaka 2009-2015
          , (c) Dong Han 2020
License   : BSD3

'Builder's to encode Haskell data types in MessagePack format.

-}

module Z.Data.MessagePack.Builder where

import           Control.Monad
import           Data.Bits
import           GHC.Int
import           Data.Word
import           Data.Primitive.PrimArray
import           GHC.Exts
import           GHC.Integer.GMP.Internals
import           Prelude                    hiding (map)
import           Z.Data.Array.Unaligned
import qualified Z.Data.Text                as T
import qualified Z.Data.Builder             as B
import qualified Z.Data.Vector              as V
import           Z.Data.MessagePack.Value   hiding (value)

value :: Value -> B.Builder ()
{-# INLINABLE value #-}
value :: Value -> Builder ()
value Value
v = case Value
v of
    Value
Nil      -> Builder ()
nil
    Bool   Bool
b -> Bool -> Builder ()
bool Bool
b
    Int    Int64
n -> Int64 -> Builder ()
int Int64
n
    Float  Float
f -> Float -> Builder ()
float Float
f
    Double Double
d -> Double -> Builder ()
double Double
d
    Str    Text
t -> Text -> Builder ()
str Text
t
    Bin    Bytes
b -> Bytes -> Builder ()
bin Bytes
b
    Array  Vector Value
a -> (Value -> Builder ()) -> Vector Value -> Builder ()
forall (v :: * -> *) a.
Vec v a =>
(a -> Builder ()) -> v a -> Builder ()
array Value -> Builder ()
value Vector Value
a
    Map    Vector (Value, Value)
m -> (Value -> Builder ())
-> (Value -> Builder ()) -> Vector (Value, Value) -> Builder ()
forall a b.
(a -> Builder ())
-> (b -> Builder ()) -> Vector (a, b) -> Builder ()
map Value -> Builder ()
value Value -> Builder ()
value Vector (Value, Value)
m
    Ext  Word8
b Bytes
r -> Word8 -> Bytes -> Builder ()
ext Word8
b Bytes
r

nil :: B.Builder ()
{-# INLINE nil #-}
nil :: Builder ()
nil = Word8 -> Builder ()
B.word8 Word8
0xC0

bool :: Bool -> B.Builder ()
{-# INLINE bool #-}
bool :: Bool -> Builder ()
bool Bool
False = Word8 -> Builder ()
B.word8 Word8
0xC2
bool Bool
True  = Word8 -> Builder ()
B.word8 Word8
0xC3

int :: Int64 -> B.Builder ()
{-# INLINE int #-}
int :: Int64 -> Builder ()
int Int64
n
    | -Int64
0x20 Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n Bool -> Bool -> Bool
&& Int64
n Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
0x80         =  Word8 -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Int64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n :: Word8)
    | Int64
0     Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n Bool -> Bool -> Bool
&& Int64
n Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
0x100        =  (Word8, Word8) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xCC :: Word8, Int64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n :: Word8)
    | Int64
0     Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n Bool -> Bool -> Bool
&& Int64
n Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
0x10000      =  (Word8, BE Word16) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xCD :: Word8, Word16 -> BE Word16
forall a. a -> BE a
BE (Int64 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n :: Word16))
    | Int64
0     Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n Bool -> Bool -> Bool
&& Int64
n Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
0x100000000  =  (Word8, BE Word32) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xCE :: Word8, Word32 -> BE Word32
forall a. a -> BE a
BE (Int64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n :: Word32))
    | Int64
0     Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n                     =  (Word8, BE Word64) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xCF :: Word8, Word64 -> BE Word64
forall a. a -> BE a
BE (Int64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n :: Word64))
    | -Int64
0x80 Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n                     =  (Word8, Word8) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xD0 :: Word8, Int64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n :: Word8)
    | -Int64
0x8000 Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n                   =  (Word8, BE Word16) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xD1 :: Word8, Word16 -> BE Word16
forall a. a -> BE a
BE (Int64 -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n :: Word16))
    | -Int64
0x80000000 Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n               =  (Word8, BE Word32) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xD2 :: Word8, Word32 -> BE Word32
forall a. a -> BE a
BE (Int64 -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n :: Word32))
    | Bool
otherwise                      =  (Word8, BE Word64) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xD3 :: Word8, Word64 -> BE Word64
forall a. a -> BE a
BE (Int64 -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int64
n :: Word64))

float :: Float -> B.Builder ()
{-# INLINE float #-}
float :: Float -> Builder ()
float Float
f = (Word8, BE Float) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xCA :: Word8, Float -> BE Float
forall a. a -> BE a
BE Float
f)

double :: Double -> B.Builder ()
{-# INLINE double #-}
double :: Double -> Builder ()
double Double
d = (Word8, BE Double) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xCB :: Word8, Double -> BE Double
forall a. a -> BE a
BE Double
d)

-- | Construct a scientific value, see 'scientific'.
scientificValue :: Integer -> Int64 -> Value
{-# INLINE scientificValue #-}
scientificValue :: Integer -> Int64 -> Value
scientificValue Integer
0 Int64
_ = Word8 -> Bytes -> Value
Ext Word8
0x00 ([Word8] -> Bytes
forall (v :: * -> *) a. Vec v a => [a] -> v a
V.pack [Word8
0x00, Word8
0x00])
scientificValue Integer
c Int64
e = Word8 -> Bytes -> Value
Ext (if Integer
c Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
0 then Word8
0x00 else Word8
0x01) (Bytes -> Value) -> (Builder () -> Bytes) -> Builder () -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder () -> Bytes
forall a. Builder a -> Bytes
B.build (Builder () -> Value) -> Builder () -> Value
forall a b. (a -> b) -> a -> b
$ do
    Int64 -> Builder ()
int Int64
e
    Int
-> (MutablePrimArray RealWorld Word8 -> Int -> IO ()) -> Builder ()
B.writeN (Int# -> Int
I# (Word# -> Int#
word2Int# Word#
siz#)) ((MutablePrimArray RealWorld Word8 -> Int -> IO ()) -> Builder ())
-> (MutablePrimArray RealWorld Word8 -> Int -> IO ()) -> Builder ()
forall a b. (a -> b) -> a -> b
$ \ (MutablePrimArray MutableByteArray# RealWorld
mba#) (I# Int#
off#) ->
        IO Word -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Integer -> MutableByteArray# RealWorld -> Word# -> Int# -> IO Word
exportIntegerToMutableByteArray Integer
c MutableByteArray# RealWorld
mba# (Int# -> Word#
int2Word# Int#
off#) Int#
1#)
  where
    siz# :: Word#
siz# = Integer -> Int# -> Word#
sizeInBaseInteger Integer
c Int#
256#

-- | Write a scientific value in ext 0x00(positive) and 0x01(negative) format, e.g.
--
--  +--------+--------+--------+--------+
--  |  0xD5  |  0x00  |  0x00  |  0x00  |
--  +--------+--------+--------+--------+
--
--
--  +--------+--------+--------+-----------------------------------------+---------------------------------------+
--  |  0xC7  |XXXXXXXX|  0x00  | base10 exponent(MessagePack int format) | coefficient(big endian 256-base limbs |
--  +--------+--------+--------+-----------------------------------------+---------------------------------------+
--
scientific :: Integer -> Int64 -> B.Builder ()
{-# INLINABLE scientific #-}
scientific :: Integer -> Int64 -> Builder ()
scientific Integer
0 Int64
_ = (Word8, Word8, Word8, Word8) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim @(Word8, Word8, Word8, Word8) (Word8
0xD5, Word8
0x00, Word8
0x00, Word8
0x00)
scientific Integer
c Int64
e = do
    case (Int# -> Int
I# (Word# -> Int#
word2Int# Word#
siz#)) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int64 -> Int
intSiz Int64
e of
        Int
1 -> Word8 -> Builder ()
B.word8 Word8
0xD4
        Int
2 -> Word8 -> Builder ()
B.word8 Word8
0xD5
        Int
4 -> Word8 -> Builder ()
B.word8 Word8
0xD6
        Int
8 -> Word8 -> Builder ()
B.word8 Word8
0xD7
        Int
16 -> Word8 -> Builder ()
B.word8 Word8
0xD8
        Int
siz' | Int
siz' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x100   -> (Word8, Word8) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xC7 :: Word8, Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
siz' :: Word8)
             | Int
siz' Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x10000 -> (Word8, BE Word16) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xC8 :: Word8, Word16 -> BE Word16
forall a. a -> BE a
BE (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
siz' :: Word16))
             | Bool
otherwise      -> (Word8, BE Word32) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xC9 :: Word8, Word32 -> BE Word32
forall a. a -> BE a
BE (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
siz' :: Word32))
    Word8 -> Builder ()
B.word8 (if Integer
c Integer -> Integer -> Bool
forall a. Ord a => a -> a -> Bool
> Integer
0 then Word8
0x00 else Word8
0x01)
    Int64 -> Builder ()
int Int64
e
    Int
-> (MutablePrimArray RealWorld Word8 -> Int -> IO ()) -> Builder ()
B.writeN (Int# -> Int
I# (Word# -> Int#
word2Int# Word#
siz#)) ((MutablePrimArray RealWorld Word8 -> Int -> IO ()) -> Builder ())
-> (MutablePrimArray RealWorld Word8 -> Int -> IO ()) -> Builder ()
forall a b. (a -> b) -> a -> b
$ \ (MutablePrimArray MutableByteArray# RealWorld
mba#) (I# Int#
off#) ->
        IO Word -> IO ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (Integer -> MutableByteArray# RealWorld -> Word# -> Int# -> IO Word
exportIntegerToMutableByteArray Integer
c MutableByteArray# RealWorld
mba# (Int# -> Word#
int2Word# Int#
off#) Int#
1#)
  where
    siz# :: Word#
siz# = Integer -> Int# -> Word#
sizeInBaseInteger Integer
c Int#
256#
    intSiz :: Int64 -> Int
    intSiz :: Int64 -> Int
intSiz Int64
n
        | -Int64
0x20 Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n Bool -> Bool -> Bool
&& Int64
n Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
0x80         =  Int
1
        | Int64
0     Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n Bool -> Bool -> Bool
&& Int64
n Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
0x100        =  Int
2
        | Int64
0     Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n Bool -> Bool -> Bool
&& Int64
n Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
0x10000      =  Int
3
        | Int64
0     Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n Bool -> Bool -> Bool
&& Int64
n Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
< Int64
0x100000000  =  Int
5
        | Int64
0     Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n                     =  Int
9
        | -Int64
0x80 Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n                     =  Int
2
        | -Int64
0x8000 Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n                   =  Int
3
        | -Int64
0x80000000 Int64 -> Int64 -> Bool
forall a. Ord a => a -> a -> Bool
<= Int64
n               =  Int
5
        | Bool
otherwise                      =  Int
9

-- | Construct a timestamp(seconds, nanoseconds) value.
timestampValue :: Int64 -> Int32 -> Value
{-# INLINE timestampValue #-}
timestampValue :: Int64 -> Int32 -> Value
timestampValue Int64
s Int32
ns = Word8 -> Bytes -> Value
Ext Word8
0xFF (Builder () -> Bytes
forall a. Builder a -> Bytes
B.build (Builder () -> Bytes) -> Builder () -> Bytes
forall a b. (a -> b) -> a -> b
$ (BE Int32, BE Int64) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Int32 -> BE Int32
forall a. a -> BE a
BE Int32
ns, Int64 -> BE Int64
forall a. a -> BE a
BE Int64
s))

-- | Write a timestamp(seconds, nanoseconds) in ext 0xFF format, e.g.
timestamp :: Int64 -> Int32 -> B.Builder ()
{-# INLINE timestamp #-}
timestamp :: Int64 -> Int32 -> Builder ()
timestamp Int64
s Int32
ns = (Word8, Word8, Word8, BE Int32, BE Int64) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim
    (Word8
0xC7 :: Word8, Word8
0x0C :: Word8, Word8
0xFF :: Word8, (Int32 -> BE Int32
forall a. a -> BE a
BE Int32
ns :: BE Int32), (Int64 -> BE Int64
forall a. a -> BE a
BE Int64
s :: BE Int64))

str' :: String -> B.Builder ()
{-# INLINE str' #-}
str' :: String -> Builder ()
str' = Text -> Builder ()
str (Text -> Builder ()) -> (String -> Text) -> String -> Builder ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack

str :: T.Text -> B.Builder ()
{-# INLINE str #-}
str :: Text -> Builder ()
str Text
t = do
    let bs :: Bytes
bs = Text -> Bytes
T.getUTF8Bytes Text
t
    case Bytes -> Int
forall (v :: * -> *) a. Vec v a => v a -> Int
V.length Bytes
bs of
        Int
len | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
31      ->  Word8 -> Builder ()
B.word8 (Word8
0xA0 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)
            | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x100    ->  (Word8, Word8) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xD9 :: Word8, Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word8)
            | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x10000  ->  (Word8, BE Word16) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xDA :: Word8, Word16 -> BE Word16
forall a. a -> BE a
BE (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word16))
            | Bool
otherwise      ->  (Word8, BE Word32) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xDB :: Word8, Word32 -> BE Word32
forall a. a -> BE a
BE (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word32))
    Bytes -> Builder ()
B.bytes Bytes
bs

bin :: V.Bytes -> B.Builder ()
{-# INLINE bin #-}
bin :: Bytes -> Builder ()
bin Bytes
bs = do
    case Bytes -> Int
forall (v :: * -> *) a. Vec v a => v a -> Int
V.length Bytes
bs of
        Int
len | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x100    ->  (Word8, Word8) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xC4 :: Word8, Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word8)
            | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x10000  ->  (Word8, BE Word16) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xC5 :: Word8, Word16 -> BE Word16
forall a. a -> BE a
BE (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word16))
            | Bool
otherwise      ->  (Word8, BE Word32) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xC6 :: Word8, Word32 -> BE Word32
forall a. a -> BE a
BE (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word32))
    Bytes -> Builder ()
B.bytes Bytes
bs

array :: V.Vec v a => (a -> B.Builder ()) -> v a -> B.Builder ()
{-# INLINE array #-}
array :: (a -> Builder ()) -> v a -> Builder ()
array a -> Builder ()
p v a
xs = do
    Int -> Builder ()
arrayHeader (v a -> Int
forall (v :: * -> *) a. Vec v a => v a -> Int
V.length v a
xs)
    (a -> Builder ()) -> v a -> Builder ()
forall (v :: * -> *) a (f :: * -> *) b.
(Vec v a, Applicative f) =>
(a -> f b) -> v a -> f ()
V.traverseVec_ a -> Builder ()
p v a
xs

array' :: (a -> B.Builder ()) -> [a] -> B.Builder ()
{-# INLINE array' #-}
array' :: (a -> Builder ()) -> [a] -> Builder ()
array' a -> Builder ()
p [a]
xs = do
    Int -> Builder ()
arrayHeader ([a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a]
xs)
    (a -> Builder ()) -> [a] -> Builder ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ a -> Builder ()
p [a]
xs

arrayHeader :: Int -> B.Builder ()
{-# INLINE arrayHeader #-}
arrayHeader :: Int -> Builder ()
arrayHeader Int
len
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
15      =  Word8 -> Builder ()
B.word8 (Word8
0x90 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x10000  =  (Word8, BE Word16) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xDC :: Word8, Word16 -> BE Word16
forall a. a -> BE a
BE (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word16))
    | Bool
otherwise      =  (Word8, BE Word32) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xDD :: Word8, Word32 -> BE Word32
forall a. a -> BE a
BE (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word32))

map :: (a -> B.Builder ()) -> (b -> B.Builder ()) -> V.Vector (a, b) -> B.Builder ()
{-# INLINE map #-}
map :: (a -> Builder ())
-> (b -> Builder ()) -> Vector (a, b) -> Builder ()
map a -> Builder ()
p b -> Builder ()
q Vector (a, b)
xs = do
    Int -> Builder ()
mapHeader (Vector (a, b) -> Int
forall (v :: * -> *) a. Vec v a => v a -> Int
V.length Vector (a, b)
xs)
    ((a, b) -> Builder ()) -> Vector (a, b) -> Builder ()
forall (v :: * -> *) a (f :: * -> *) b.
(Vec v a, Applicative f) =>
(a -> f b) -> v a -> f ()
V.traverseVec_ (\(a
a, b
b) -> a -> Builder ()
p a
a Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> b -> Builder ()
q b
b) Vector (a, b)
xs

map' :: (a -> B.Builder ()) -> (b -> B.Builder ()) -> [(a, b)] -> B.Builder ()
{-# INLINE map' #-}
map' :: (a -> Builder ()) -> (b -> Builder ()) -> [(a, b)] -> Builder ()
map' a -> Builder ()
p b -> Builder ()
q [(a, b)]
xs = do
    Int -> Builder ()
mapHeader ([(a, b)] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(a, b)]
xs)
    ((a, b) -> Builder ()) -> [(a, b)] -> Builder ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ (\(a
a, b
b) -> a -> Builder ()
p a
a Builder () -> Builder () -> Builder ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> b -> Builder ()
q b
b) [(a, b)]
xs

mapHeader :: Int -> B.Builder ()
{-# INLINE mapHeader #-}
mapHeader :: Int -> Builder ()
mapHeader Int
len
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
15      =  Word8 -> Builder ()
B.word8 (Word8
0x80 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)
    | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x10000  =  (Word8, BE Word16) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xDE :: Word8, Word16 -> BE Word16
forall a. a -> BE a
BE (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word16))
    | Bool
otherwise      =  (Word8, BE Word32) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xDF :: Word8, Word32 -> BE Word32
forall a. a -> BE a
BE (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word32))

ext :: Word8 -> V.Bytes -> B.Builder ()
{-# INLINABLE ext #-}
ext :: Word8 -> Bytes -> Builder ()
ext Word8
typ Bytes
dat = do
    case Bytes -> Int
forall (v :: * -> *) a. Vec v a => v a -> Int
V.length Bytes
dat of
        Int
1  -> Word8 -> Builder ()
B.word8 Word8
0xD4
        Int
2  -> Word8 -> Builder ()
B.word8 Word8
0xD5
        Int
4  -> Word8 -> Builder ()
B.word8 Word8
0xD6
        Int
8  -> Word8 -> Builder ()
B.word8 Word8
0xD7
        Int
16 -> Word8 -> Builder ()
B.word8 Word8
0xD8
        Int
len | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x100   -> (Word8, Word8) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xC7 :: Word8, Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word8)
            | Int
len Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
0x10000 -> (Word8, BE Word16) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xC8 :: Word8, Word16 -> BE Word16
forall a. a -> BE a
BE (Int -> Word16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word16))
            | Bool
otherwise     -> (Word8, BE Word32) -> Builder ()
forall a. Unaligned a => a -> Builder ()
B.encodePrim (Word8
0xC9 :: Word8, Word32 -> BE Word32
forall a. a -> BE a
BE (Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len :: Word32))
    Word8 -> Builder ()
B.word8 Word8
typ
    Bytes -> Builder ()
B.bytes Bytes
dat