-- |
-- Module      : Data.ByteArray.Sized
-- License     : BSD-style
-- Maintainer  : Nicolas Di Prima <nicolas@primetype.co.uk>
-- Stability   : stable
-- Portability : Good
--

{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
#if __GLASGOW_HASKELL__ >= 806
{-# LANGUAGE NoStarIsType #-}
#endif

module Data.ByteArray.Sized
    ( ByteArrayN(..)
    , SizedByteArray
    , unSizedByteArray
    , sizedByteArray
    , unsafeSizedByteArray

    , -- * ByteArrayN operators
      alloc
    , create
    , allocAndFreeze
    , unsafeCreate
    , inlineUnsafeCreate
    , empty
    , pack
    , unpack
    , cons
    , snoc
    , xor
    , index
    , splitAt
    , take
    , drop
    , append
    , copy
    , copyRet
    , copyAndFreeze
    , replicate
    , zero
    , convert
    , fromByteArrayAccess
    , unsafeFromByteArrayAccess
    ) where

import Basement.Imports
import Basement.NormalForm
import Basement.Nat
import Basement.Numerical.Additive ((+))
import Basement.Numerical.Subtractive ((-))

import Basement.Sized.List (ListN, unListN, toListN)

import           Foreign.Storable
import           Foreign.Ptr
import           Data.Maybe (fromMaybe)

import           Data.Memory.Internal.Compat
import           Data.Memory.PtrMethods

import Data.Proxy (Proxy(..))

import Data.ByteArray.Types (ByteArrayAccess(..), ByteArray)
import qualified Data.ByteArray.Types as ByteArray (allocRet)

#if MIN_VERSION_basement(0,0,7)
import           Basement.BlockN (BlockN)
import qualified Basement.BlockN as BlockN
import qualified Basement.PrimType as Base
import           Basement.Types.OffsetSize (Countable)
#endif

-- | Type class to emulate exactly the behaviour of 'ByteArray' but with
-- a known length at compile time
--
class (ByteArrayAccess c, KnownNat n) => ByteArrayN (n :: Nat) c | c -> n where
    -- | just like 'allocRet' but with the size at the type level
    allocRet :: forall p a
              . Proxy n
             -> (Ptr p -> IO a)
             -> IO (a, c)

-- | Wrapper around any collection type with the size as type parameter
--
newtype SizedByteArray (n :: Nat) ba = SizedByteArray { forall (n :: Nat) ba. SizedByteArray n ba -> ba
unSizedByteArray :: ba }
  deriving (SizedByteArray n ba -> SizedByteArray n ba -> Bool
forall (n :: Nat) ba.
Eq ba =>
SizedByteArray n ba -> SizedByteArray n ba -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: SizedByteArray n ba -> SizedByteArray n ba -> Bool
$c/= :: forall (n :: Nat) ba.
Eq ba =>
SizedByteArray n ba -> SizedByteArray n ba -> Bool
== :: SizedByteArray n ba -> SizedByteArray n ba -> Bool
$c== :: forall (n :: Nat) ba.
Eq ba =>
SizedByteArray n ba -> SizedByteArray n ba -> Bool
Eq, Int -> SizedByteArray n ba -> ShowS
forall (n :: Nat) ba.
Show ba =>
Int -> SizedByteArray n ba -> ShowS
forall (n :: Nat) ba. Show ba => [SizedByteArray n ba] -> ShowS
forall (n :: Nat) ba. Show ba => SizedByteArray n ba -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [SizedByteArray n ba] -> ShowS
$cshowList :: forall (n :: Nat) ba. Show ba => [SizedByteArray n ba] -> ShowS
show :: SizedByteArray n ba -> String
$cshow :: forall (n :: Nat) ba. Show ba => SizedByteArray n ba -> String
showsPrec :: Int -> SizedByteArray n ba -> ShowS
$cshowsPrec :: forall (n :: Nat) ba.
Show ba =>
Int -> SizedByteArray n ba -> ShowS
Show, Typeable, SizedByteArray n ba -> SizedByteArray n ba -> Bool
SizedByteArray n ba -> SizedByteArray n ba -> Ordering
SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
forall {n :: Nat} {ba}. Ord ba => Eq (SizedByteArray n ba)
forall (n :: Nat) ba.
Ord ba =>
SizedByteArray n ba -> SizedByteArray n ba -> Bool
forall (n :: Nat) ba.
Ord ba =>
SizedByteArray n ba -> SizedByteArray n ba -> Ordering
forall (n :: Nat) ba.
Ord ba =>
SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
$cmin :: forall (n :: Nat) ba.
Ord ba =>
SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
max :: SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
$cmax :: forall (n :: Nat) ba.
Ord ba =>
SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
>= :: SizedByteArray n ba -> SizedByteArray n ba -> Bool
$c>= :: forall (n :: Nat) ba.
Ord ba =>
SizedByteArray n ba -> SizedByteArray n ba -> Bool
> :: SizedByteArray n ba -> SizedByteArray n ba -> Bool
$c> :: forall (n :: Nat) ba.
Ord ba =>
SizedByteArray n ba -> SizedByteArray n ba -> Bool
<= :: SizedByteArray n ba -> SizedByteArray n ba -> Bool
$c<= :: forall (n :: Nat) ba.
Ord ba =>
SizedByteArray n ba -> SizedByteArray n ba -> Bool
< :: SizedByteArray n ba -> SizedByteArray n ba -> Bool
$c< :: forall (n :: Nat) ba.
Ord ba =>
SizedByteArray n ba -> SizedByteArray n ba -> Bool
compare :: SizedByteArray n ba -> SizedByteArray n ba -> Ordering
$ccompare :: forall (n :: Nat) ba.
Ord ba =>
SizedByteArray n ba -> SizedByteArray n ba -> Ordering
Ord, SizedByteArray n ba -> ()
forall (n :: Nat) ba. NormalForm ba => SizedByteArray n ba -> ()
forall a. (a -> ()) -> NormalForm a
toNormalForm :: SizedByteArray n ba -> ()
$ctoNormalForm :: forall (n :: Nat) ba. NormalForm ba => SizedByteArray n ba -> ()
NormalForm)

-- | create a 'SizedByteArray' from the given 'ByteArrayAccess' if the
-- size is the same as the target size.
--
sizedByteArray :: forall n ba . (KnownNat n, ByteArrayAccess ba)
               => ba
               -> Maybe (SizedByteArray n ba)
sizedByteArray :: forall (n :: Nat) ba.
(KnownNat n, ByteArrayAccess ba) =>
ba -> Maybe (SizedByteArray n ba)
sizedByteArray ba
ba
    | forall ba. ByteArrayAccess ba => ba -> Int
length ba
ba forall a. Eq a => a -> a -> Bool
== Int
n = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) ba. ba -> SizedByteArray n ba
SizedByteArray ba
ba
    | Bool
otherwise      = forall a. Maybe a
Nothing
  where
    n :: Int
n = forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @n)

