{-# language AllowAmbiguousTypes #-}
{-# language DataKinds #-}
{-# language GADTSyntax #-}
{-# language KindSignatures #-}
{-# language MagicHash #-}
{-# language RoleAnnotations #-}
{-# language ScopedTypeVariables #-}
{-# language UnboxedTuples #-}
{-# language TypeApplications #-}
module System.ByteOrder.Unsafe
  ( Fixed(..)
  , FixedOrdering(..)
  ) where
import Data.Kind (Type)
import Data.Primitive.Types (Prim)
import GHC.ByteOrder (ByteOrder(BigEndian,LittleEndian))
import System.ByteOrder.Class (Bytes(toLittleEndian,toBigEndian))
import qualified Data.Primitive.Types as PM
newtype Fixed :: ByteOrder -> Type -> Type where
  Fixed :: { getFixed :: a } -> Fixed b a
type role Fixed phantom representational
class FixedOrdering (b :: ByteOrder) where
  toFixedEndian :: Bytes a => a -> a
instance FixedOrdering 'LittleEndian where
  toFixedEndian = toLittleEndian
instance FixedOrdering 'BigEndian where
  toFixedEndian = toBigEndian
instance (FixedOrdering b, Prim a, Bytes a) => Prim (Fixed b a) where
  sizeOf# _ = PM.sizeOf# (undefined :: a)
  alignment# _ = PM.alignment# (undefined :: a)
  indexByteArray# a i = Fixed (toFixedEndian @b (PM.indexByteArray# a i))
  readByteArray# a i s0 = case PM.readByteArray# a i s0 of
    (# s1, x #) -> (# s1, Fixed (toFixedEndian @b x) #)
  writeByteArray# a i (Fixed x) = PM.writeByteArray# a i (toFixedEndian @b x)
  setByteArray# a i n (Fixed x) = PM.setByteArray# a i n (toFixedEndian @b x)
  indexOffAddr# a i = Fixed (toFixedEndian @b (PM.indexOffAddr# a i))
  readOffAddr# a i s0 = case PM.readOffAddr# a i s0 of
    (# s1, x #) -> (# s1, Fixed (toFixedEndian @b x) #)
  writeOffAddr# a i (Fixed x) = PM.writeOffAddr# a i (toFixedEndian @b x)
  setOffAddr# a i n (Fixed x) = PM.setOffAddr# a i n (toFixedEndian @b x)