-- |
-- 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 { SizedByteArray n ba -> ba
unSizedByteArray :: ba }
  deriving (SizedByteArray n ba -> SizedByteArray n ba -> Bool
(SizedByteArray n ba -> SizedByteArray n ba -> Bool)
-> (SizedByteArray n ba -> SizedByteArray n ba -> Bool)
-> Eq (SizedByteArray n ba)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
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
== :: 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
[SizedByteArray n ba] -> ShowS
SizedByteArray n ba -> String
(Int -> SizedByteArray n ba -> ShowS)
-> (SizedByteArray n ba -> String)
-> ([SizedByteArray n ba] -> ShowS)
-> Show (SizedByteArray n ba)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
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
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, Eq (SizedByteArray n ba)
Eq (SizedByteArray n ba)
-> (SizedByteArray n ba -> SizedByteArray n ba -> Ordering)
-> (SizedByteArray n ba -> SizedByteArray n ba -> Bool)
-> (SizedByteArray n ba -> SizedByteArray n ba -> Bool)
-> (SizedByteArray n ba -> SizedByteArray n ba -> Bool)
-> (SizedByteArray n ba -> SizedByteArray n ba -> Bool)
-> (SizedByteArray n ba
    -> SizedByteArray n ba -> SizedByteArray n ba)
-> (SizedByteArray n ba
    -> SizedByteArray n ba -> SizedByteArray n ba)
-> Ord (SizedByteArray n ba)
SizedByteArray n ba -> SizedByteArray n ba -> Bool
SizedByteArray n ba -> SizedByteArray n ba -> Ordering
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
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
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
$cp1Ord :: forall (n :: Nat) ba. Ord ba => Eq (SizedByteArray n ba)
Ord, SizedByteArray n ba -> ()
(SizedByteArray n ba -> ()) -> NormalForm (SizedByteArray n ba)
forall a. (a -> ()) -> NormalForm a
forall (n :: Nat) ba. NormalForm ba => SizedByteArray n ba -> ()
toNormalForm :: SizedByteArray n ba -> ()
$ctoNormalForm :: forall (n :: Nat) ba. NormalForm ba => SizedByteArray n ba -> ()
NormalForm, b -> SizedByteArray n ba -> SizedByteArray n ba
NonEmpty (SizedByteArray n ba) -> SizedByteArray n ba
SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
(SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba)
-> (NonEmpty (SizedByteArray n ba) -> SizedByteArray n ba)
-> (forall b.
    Integral b =>
    b -> SizedByteArray n ba -> SizedByteArray n ba)
-> Semigroup (SizedByteArray n ba)
forall b.
Integral b =>
b -> SizedByteArray n ba -> SizedByteArray n ba
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
forall (n :: Nat) ba.
Semigroup ba =>
NonEmpty (SizedByteArray n ba) -> SizedByteArray n ba
forall (n :: Nat) ba.
Semigroup ba =>
SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
forall (n :: Nat) ba b.
(Semigroup ba, Integral b) =>
b -> SizedByteArray n ba -> SizedByteArray n ba
stimes :: b -> SizedByteArray n ba -> SizedByteArray n ba
$cstimes :: forall (n :: Nat) ba b.
(Semigroup ba, Integral b) =>
b -> SizedByteArray n ba -> SizedByteArray n ba
sconcat :: NonEmpty (SizedByteArray n ba) -> SizedByteArray n ba
$csconcat :: forall (n :: Nat) ba.
Semigroup ba =>
NonEmpty (SizedByteArray n ba) -> SizedByteArray n ba
<> :: SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
$c<> :: forall (n :: Nat) ba.
Semigroup ba =>
SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
Semigroup, Semigroup (SizedByteArray n ba)
SizedByteArray n ba
Semigroup (SizedByteArray n ba)
-> SizedByteArray n ba
-> (SizedByteArray n ba
    -> SizedByteArray n ba -> SizedByteArray n ba)
-> ([SizedByteArray n ba] -> SizedByteArray n ba)
-> Monoid (SizedByteArray n ba)
[SizedByteArray n ba] -> SizedByteArray n ba
SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
forall a.
Semigroup a -> a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
forall (n :: Nat) ba. Monoid ba => Semigroup (SizedByteArray n ba)
forall (n :: Nat) ba. Monoid ba => SizedByteArray n ba
forall (n :: Nat) ba.
Monoid ba =>
[SizedByteArray n ba] -> SizedByteArray n ba
forall (n :: Nat) ba.
Monoid ba =>
SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
mconcat :: [SizedByteArray n ba] -> SizedByteArray n ba
$cmconcat :: forall (n :: Nat) ba.
Monoid ba =>
[SizedByteArray n ba] -> SizedByteArray n ba
mappend :: SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
$cmappend :: forall (n :: Nat) ba.
Monoid ba =>
SizedByteArray n ba -> SizedByteArray n ba -> SizedByteArray n ba
mempty :: SizedByteArray n ba
$cmempty :: forall (n :: Nat) ba. Monoid ba => SizedByteArray n ba
$cp1Monoid :: forall (n :: Nat) ba. Monoid ba => Semigroup (SizedByteArray n ba)
Monoid)