-- | just like the 'sizedByteArray' function but throw an exception if
-- the size is invalid.
unsafeSizedByteArray :: forall n ba . (ByteArrayAccess ba, KnownNat n) => ba -> SizedByteArray n ba
unsafeSizedByteArray :: forall (n :: Nat) ba.
(ByteArrayAccess ba, KnownNat n) =>
ba -> SizedByteArray n ba
unsafeSizedByteArray = forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => String -> a
error String
"The size is invalid") forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall (n :: Nat) ba.
(KnownNat n, ByteArrayAccess ba) =>
ba -> Maybe (SizedByteArray n ba)
sizedByteArray

instance (ByteArrayAccess ba, KnownNat n) => ByteArrayAccess (SizedByteArray n ba) where
    length :: SizedByteArray n ba -> Int
length SizedByteArray n ba
_ = forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @n)
    withByteArray :: forall p a. SizedByteArray n ba -> (Ptr p -> IO a) -> IO a
withByteArray (SizedByteArray ba
ba) = forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
ba

instance (KnownNat n, ByteArray ba) => ByteArrayN n (SizedByteArray n ba) where
    allocRet :: forall p a.
Proxy n -> (Ptr p -> IO a) -> IO (a, SizedByteArray n ba)
allocRet Proxy n
p Ptr p -> IO a
f = do
        (a
a, ba
ba) <- forall ba p a. ByteArray ba => Int -> (Ptr p -> IO a) -> IO (a, ba)
ByteArray.allocRet Int
n Ptr p -> IO a
f
        forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (a
a, forall (n :: Nat) ba. ba -> SizedByteArray n ba
SizedByteArray ba
ba)
      where
        n :: Int
n = forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal Proxy n
p

#if MIN_VERSION_basement(0,0,7)
instance ( ByteArrayAccess (BlockN n ty)
         , PrimType ty
         , KnownNat n
         , Countable ty n
         , KnownNat nbytes
         , nbytes ~ (Base.PrimSize ty * n)
         ) => ByteArrayN nbytes (BlockN n ty) where
    allocRet :: forall p a. Proxy nbytes -> (Ptr p -> IO a) -> IO (a, BlockN n ty)
allocRet Proxy nbytes
_ Ptr p -> IO a
f = do
        MutableBlockN n ty RealWorld
mba <- forall (n :: Nat) ty (prim :: Type -> Type).
(PrimType ty, KnownNat n, Countable ty n, PrimMonad prim) =>
prim (MutableBlockN n ty (PrimState prim))
BlockN.new @n
        a
a   <- forall (n :: Nat) ty (prim :: Type -> Type) a.
(PrimMonad prim, KnownNat n) =>
Bool
-> Bool
-> MutableBlockN n ty (PrimState prim)
-> (Ptr ty -> prim a)
-> prim a
BlockN.withMutablePtrHint Bool
True Bool
False MutableBlockN n ty RealWorld
mba (Ptr p -> IO a
f forall {k} (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a b. Ptr a -> Ptr b
castPtr)
        BlockN n ty
ba  <- forall (prim :: Type -> Type) ty (n :: Nat).
(PrimMonad prim, PrimType ty, Countable ty n) =>
MutableBlockN n ty (PrimState prim) -> prim (BlockN n ty)
BlockN.freeze MutableBlockN n ty RealWorld
mba
        forall (m :: Type -> Type) a. Monad m => a -> m a
return (a
a, BlockN n ty
ba)
#endif


-- | Allocate a new bytearray of specific size, and run the initializer on this memory
alloc :: forall n ba p . (ByteArrayN n ba, KnownNat n)
      => (Ptr p -> IO ())
      -> IO ba
alloc :: forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc Ptr p -> IO ()
f = forall a b. (a, b) -> b
snd forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (n :: Nat) c p a.
ByteArrayN n c =>
Proxy n -> (Ptr p -> IO a) -> IO (a, c)
allocRet (forall {k} (t :: k). Proxy t
Proxy @n) Ptr p -> IO ()
f

-- | Allocate a new bytearray of specific size, and run the initializer on this memory
create :: forall n ba p . (ByteArrayN n ba, KnownNat n)
       => (Ptr p -> IO ())
       -> IO ba
create :: forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
create = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @n
{-# NOINLINE create #-}

-- | similar to 'allocN' but hide the allocation and initializer in a pure context
allocAndFreeze :: forall n ba p . (ByteArrayN n ba, KnownNat n)
               => (Ptr p -> IO ()) -> ba
allocAndFreeze :: forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
allocAndFreeze Ptr p -> IO ()
f = forall a. IO a -> a
unsafeDoIO (forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @n Ptr p -> IO ()
f)
{-# NOINLINE allocAndFreeze #-}

-- | similar to 'createN' but hide the allocation and initializer in a pure context
unsafeCreate :: forall n ba p . (ByteArrayN n ba, KnownNat n)
             => (Ptr p -> IO ()) -> ba
unsafeCreate :: forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate Ptr p -> IO ()
f = forall a. IO a -> a
unsafeDoIO (forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @n Ptr p -> IO ()
f)
{-# NOINLINE unsafeCreate #-}

inlineUnsafeCreate :: forall n ba p . (ByteArrayN n ba, KnownNat n)
                   => (Ptr p -> IO ()) -> ba
inlineUnsafeCreate :: forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate Ptr p -> IO ()
f = forall a. IO a -> a
unsafeDoIO (forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @n Ptr p -> IO ()
f)
{-# INLINE inlineUnsafeCreate #-}

-- | Create an empty byte array
empty :: forall ba . ByteArrayN 0 ba => ba
empty :: forall ba. ByteArrayN 0 ba => ba
empty = forall a. IO a -> a
unsafeDoIO (forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @0 forall a b. (a -> b) -> a -> b
$ \Ptr Any
_ -> forall (m :: Type -> Type) a. Monad m => a -> m a
return ())

-- | Pack a list of bytes into a bytearray
pack :: forall n ba . (ByteArrayN n ba, KnownNat n) => ListN n Word8 -> ba
pack :: forall (n :: Nat) ba.
(ByteArrayN n ba, KnownNat n) =>
ListN n Word8 -> ba
pack ListN n Word8
l = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate @n (forall {b}. Storable b => [b] -> Ptr b -> IO ()
fill forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) a. ListN n a -> [a]
unListN ListN n Word8
l)
  where fill :: [b] -> Ptr b -> IO ()
fill []     Ptr b
_  = forall (m :: Type -> Type) a. Monad m => a -> m a
return ()
        fill (b
x:[b]
xs) !Ptr b
p = forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr b
p b
x forall (m :: Type -> Type) a b. Monad m => m a -> m b -> m b
>> [b] -> Ptr b -> IO ()
fill [b]
xs (Ptr b
p forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1)
        {-# INLINE fill #-}
{-# NOINLINE pack #-}

-- | Un-pack a bytearray into a list of bytes
unpack :: forall n ba
        . (ByteArrayN n ba, KnownNat n, NatWithinBound Int n, ByteArrayAccess ba)
       => ba -> ListN n Word8
unpack :: forall (n :: Nat) ba.
(ByteArrayN n ba, KnownNat n, NatWithinBound Int n,
 ByteArrayAccess ba) =>
ba -> ListN n Word8
unpack ba
bs =  forall a. a -> Maybe a -> a
fromMaybe (forall a. HasCallStack => String -> a
error String
"the impossible appened") forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) a.
(KnownNat n, NatWithinBound Int n) =>
[a] -> Maybe (ListN n a)
toListN @n forall a b. (a -> b) -> a -> b
$ Int -> [Word8]
loop Int
0
  where !len :: Int
len = forall ba. ByteArrayAccess ba => ba -> Int
length ba
bs
        loop :: Int -> [Word8]
loop Int
i
            | Int
i forall a. Eq a => a -> a -> Bool
== Int
len  = []
            | Bool
otherwise =
                let !v :: Word8
v = forall a. IO a -> a
unsafeDoIO forall a b. (a -> b) -> a -> b
$ forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
bs (forall a b. Storable a => Ptr b -> Int -> IO a
`peekByteOff` Int
i)
                 in Word8
v forall a. a -> [a] -> [a]
: Int -> [Word8]
loop (Int
iforall a. Additive a => a -> a -> a
+Int
1)

-- | prepend a single byte to a byte array
cons :: forall ni no bi bo
      . ( ByteArrayN ni bi, ByteArrayN no bo, ByteArrayAccess bi
        , KnownNat ni, KnownNat no
        , (ni + 1) ~ no
        )
     => Word8 -> bi -> bo
cons :: forall (ni :: Nat) (no :: Nat) bi bo.
(ByteArrayN ni bi, ByteArrayN no bo, ByteArrayAccess bi,
 KnownNat ni, KnownNat no, (ni + 1) ~ no) =>
Word8 -> bi -> bo
cons Word8
b bi
ba = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @no forall a b. (a -> b) -> a -> b
$ \Ptr Any
d -> forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bi
ba forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> do
    forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Any
d Int
0 Word8
b
    Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy (Ptr Any
d forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1) Ptr Word8
s Int
len
  where
    !len :: Int
len = forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @ni)

-- | append a single byte to a byte array
snoc :: forall bi bo ni no
      . ( ByteArrayN ni bi, ByteArrayN no bo, ByteArrayAccess bi
        , KnownNat ni, KnownNat no
        , (ni + 1) ~ no
        )
     => bi -> Word8 -> bo
snoc :: forall bi bo (ni :: Nat) (no :: Nat).
(ByteArrayN ni bi, ByteArrayN no bo, ByteArrayAccess bi,
 KnownNat ni, KnownNat no, (ni + 1) ~ no) =>
bi -> Word8 -> bo
snoc bi
ba Word8
b = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @no forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bi
ba forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> do
    Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d Ptr Word8
s Int
len
    forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
d Int
len Word8
b
  where
    !len :: Int
len = forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @ni)

-- | Create a xor of bytes between a and b.
--
-- the returns byte array is the size of the smallest input.
xor :: forall n a b c
     . ( ByteArrayN n a, ByteArrayN n b, ByteArrayN n c
       , ByteArrayAccess a, ByteArrayAccess b
       , KnownNat n
       )
    => a -> b -> c
xor :: forall (n :: Nat) a b c.
(ByteArrayN n a, ByteArrayN n b, ByteArrayN n c, ByteArrayAccess a,
 ByteArrayAccess b, KnownNat n) =>
a -> b -> c
xor a
a b
b =
    forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @n forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pc ->
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray a
a  forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pa ->
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray b
b  forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pb ->
        Ptr Word8 -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memXor Ptr Word8
pc Ptr Word8
pa Ptr Word8
pb Int
n
  where
    n :: Int
n  = forall a. Integral a => Integer -> a
fromInteger (forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @n))

-- | return a specific byte indexed by a number from 0 in a bytearray
--
-- unsafe, no bound checking are done
index :: forall n na ba
       . ( ByteArrayN na ba, ByteArrayAccess ba
         , KnownNat na, KnownNat n
         , n <= na
         )
      => ba -> Proxy n -> Word8
index :: forall (n :: Nat) (na :: Nat) ba.
(ByteArrayN na ba, ByteArrayAccess ba, KnownNat na, KnownNat n,
 n <= na) =>
ba -> Proxy n -> Word8
index ba
b Proxy n
pi = forall a. IO a -> a
unsafeDoIO forall a b. (a -> b) -> a -> b
$ forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
b forall a b. (a -> b) -> a -> b
$ \Ptr Any
p -> forall a. Storable a => Ptr a -> IO a
peek (Ptr Any
p forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
i)
  where
    i :: Int
i = forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal Proxy n
pi

-- | Split a bytearray at a specific length in two bytearray
splitAt :: forall nblhs nbi nbrhs bi blhs brhs
         . ( ByteArrayN nbi bi, ByteArrayN nblhs blhs, ByteArrayN nbrhs brhs
           , ByteArrayAccess bi
           , KnownNat nbi, KnownNat nblhs, KnownNat nbrhs
           , nblhs <= nbi, (nbrhs + nblhs) ~ nbi
           )
        => bi -> (blhs, brhs)
splitAt :: forall (nblhs :: Nat) (nbi :: Nat) (nbrhs :: Nat) bi blhs brhs.
(ByteArrayN nbi bi, ByteArrayN nblhs blhs, ByteArrayN nbrhs brhs,
 ByteArrayAccess bi, KnownNat nbi, KnownNat nblhs, KnownNat nbrhs,
 nblhs <= nbi, (nbrhs + nblhs) ~ nbi) =>
bi -> (blhs, brhs)
splitAt bi
bs = forall a. IO a -> a
unsafeDoIO forall a b. (a -> b) -> a -> b
$
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bi
bs forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> do
        blhs
b1 <- forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @nblhs forall a b. (a -> b) -> a -> b
$ \Ptr Word8
r -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
r Ptr Word8
p Int
n
        brhs
b2 <- forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @nbrhs forall a b. (a -> b) -> a -> b
$ \Ptr Word8
r -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
r (Ptr Word8
p forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
n) (Int
len forall a. Subtractive a => a -> a -> Difference a
- Int
n)
        forall (m :: Type -> Type) a. Monad m => a -> m a
return (blhs
b1, brhs
b2)
  where
    n :: Int
n = forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @nblhs)
    len :: Int
len = forall ba. ByteArrayAccess ba => ba -> Int
length bi
bs

-- | Take the first @n@ byte of a bytearray
take :: forall nbo nbi bi bo
      . ( ByteArrayN nbi bi, ByteArrayN nbo bo
        , ByteArrayAccess bi
        , KnownNat nbi, KnownNat nbo
        , nbo <= nbi
        )
     => bi -> bo
take :: forall (nbo :: Nat) (nbi :: Nat) bi bo.
(ByteArrayN nbi bi, ByteArrayN nbo bo, ByteArrayAccess bi,
 KnownNat nbi, KnownNat nbo, nbo <= nbi) =>
bi -> bo
take bi
bs = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @nbo forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bi
bs forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d Ptr Word8
s Int
m
  where
    !m :: Int
m   = forall a. Ord a => a -> a -> a
min Int
len Int
n
    !len :: Int
len = forall ba. ByteArrayAccess ba => ba -> Int
length bi
bs
    !n :: Int
n   = forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @nbo)

