{-# LANGUAGE AllowAmbiguousTypes #-}

module Telescope.Data.Binary
  ( BinaryValue (..)
  , ByteOrder (..)
  ) where

import Data.Binary.Get
import Data.Binary.Put
import GHC.Int
import System.ByteOrder (ByteOrder (..))


-- | Primitive types that can be serialized as Big or Little Endian
class BinaryValue a where
  byteSize :: Int
  put :: ByteOrder -> a -> Put
  get :: ByteOrder -> Get a


instance BinaryValue Int8 where
  byteSize :: Int
byteSize = Int
1
  put :: ByteOrder -> Int8 -> Put
put ByteOrder
_ = Int8 -> Put
putInt8
  get :: ByteOrder -> Get Int8
get ByteOrder
_ = Get Int8
getInt8


instance BinaryValue Int16 where
  byteSize :: Int
byteSize = Int
2
  put :: ByteOrder -> Int16 -> Put
put ByteOrder
BigEndian = Int16 -> Put
putInt16be
  put ByteOrder
LittleEndian = Int16 -> Put
putInt16le
  get :: ByteOrder -> Get Int16
get ByteOrder
BigEndian = Get Int16
getInt16be
  get ByteOrder
LittleEndian = Get Int16
getInt16le


instance BinaryValue Int32 where
  byteSize :: Int
byteSize = Int
4
  put :: ByteOrder -> Int32 -> Put
put ByteOrder
BigEndian = Int32 -> Put
putInt32be
  put ByteOrder
LittleEndian = Int32 -> Put
putInt32le
  get :: ByteOrder -> Get Int32
get ByteOrder
BigEndian = Get Int32
getInt32be
  get ByteOrder
LittleEndian = Get Int32
getInt32le


instance BinaryValue Int64 where
  byteSize :: Int
byteSize = Int
8
  put :: ByteOrder -> Int64 -> Put
put ByteOrder
BigEndian = Int64 -> Put
putInt64be
  put ByteOrder
LittleEndian = Int64 -> Put
putInt64le
  get :: ByteOrder -> Get Int64
get ByteOrder
BigEndian = Get Int64
getInt64be
  get ByteOrder
LittleEndian = Get Int64
getInt64le


instance BinaryValue Int where
  byteSize :: Int
byteSize = forall a. BinaryValue a => Int
byteSize @Int64
  put :: ByteOrder -> Int -> Put
put ByteOrder
bo Int
a = forall a. BinaryValue a => ByteOrder -> a -> Put
put @Int64 ByteOrder
bo (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
a)
  get :: ByteOrder -> Get Int
get ByteOrder
bo = Int64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int64 -> Int) -> Get Int64 -> Get Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. BinaryValue a => ByteOrder -> Get a
get @Int64 ByteOrder
bo


instance BinaryValue Float where
  byteSize :: Int
byteSize = Int
4
  put :: ByteOrder -> Float -> Put
put ByteOrder
BigEndian = Float -> Put
putFloatbe
  put ByteOrder
LittleEndian = Float -> Put
putFloatle
  get :: ByteOrder -> Get Float
get ByteOrder
BigEndian = Get Float
getFloatbe
  get ByteOrder
LittleEndian = Get Float
getFloatle


instance BinaryValue Double where
  byteSize :: Int
byteSize = Int
8
  put :: ByteOrder -> Double -> Put
put ByteOrder
BigEndian = Double -> Put
putDoublebe
  put ByteOrder
LittleEndian = Double -> Put
putDoublele
  get :: ByteOrder -> Get Double
get ByteOrder
BigEndian = Get Double
getDoublebe
  get ByteOrder
LittleEndian = Get Double
getDoublele