-- | 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 :: ba -> Maybe (SizedByteArray n ba)
sizedByteArray ba
ba
    | ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length ba
ba Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
n = SizedByteArray n ba -> Maybe (SizedByteArray n ba)
forall a. a -> Maybe a
Just (SizedByteArray n ba -> Maybe (SizedByteArray n ba))
-> SizedByteArray n ba -> Maybe (SizedByteArray n ba)
forall a b. (a -> b) -> a -> b
$ ba -> SizedByteArray n ba
forall (n :: Nat) ba. ba -> SizedByteArray n ba
SizedByteArray ba
ba
    | Bool
otherwise      = Maybe (SizedByteArray n ba)
forall a. Maybe a
Nothing
  where
    n :: Int
n = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n
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 :: ba -> SizedByteArray n ba
unsafeSizedByteArray = SizedByteArray n ba
-> Maybe (SizedByteArray n ba) -> SizedByteArray n ba
forall a. a -> Maybe a -> a
fromMaybe (String -> SizedByteArray n ba
forall a. HasCallStack => String -> a
error String
"The size is invalid") (Maybe (SizedByteArray n ba) -> SizedByteArray n ba)
-> (ba -> Maybe (SizedByteArray n ba)) -> ba -> SizedByteArray n ba
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. ba -> Maybe (SizedByteArray n ba)
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
_ = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n
forall k (t :: k). Proxy t
Proxy @n)
    withByteArray :: SizedByteArray n ba -> (Ptr p -> IO a) -> IO a
withByteArray (SizedByteArray ba
ba) = ba -> (Ptr p -> IO a) -> IO a
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 :: 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) <- Int -> (Ptr p -> IO a) -> IO (a, ba)
forall ba p a. ByteArray ba => Int -> (Ptr p -> IO a) -> IO (a, ba)
ByteArray.allocRet Int
n Ptr p -> IO a
f
        (a, SizedByteArray n ba) -> IO (a, SizedByteArray n ba)
forall (f :: Type -> Type) a. Applicative f => a -> f a
pure (a
a, ba -> SizedByteArray n ba
forall (n :: Nat) ba. ba -> SizedByteArray n ba
SizedByteArray ba
ba)
      where
        n :: Int
n = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
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 :: 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 ty (prim :: Type -> Type).
(PrimType ty, KnownNat n, Countable ty n, PrimMonad prim) =>
prim (MutableBlockN n ty (PrimState prim))
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   <- Bool
-> Bool
-> MutableBlockN n ty (PrimState IO)
-> (Ptr ty -> IO a)
-> IO 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
MutableBlockN n ty (PrimState IO)
mba (Ptr p -> IO a
f (Ptr p -> IO a) -> (Ptr ty -> Ptr p) -> Ptr ty -> IO a
forall k (cat :: k -> k -> Type) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Ptr ty -> Ptr p
forall a b. Ptr a -> Ptr b
castPtr)
        BlockN n ty
