{-# 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 :: forall a. (FiniteBits a, Integral a) => a -> Builder
putNonNegative a
n = if a
n forall a. Bits a => a -> a -> a
.&. forall a. Bits a => a -> a
complement a
0x7F forall a. Eq a => a -> a -> Bool
== a
0
  then Word8 -> Builder
word8 forall a b. (a -> b) -> a -> b
$ forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
n forall a. Bits a => a -> a -> a
.&. a
0x7f)
  else Word8 -> Builder
word8 (Word8
0x80 forall a. Bits a => a -> a -> a
.|. (forall a b. (Integral a, Num b) => a -> b
fromIntegral a
n forall a. Bits a => a -> a -> a
.&. Word8
0x7F)) forall a. Semigroup a => a -> a -> a
<> forall a. (FiniteBits a, Integral a) => a -> Builder
putNonNegative (a
n 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 = forall a. (FiniteBits a, Integral a) => a -> Builder
putNonNegative
  {-# INLINE encodeRaw #-}

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

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

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

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

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

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

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

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

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

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

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