-- | drop the first @n@ byte of a bytearray
drop :: forall n nbi nbo bi bo
      . ( ByteArrayN nbi bi, ByteArrayN nbo bo
        , ByteArrayAccess bi
        , KnownNat n, KnownNat nbi, KnownNat nbo
        , (nbo + n) ~ nbi
        )
     => Proxy n -> bi -> bo
drop :: forall (n :: Nat) (nbi :: Nat) (nbo :: Nat) bi bo.
(ByteArrayN nbi bi, ByteArrayN nbo bo, ByteArrayAccess bi,
 KnownNat n, KnownNat nbi, KnownNat nbo, (nbo + n) ~ nbi) =>
Proxy n -> bi -> bo
drop Proxy n
pn bi
bs = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @nbo forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d ->
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bi
bs forall a b. (a -> b) -> a -> b
$ \Ptr Any
s ->
    Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d (Ptr Any
s forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
ofs) Difference Int
nb
  where
    ofs :: Int
ofs = forall a. Ord a => a -> a -> a
min Int
len Int
n
    nb :: Difference Int
nb  = Int
len forall a. Subtractive a => a -> a -> Difference a
- Int
ofs
    len :: Int
len = forall ba. ByteArrayAccess ba => ba -> Int
length bi
bs
    n :: Int
