{- | This is drop-in replacement for the read, write, and index functions
present in @Data.Primitive.ByteArray@ and @Data.Primitive.ByteArray.Unaligned@.
While the functions from those modules use native byte order, the functions
in this one use big-endian byte order (most significant byte first).
-}
module Data.Primitive.ByteArray.BigEndian
  ( -- * Aligned
    writeByteArray
  , readByteArray
  , indexByteArray

    -- * Unaligned
  , writeUnalignedByteArray
  , readUnalignedByteArray
  , indexUnalignedByteArray
  ) where

import Control.Monad.Primitive (PrimMonad, PrimState)
import Data.Primitive (ByteArray, MutableByteArray, Prim)
import qualified Data.Primitive as PM
import Data.Primitive.ByteArray.Unaligned (PrimUnaligned)
import qualified Data.Primitive.ByteArray.Unaligned as PMU
import System.ByteOrder (Bytes, fromBigEndian, toBigEndian)

{- | Write a primitive value to the byte array. The offset is given
in elements of type @a@ rather than in bytes. The most significant
byte in the value comes first.
-}
writeByteArray :: (PrimMonad m, Prim a, Bytes a) => MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray :: forall (m :: * -> *) a.
(PrimMonad m, Prim a, Bytes a) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeByteArray MutableByteArray (PrimState m)
arr Int
ix a
v = MutableByteArray (PrimState m) -> Int -> a -> m ()
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
PM.writeByteArray MutableByteArray (PrimState m)
arr Int
ix (a -> a
forall a. Bytes a => a -> a
toBigEndian a
v)

{- | Read a primitive value from the byte array, interpreting the first
byte as the most significant one. The offset is given in elements of
type @a@ rather than in bytes.
-}
readByteArray :: (PrimMonad m, Prim a, Bytes a) => MutableByteArray (PrimState m) -> Int -> m a
readByteArray :: forall (m :: * -> *) a.
(PrimMonad m, Prim a, Bytes a) =>
MutableByteArray (PrimState m) -> Int -> m a
readByteArray MutableByteArray (PrimState m)
arr Int
ix = a -> a
forall a. Bytes a => a -> a
fromBigEndian (a -> a) -> m a -> m a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MutableByteArray (PrimState m) -> Int -> m a
forall a (m :: * -> *).
(Prim a, PrimMonad m) =>
MutableByteArray (PrimState m) -> Int -> m a
PM.readByteArray MutableByteArray (PrimState m)
arr Int
ix

{- | Read a primitive value from the byte array, interpreting the first
byte as the most significant one. The offset is given in elements of
type @a@ rather than in bytes.
-}
indexByteArray :: (Prim a, Bytes a) => ByteArray -> Int -> a
indexByteArray :: forall a. (Prim a, Bytes a) => ByteArray -> Int -> a
indexByteArray ByteArray
arr Int
ix = a -> a
forall a. Bytes a => a -> a
fromBigEndian (ByteArray -> Int -> a
forall a. Prim a => ByteArray -> Int -> a
PM.indexByteArray ByteArray
arr Int
ix)

{- | Write a primitive value to the byte array. The offset is given
in bytes rather than in elements of type @a@. The most significant
byte in the value comes first.
-}
writeUnalignedByteArray ::
  (PrimMonad m, PrimUnaligned a, Bytes a) =>
  MutableByteArray (PrimState m) ->
  Int ->
  a ->
  m ()
writeUnalignedByteArray :: forall (m :: * -> *) a.
(PrimMonad m, PrimUnaligned a, Bytes a) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
writeUnalignedByteArray MutableByteArray (PrimState m)
arr Int
ix a
v = MutableByteArray (PrimState m) -> Int -> a -> m ()
forall (m :: * -> *) a.
(PrimMonad m, PrimUnaligned a) =>
MutableByteArray (PrimState m) -> Int -> a -> m ()
PMU.writeUnalignedByteArray MutableByteArray (PrimState m)
arr Int
ix (a -> a
forall a. Bytes a => a -> a
toBigEndian a
v)

{- | Read a primitive value from the byte array, interpreting the first
byte as the most significant one. The offset is given in bytes rather
than in elements of type @a@.
-}
readUnalignedByteArray ::
  (PrimMonad m, PrimUnaligned a, Bytes a) =>
  MutableByteArray (PrimState m) ->
  Int ->
  m a
readUnalignedByteArray :: forall (m :: * -> *) a.
(PrimMonad m, PrimUnaligned a, Bytes a) =>
MutableByteArray (PrimState m) -> Int -> m a
readUnalignedByteArray MutableByteArray (PrimState m)
arr Int
ix = a -> a
forall a. Bytes a => a -> a
fromBigEndian (a -> a) -> m a -> m a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> MutableByteArray (PrimState m) -> Int -> m a
forall (m :: * -> *) a.
(PrimMonad m, PrimUnaligned a) =>
MutableByteArray (PrimState m) -> Int -> m a
PMU.readUnalignedByteArray MutableByteArray (PrimState m)
arr Int
ix

{- | Read a primitive value from the byte array, interpreting the first
byte as the most significant one. The offset is given in bytes rather
than in elements of type @a@.
-}
indexUnalignedByteArray ::
  (PrimUnaligned a, Bytes a) =>
  ByteArray ->
  Int ->
  a
indexUnalignedByteArray :: forall a. (PrimUnaligned a, Bytes a) => ByteArray -> Int -> a
indexUnalignedByteArray ByteArray
arr Int
ix = a -> a
forall a. Bytes a => a -> a
fromBigEndian (ByteArray -> Int -> a
forall a. PrimUnaligned a => ByteArray -> Int -> a
PMU.indexUnalignedByteArray ByteArray
arr Int
ix)