{-# LANGUAGE ScopedTypeVariables #-}

module Data.Avro.Internal.EncodeRaw
  ( EncodeRaw(..)
  , putI
  , long0
  ) where

import Data.Avro.Internal.Zig
import Data.Bits
import Data.ByteString.Builder
import Data.Int
import Data.Word

putNonNegative :: forall a. (FiniteBits a, Integral a) => a -> Builder
putNonNegative :: a -> Builder
putNonNegative a
n = if a
n a -> a -> a
forall a. Bits a => a -> a -> a
.&. a -> a
forall a. Bits a => a -> a
complement a
0x7F a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
0
  then Word8 -> Builder
word8 (Word8 -> Builder) -> Word8 -> Builder
forall a b. (a -> b) -> a -> b
$ a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
n a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x7f)
  else Word8 -> Builder
word8 (Word8
0x80 Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.&. Word8
0x7F)) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> a -> Builder
forall a. (FiniteBits a, Integral a) => a -> Builder
putNonNegative (a
n a -> Int -> a
forall a. Bits a => a -> Int -> a
`shiftR` Int
7)

class EncodeRaw a where
  encodeRaw :: a -> Builder

instance EncodeRaw Word where
  encodeRaw :: Word -> Builder
encodeRaw = Word -> Builder
forall a. (FiniteBits a, Integral a) => a -> Builder
putNonNegative
  {-# INLINE encodeRaw #-}

instance EncodeRaw Word8 where
  encodeRaw :: Word8 -> Builder
encodeRaw = Word8 -> Builder
forall a. (FiniteBits a, Integral a) => a -> Builder
putNonNegative
  {-# INLINE encodeRaw #-}

instance EncodeRaw Word16 where
  encodeRaw :: Word16 -> Builder
encodeRaw = Word16 -> Builder
forall a. (FiniteBits a, Integral a) => a -> Builder
putNonNegative
  {-# INLINE encodeRaw #-}

instance EncodeRaw Word32 where
  encodeRaw :: Word32 -> Builder
encodeRaw = Word32 -> Builder
forall a. (FiniteBits a, Integral a) => a -> Builder
putNonNegative
  {-# INLINE encodeRaw #-}

instance EncodeRaw Word64 where
  encodeRaw :: Word64 -> Builder
encodeRaw = Word64 -> Builder
forall a. (FiniteBits a, Integral a) => a -> Builder
putNonNegative
  {-# INLINE encodeRaw #-}

instance EncodeRaw Int where
  encodeRaw :: Int -> Builder
encodeRaw = Word -> Builder
forall a. EncodeRaw a => a -> Builder
encodeRaw (Word -> Builder) -> (Int -> Word) -> Int -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Word
forall a. Zig a => a -> Zigged a
zig
  {-# INLINE encodeRaw #-}

instance EncodeRaw Int8 where
  encodeRaw :: Int8 -> Builder
encodeRaw = Word8 -> Builder
forall a. EncodeRaw a => a -> Builder
encodeRaw (Word8 -> Builder) -> (Int8 -> Word8) -> Int8 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int8 -> Word8
forall a. Zig a => a -> Zigged a
zig
  {-# INLINE encodeRaw #-}

instance EncodeRaw Int16 where
  encodeRaw :: Int16 -> Builder
encodeRaw = Word16 -> Builder
forall a. EncodeRaw a => a -> Builder
encodeRaw (Word16 -> Builder) -> (Int16 -> Word16) -> Int16 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int16 -> Word16
forall a. Zig a => a -> Zigged a
zig
  {-# INLINE encodeRaw #-}

instance EncodeRaw Int32 where
  encodeRaw :: Int32 -> Builder
encodeRaw = Word32 -> Builder
forall a. EncodeRaw a => a -> Builder
encodeRaw (Word32 -> Builder) -> (Int32 -> Word32) -> Int32 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int32 -> Word32
forall a. Zig a => a -> Zigged a
zig
  {-# INLINE encodeRaw #-}

instance EncodeRaw Int64 where
  encodeRaw :: Int64 -> Builder
encodeRaw = Word64 -> Builder
forall a. EncodeRaw a => a -> Builder
encodeRaw (Word64 -> Builder) -> (Int64 -> Word64) -> Int64 -> Builder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int64 -> Word64
forall a. Zig a => a -> Zigged a
zig
  {-# INLINE encodeRaw #-}

-- Put a Haskell Int.
putI :: Int -> Builder
putI :: Int -> Builder
putI = Int -> Builder
forall a. EncodeRaw a => a -> Builder
encodeRaw
{-# INLINE putI #-}

-- Terminating word for array and map types.
long0 :: Builder
long0 :: Builder
long0 = Word64 -> Builder
forall a. EncodeRaw a => a -> Builder
encodeRaw (Word64
0 :: Word64)
{-# INLINE long0 #-}