n   = forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal Proxy n
pn

-- | append one bytearray to the other
append :: forall nblhs nbrhs nbout blhs brhs bout
        . ( ByteArrayN nblhs blhs, ByteArrayN nbrhs brhs, ByteArrayN nbout bout
          , ByteArrayAccess blhs, ByteArrayAccess brhs
          , KnownNat nblhs, KnownNat nbrhs, KnownNat nbout
          , (nbrhs + nblhs) ~ nbout
          )
       => blhs -> brhs -> bout
append :: forall (nblhs :: Nat) (nbrhs :: Nat) (nbout :: Nat) blhs brhs bout.
(ByteArrayN nblhs blhs, ByteArrayN nbrhs brhs,
 ByteArrayN nbout bout, ByteArrayAccess blhs, ByteArrayAccess brhs,
 KnownNat nblhs, KnownNat nbrhs, KnownNat nbout,
 (nbrhs + nblhs) ~ nbout) =>
blhs -> brhs -> bout
append blhs
blhs brhs
brhs = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @nbout forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p ->
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray blhs
blhs forall a b. (a -> b) -> a -> b
$ \Ptr Word8
plhs ->
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray brhs
brhs forall a b. (a -> b) -> a -> b
$ \Ptr Word8
prhs -> do
        Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