ba  <- MutableBlockN n ty (PrimState IO) -> IO (BlockN n ty)
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
MutableBlockN n ty (PrimState IO)
mba
        (a, BlockN n ty) -> IO (a, BlockN n ty)
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 :: (Ptr p -> IO ()) -> IO ba
alloc Ptr p -> IO ()
f = ((), ba) -> ba
forall a b. (a, b) -> b
snd (((), ba) -> ba) -> IO ((), ba) -> IO ba
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Proxy n -> (Ptr p -> IO ()) -> IO ((), ba)
forall (n :: Nat) c p a.
ByteArrayN n c =>
Proxy n -> (Ptr p -> IO a) -> IO (a, c)
allocRet (Proxy n
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 :: (Ptr p -> IO ()) -> IO ba
create = forall ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
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 :: (Ptr p -> IO ()) -> ba
allocAndFreeze Ptr p -> IO ()
f = IO ba -> ba
forall a. IO a -> a
unsafeDoIO ((Ptr p -> IO ()) -> IO ba
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 :: (Ptr p -> IO ()) -> ba
unsafeCreate Ptr p -> IO ()
f = IO ba -> ba
forall a. IO a -> a
unsafeDoIO ((Ptr p -> IO ()) -> IO ba
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 :: (Ptr p -> IO ()) -> ba
inlineUnsafeCreate Ptr p -> IO ()
f = IO ba -> ba
forall a. IO a -> a
unsafeDoIO ((Ptr p -> IO ()) -> IO ba
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 :: ba
empty = IO ba -> ba
forall a. IO a -> a
unsafeDoIO (forall ba p.
(ByteArrayN 0 ba, KnownNat 0) =>
(Ptr p -> IO ()) -> IO ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @0 ((Ptr Any -> IO ()) -> IO ba) -> (Ptr Any -> IO ()) -> IO ba
forall a b. (a -> b) -> a -> b
$ \Ptr Any
_ -> () -> IO ()
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 :: ListN n Word8 -> ba
pack ListN n Word8
l = (Ptr Word8 -> IO ()) -> ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate @n ([Word8] -> Ptr Word8 -> IO ()
forall b. Storable b => [b] -> Ptr b -> IO ()
fill ([Word8] -> Ptr Word8 -> IO ()) -> [Word8] -> Ptr Word8 -> IO ()
forall a b. (a -> b) -> a -> b
$ ListN n Word8 -> [Word8]
forall (n :: Nat) a. ListN n a -> [a]
unListN ListN n Word8
l)
  where fill :: [b] -> Ptr b -> IO ()
fill []     Ptr b
_  = () -> IO ()
forall (m :: Type -> Type) a. Monad m => a -> m a
return ()
        fill (b
x:[b]
xs) !Ptr b
p = Ptr b -> b -> IO ()
forall a. Storable a => Ptr a -> a -> IO ()
poke Ptr b
p b
x IO () -> IO () -> IO ()
forall (m :: Type -> Type) a b. Monad m => m a -> m b -> m b
>> [b] -> Ptr b -> IO ()
fill [b]
xs (Ptr b
p Ptr b -> Int -> Ptr b
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 :: ba -> ListN n Word8
unpack ba
bs =  ListN n Word8 -> Maybe (ListN n Word8) -> ListN n Word8
forall a. a -> Maybe a -> a
fromMaybe (String -> ListN n Word8
forall a. HasCallStack => String -> a
error String
"the impossible appened") (Maybe (ListN n Word8) -> ListN n Word8)
-> Maybe (ListN n Word8) -> ListN n Word8
forall a b. (a -> b) -> a -> b
$ forall a.
(KnownNat n, NatWithinBound Int n) =>
[a] -> Maybe (ListN n a)
forall (n :: Nat) a.
(KnownNat n, NatWithinBound Int n) =>
[a] -> Maybe (ListN n a)
toListN @n ([Word8] -> Maybe (ListN n Word8))
-> [Word8] -> Maybe (ListN n Word8)
forall a b. (a -> b) -> a -> b
$ Int -> [Word8]
loop Int
0
  where !len :: Int
len = ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length ba
bs
        loop :: Int -> [Word8]
loop Int
i
            | Int
i Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
len  = []
            | Bool
otherwise =
                let !v :: Word8
v = IO Word8 -> Word8
forall a. IO a -> a
unsafeDoIO (IO Word8 -> Word8) -> IO Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ ba -> (Ptr Any -> IO Word8) -> IO Word8
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
bs (Ptr Any -> Int -> IO Word8
forall a b. Storable a => Ptr b -> Int -> IO a
`peekByteOff` Int
i)
                 in Word8
v Word8 -> [Word8] -> [Word8]
forall a. a -> [a] -> [a]
: Int -> [Word8]
loop (Int
iInt -> Int -> Int
forall 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 :: Word8 -> bi -> bo
cons Word8
b bi
ba = forall ba p.
(ByteArrayN no ba, KnownNat no) =>
(Ptr p -> IO ()) -> ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @no ((Ptr Any -> IO ()) -> bo) -> (Ptr Any -> IO ()) -> bo
forall a b. (a -> b) -> a -> b
$ \Ptr Any
d -> bi -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bi
ba ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> do
    Ptr Any -> Int -> Word8 -> IO ()
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 Ptr Any -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
1) Ptr Word8
s Int
len
  where
    !len :: Int
len = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy ni -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (Proxy ni
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 :: bi -> Word8 -> bo
snoc bi
ba Word8
b = forall ba p.
(ByteArrayN no ba, KnownNat no) =>
(Ptr p -> IO ()) -> ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @no ((Ptr Word8 -> IO ()) -> bo) -> (Ptr Word8 -> IO ()) -> bo
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> bi -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bi
ba ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
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
    Ptr Word8 -> Int -> Word8 -> IO ()
forall a b. Storable a => Ptr b -> Int -> a -> IO ()
pokeByteOff Ptr Word8
d Int
len Word8
b
  where
    !len :: Int
len = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy ni -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (Proxy ni
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 :: a -> b -> c
xor a
a b
b =
    forall ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @n ((Ptr Word8 -> IO ()) -> c) -> (Ptr Word8 -> IO ()) -> c
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pc ->
    a -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray a
a  ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
pa ->
    b -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray b
b  ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
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  = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n
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 :: ba -> Proxy n -> Word8
index ba
b Proxy n
pi = IO Word8 -> Word8
forall a. IO a -> a
unsafeDoIO (IO Word8 -> Word8) -> IO Word8 -> Word8
forall a b. (a -> b) -> a -> b
$ ba -> (Ptr Any -> IO Word8) -> IO Word8
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray ba
b ((Ptr Any -> IO Word8) -> IO Word8)
-> (Ptr Any -> IO Word8) -> IO Word8
forall a b. (a -> b) -> a -> b
$ \Ptr Any
p -> Ptr Word8 -> IO Word8
forall a. Storable a => Ptr a -> IO a
peek (Ptr Any
p Ptr Any -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
i)
  where
    i :: Int
i = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
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 :: bi -> (blhs, brhs)
splitAt bi
bs = IO (blhs, brhs) -> (blhs, brhs)
forall a. IO a -> a
unsafeDoIO (IO (blhs, brhs) -> (blhs, brhs))
-> IO (blhs, brhs) -> (blhs, brhs)
forall a b. (a -> b) -> a -> b
$
    bi -> (Ptr Word8 -> IO (blhs, brhs)) -> IO (blhs, brhs)
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bi
bs ((Ptr Word8 -> IO (blhs, brhs)) -> IO (blhs, brhs))
-> (Ptr Word8 -> IO (blhs, brhs)) -> IO (blhs, brhs)
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p -> do
        blhs
b1 <- forall ba p.
(ByteArrayN nblhs ba, KnownNat nblhs) =>
(Ptr p -> IO ()) -> IO ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @nblhs ((Ptr Word8 -> IO ()) -> IO blhs)
-> (Ptr Word8 -> IO ()) -> IO blhs
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 ba p.
(ByteArrayN nbrhs ba, KnownNat nbrhs) =>
(Ptr p -> IO ()) -> IO ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @nbrhs ((Ptr Word8 -> IO ()) -> IO brhs)
-> (Ptr Word8 -> IO ()) -> IO brhs
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
r -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
r (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
n) (Int
len Int -> Int -> Difference Int
forall a. Subtractive a => a -> a -> Difference a
- Int
n)
        (blhs, brhs) -> IO (blhs, brhs)
forall (m :: Type -> Type) a. Monad m => a -> m a
return (blhs
b1, brhs
b2)
  where
    n :: Int
n = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy nblhs -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (Proxy nblhs
forall k (t :: k). Proxy t
Proxy @nblhs)
    len :: Int
len = bi -> Int
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 :: bi -> bo
take bi
bs = forall ba p.
(ByteArrayN nbo ba, KnownNat nbo) =>
(Ptr p -> IO ()) -> ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @nbo ((Ptr Word8 -> IO ()) -> bo) -> (Ptr Word8 -> IO ()) -> bo
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> bi -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bi
bs ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
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   = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
len Int
n
    !len :: Int
len = bi -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bi
bs
    !n :: Int
n   = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy nbo -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (Proxy nbo
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 :: Proxy n -> bi -> bo
drop Proxy n
pn bi
bs = forall ba p.
(ByteArrayN nbo ba, KnownNat nbo) =>
(Ptr p -> IO ()) -> ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @nbo ((Ptr Word8 -> IO ()) -> bo) -> (Ptr Word8 -> IO ()) -> bo
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d ->
    bi -> (Ptr Any -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bi
bs ((Ptr Any -> IO ()) -> IO ()) -> (Ptr Any -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Any
s ->
    Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d (Ptr Any
s Ptr Any -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
ofs) Int
Difference Int
nb
  where
    ofs :: Int
ofs = Int -> Int -> Int
forall a. Ord a => a -> a -> a
min Int
len Int
n
    nb :: Difference Int
nb  = Int
len Int -> Int -> Difference Int
forall a. Subtractive a => a -> a -> Difference a
- Int
ofs
    len :: Int
len = bi -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bi
bs
    n :: Int
n   = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
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 :: blhs -> brhs -> bout
append blhs
blhs brhs
brhs = forall ba p.
(ByteArrayN nbout ba, KnownNat nbout) =>
(Ptr p -> IO ()) -> ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @nbout ((Ptr Word8 -> IO ()) -> bout) -> (Ptr Word8 -> IO ()) -> bout
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
p ->
    blhs -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray blhs
blhs ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
plhs ->
    brhs -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray brhs
brhs ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
prhs -> do
        Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
p Ptr Word8
plhs (blhs -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length blhs
blhs)
        Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy (Ptr Word8
p Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` blhs -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length blhs
blhs) Ptr Word8
prhs (brhs -> Int
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 :: bs1 -> (Ptr p -> IO ()) -> IO bs2
copy bs1
bs Ptr p -> IO ()
f = forall ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> IO ba
alloc @n ((Ptr Word8 -> IO ()) -> IO bs2) -> (Ptr Word8 -> IO ()) -> IO bs2
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> do
    bs1 -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs1
bs ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d Ptr Word8
s (bs1 -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs1
bs)
    Ptr p -> IO ()
f (Ptr Word8 -> Ptr p
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 :: bs1 -> (Ptr p -> IO a) -> IO (a, bs2)
copyRet bs1
bs Ptr p -> IO a
f =
    Proxy n -> (Ptr Word8 -> IO a) -> IO (a, bs2)
forall (n :: Nat) c p a.
ByteArrayN n c =>
Proxy n -> (Ptr p -> IO a) -> IO (a, c)
allocRet (Proxy n
forall k (t :: k). Proxy t
Proxy @n) ((Ptr Word8 -> IO a) -> IO (a, bs2))
-> (Ptr Word8 -> IO a) -> IO (a, bs2)
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
d -> do
        bs1 -> (Ptr Word8 -> IO ()) -> IO ()
forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
withByteArray bs1
bs ((Ptr Word8 -> IO ()) -> IO ()) -> (Ptr Word8 -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
s -> Ptr Word8 -> Ptr Word8 -> Int -> IO ()
memCopy Ptr Word8
d Ptr Word8
s (bs1 -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bs1
bs)
        Ptr p -> IO a
f (Ptr Word8 -> Ptr p
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 :: bs1 -> (Ptr p -> IO ()) -> bs2
copyAndFreeze bs1
bs Ptr p -> IO ()
f =
    forall ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate @n ((Ptr Any -> IO ()) -> bs2) -> (Ptr Any -> IO ()) -> bs2
forall a b. (a -> b) -> a -> b
$ \Ptr Any
d -> do
        bs1 -> Ptr Any -> IO ()
forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
copyByteArrayToPtr bs1
bs Ptr Any
d
        Ptr p -> IO ()
f (Ptr Any -> Ptr p
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 :: Word8 -> ba
replicate Word8
b = forall ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate @n ((Ptr Word8 -> IO ()) -> ba) -> (Ptr Word8 -> IO ()) -> ba
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr -> Ptr Word8 -> Word8 -> Int -> IO ()
memSet Ptr Word8
ptr Word8
b (Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n -> Integer) -> Proxy n -> Integer
forall a b. (a -> b) -> a -> b
$ Proxy n
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 :: ba
zero = forall ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
unsafeCreate @n ((Ptr Word8 -> IO ()) -> ba) -> (Ptr Word8 -> IO ()) -> ba
forall a b. (a -> b) -> a -> b
$ \Ptr Word8
ptr -> Ptr Word8 -> Word8 -> Int -> IO ()
memSet Ptr Word8
ptr Word8
0 (Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n -> Integer) -> Proxy n -> Integer
forall a b. (a -> b) -> a -> b
$ Proxy n
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 :: bin -> bout
convert bin
bs = (Ptr Any -> IO ()) -> bout
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate @n (bin -> Ptr Any -> IO ()
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 :: bin -> Maybe bout
fromByteArrayAccess bin
bs
    | Int
l Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
n    = bout -> Maybe bout
forall a. a -> Maybe a
Just (bout -> Maybe bout) -> bout -> Maybe bout
forall a b. (a -> b) -> a -> b
$ (Ptr Any -> IO ()) -> bout
forall (n :: Nat) ba p.
(ByteArrayN n ba, KnownNat n) =>
(Ptr p -> IO ()) -> ba
inlineUnsafeCreate @n (bin -> Ptr Any -> IO ()
forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
copyByteArrayToPtr bin
bs)
    | Bool
otherwise = Maybe bout
forall a. Maybe a
Nothing
  where
    l :: Int
l = bin -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length bin
bs
    n :: Int
n = Integer -> Int
forall a. Integral a => Integer -> a
fromInteger (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n
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 :: bin -> bout
unsafeFromByteArrayAccess bin
bs = case bin -> Maybe bout
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 -> String -> bout
forall a. HasCallStack => String -> a
error String
"Invalid Size"
    Just bout
v  -> bout
v