p Ptr Word8
plhs (forall ba. ByteArrayAccess ba => ba -> Int
length blhs
blhs)
        Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy (Ptr Word8
p forall a b. Ptr a -> Int -> Ptr b
`plusPtr` forall ba. ByteArrayAccess ba => ba -> Int
length blhs
blhs) Ptr Word8
prhs (forall ba. ByteArrayAccess ba => ba -> Int
length brhs
brhs)

-- | Duplicate a bytearray into another bytearray, and run an initializer on it
copy :: forall n bs1 bs2 p
      . ( ByteArrayN n bs1, ByteArrayN n bs2
        , ByteArrayAccess bs1
        , KnownNat n
        )
     => bs1 -> (Ptr p -> IO ()) -> IO bs2
copy :: forall (n :: Nat) bs1 bs2 p.
(ByteArrayN n bs1, ByteArrayN n bs2, ByteArrayAccess bs1,
 KnownNat n) =>
bs1 -> (Ptr p -> IO ()) -> IO bs2
copy bs1
bs Ptr p -> IO ()
f = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @n forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> do
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs1
bs forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d Ptr Word8
s (forall ba. ByteArrayAccess ba => ba -> Int
length bs1
bs)
    Ptr p -> IO ()
f (forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
d)

-- | Similar to 'copy' but also provide a way to return a value from the initializer
copyRet :: forall n bs1 bs2 p a
         . ( ByteArrayN n bs1, ByteArrayN n bs2
           , ByteArrayAccess bs1
           , KnownNat n
           )
        => bs1 -> (Ptr p -> IO a) -> IO (a, bs2)
copyRet :: forall (n :: Nat) bs1 bs2 p a.
(ByteArrayN n bs1, ByteArrayN n bs2, ByteArrayAccess bs1,
 KnownNat n) =>
bs1 -> (Ptr p -> IO a) -> IO (a, bs2)
copyRet bs1
bs Ptr p -> IO a
f =
    forall (n :: Nat) c p a.
ByteArrayN n c =>
Proxy n -> (Ptr p -> IO a) -> IO (a, c)
allocRet (forall {k} (t :: k). Proxy t
Proxy @n) forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> do
        forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs1
bs forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d Ptr Word8
s (forall ba. ByteArrayAccess ba => ba -> Int
length bs1
bs)
        Ptr p -> IO a
f (forall a b. Ptr a -> Ptr b
castPtr Ptr Word8
d)

-- | Similiar to 'copy' but expect the resulting bytearray in a pure context
copyAndFreeze :: forall n bs1 bs2 p
               . ( ByteArrayN n bs1, ByteArrayN n bs2
                 , ByteArrayAccess bs1
                 , KnownNat n
                 )
              => bs1 -> (Ptr p -> IO ()) -> bs2
copyAndFreeze :: forall (n :: Nat) bs1 bs2 p.
(ByteArrayN n bs1, ByteArrayN n bs2, ByteArrayAccess bs1,
 KnownNat n) =>
bs1 -> (Ptr p -> IO ()) -> bs2
copyAndFreeze bs1
bs Ptr p -> IO ()
f =
    forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate @n forall a b. (a -> b) -> a -> b
$ \Ptr Any
d -> do
        forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
copyByteArrayToPtr bs1
bs Ptr Any
d
        Ptr p -> IO ()
f (forall a b. Ptr a -> Ptr b
castPtr Ptr Any
d)
{-# NOINLINE copyAndFreeze #-}

-- | Create a bytearray of a specific size containing a repeated byte value
replicate :: forall n ba . (ByteArrayN n ba, KnownNat n)
          => Word8 -> ba
replicate :: forall (n :: Nat) ba. (ByteArrayN n ba, KnownNat n) => Word8 -> ba
replicate Word8
b = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate @n forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr -> Ptr Word8 -> Word8 -> Int -> IO ()
memSet Ptr Word8
ptr Word8
b (forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal forall a b. (a -> b) -> a -> b
$ forall {k} (t :: k). Proxy t
Proxy @n)
{-# NOINLINE replicate #-}

-- | Create a bytearray of a specific size initialized to 0
zero :: forall n ba . (ByteArrayN n ba, KnownNat n) => ba
zero :: forall (n :: Nat) ba. (ByteArrayN n ba, KnownNat n) => ba
zero = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @n forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr -> Ptr Word8 -> Word8 -> Int -> IO ()
memSet Ptr Word8
ptr Word8
0 (forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal forall a b. (a -> b) -> a -> b
$ forall {k} (t :: k). Proxy t
Proxy @n)
{-# NOINLINE zero #-}

-- | Convert a bytearray to another type of bytearray
convert :: forall n bin bout
         . ( ByteArrayN n bin, ByteArrayN n bout
           , KnownNat n
           )
        => bin -> bout
convert :: forall (n :: Nat) bin bout.
(ByteArrayN n bin, ByteArrayN n bout, KnownNat n) =>
bin -> bout
convert bin
bs = forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate @n (forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
copyByteArrayToPtr bin
bs)

-- | Convert a ByteArrayAccess to another type of bytearray
--
-- This function returns nothing if the size is not compatible
fromByteArrayAccess :: forall n bin bout
                     . ( ByteArrayAccess bin, ByteArrayN n bout
                       , KnownNat n
                       )
                    => bin -> Maybe bout
fromByteArrayAccess :: forall (n :: Nat) bin bout.
(ByteArrayAccess bin, ByteArrayN n bout, KnownNat n) =>
bin -> Maybe bout
fromByteArrayAccess bin
bs
    | Int
l forall a. Eq a => a -> a -> Bool
== Int
n    = forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate @n (forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
copyByteArrayToPtr bin
bs)
    | Bool
otherwise = forall a. Maybe a
Nothing
  where
    l :: Int
l = forall ba. ByteArrayAccess ba => ba -> Int
length bin
bs
    n :: Int
n = forall a. Integral a => Integer -> a
fromInteger forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @n)

-- | Convert a ByteArrayAccess to another type of bytearray
unsafeFromByteArrayAccess :: forall n bin bout
                           . ( ByteArrayAccess bin, ByteArrayN n bout
                             , KnownNat n
                           )
                          => bin -> bout
unsafeFromByteArrayAccess :: forall (n :: Nat) bin bout.
(ByteArrayAccess bin, ByteArrayN n bout, KnownNat n) =>
bin -> bout
unsafeFromByteArrayAccess bin
bs = case forall (n :: Nat) bin bout.
(ByteArrayAccess bin, ByteArrayN n bout, KnownNat n) =>
bin -> Maybe bout
fromByteArrayAccess @n @bin @bout bin
bs of
    Maybe bout
Nothing -> forall a. HasCallStack => String -> a
error String
"Invalid Size"
    Just bout
v  -> bout
v