    -- |
    -- 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
    (SizedByteArray n ba -> SizedByteArray n ba -> Bool)
    -> (SizedByteArray n ba -> SizedByteArray n ba -> Bool)
    -> Eq (SizedByteArray n ba)
    forall (n :: Nat) ba.
    Eq ba =>
    SizedByteArray n ba -> SizedByteArray n ba -> Bool
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $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
    /= :: 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 (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
    $cshowsPrec :: forall (n :: Nat) ba.
    Show ba =>
    Int -> SizedByteArray n ba -> ShowS
    showsPrec :: Int -> SizedByteArray n ba -> ShowS
    $cshow :: forall (n :: Nat) ba. Show ba => SizedByteArray n ba -> String
    show :: SizedByteArray n ba -> String
    $cshowList :: forall (n :: Nat) ba. Show ba => [SizedByteArray n ba] -> ShowS
    showList :: [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 (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
    $ccompare :: forall (n :: Nat) ba.
    Ord ba =>
    SizedByteArray n ba -> SizedByteArray n ba -> Ordering
    compare :: SizedByteArray n ba -> SizedByteArray n ba -> Ordering
    $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
    >= :: SizedByteArray n ba -> SizedByteArray n ba -> Bool
    $cmax :: 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
    $cmin :: 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
    Ord, SizedByteArray n ba -> ()
    (SizedByteArray n ba -> ()) -> NormalForm (SizedByteArray n ba)
    forall (n :: Nat) ba. NormalForm ba => SizedByteArray n ba -> ()
    forall a. (a -> ()) -> NormalForm a
    $ctoNormalForm :: forall (n :: Nat) ba. NormalForm ba => SizedByteArray n ba -> ()
    toNormalForm :: 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
        | 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 (forall (t :: Nat). Proxy t
    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 = 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 b c a. (b -> c) -> (a -> b) -> a -> c
    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 (forall (t :: Nat). Proxy t
    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) = ba -> (Ptr p -> IO a) -> IO a
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. 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, ba) <- Int -> (Ptr p -> IO a) -> IO (a, ba)
    forall ba p a. ByteArray ba => Int -> (Ptr p -> IO a) -> IO (a, ba)
    forall p a. Int -> (Ptr p -> IO a) -> IO (a, ba)
    ByteArray.allocRet Int
    n Ptr p -> IO a
    f
            pure (a, SizedByteArray 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 :: forall p a. Proxy nbytes -> (Ptr p -> IO a) -> IO (a, BlockN n ty)
    allocRet Proxy nbytes
    _ Ptr p -> IO a
    f = do
            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   <- BlockN.withMutablePtrHint True False mba (f . castPtr)
            ba  <- BlockN.freeze mba
            return (a, 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 = ((), 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)
    forall p a. Proxy n -> (Ptr p -> IO a) -> IO (a, ba)
    allocRet (forall (t :: Nat). Proxy t
    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 = IO ba -> ba
    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 = IO ba -> ba
    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 = IO ba -> ba
    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 = IO ba -> ba
    forall a. IO a -> a
    unsafeDoIO (forall (n :: Nat) ba p.
    (ByteArrayN n ba, KnownNat n) =>
    (Ptr p -> IO ()) -> IO ba
    alloc @0 ((Ptr (ZonkAny 7) -> IO ()) -> IO ba)
    -> (Ptr (ZonkAny 7) -> IO ()) -> IO ba
    forall a b. (a -> b) -> a -> b
    $ \Ptr (ZonkAny 7)
    _ -> () -> IO ()
    forall a. a -> IO a
    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 ([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 a. a -> IO a
    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 a b. IO a -> IO b -> IO b
    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 :: forall (n :: Nat) ba.
    (ByteArrayN n ba, KnownNat n, NatWithinBound Int n,
     ByteArrayAccess ba) =>
    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 (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 (ZonkAny 1) -> IO Word8) -> IO Word8
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. ba -> (Ptr p -> IO a) -> IO a
    withByteArray ba
    bs (Ptr (ZonkAny 1) -> Int -> IO Word8
    forall b. Ptr b -> 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 :: 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 ((Ptr (ZonkAny 2) -> IO ()) -> bo)
    -> (Ptr (ZonkAny 2) -> IO ()) -> bo
    forall a b. (a -> b) -> a -> b
    $ \Ptr (ZonkAny 2)
    d -> bi -> (Ptr Word8 -> IO ()) -> IO ()
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. bi -> (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 (ZonkAny 2) -> Int -> Word8 -> IO ()
    forall b. Ptr b -> Int -> Word8 -> IO ()
    forall a b. Storable a => Ptr b -> Int -> a -> IO ()
    pokeByteOff Ptr (ZonkAny 2)
    d Int
    0 Word8
    b
        Ptr Word8 -> Ptr Word8 -> Int -> IO ()
    memCopy (Ptr (ZonkAny 2)
    d Ptr (ZonkAny 2) -> 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 (forall (t :: Nat). Proxy t
    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 ((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
    forall p a. bi -> (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 b. Ptr b -> 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 (forall (t :: Nat). Proxy t
    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 ((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
    forall p a. a -> (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
    forall p a. b -> (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 (forall (t :: Nat). Proxy t
    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 = IO Word8 -> Word8
    forall a. IO a -> a
    unsafeDoIO (IO Word8 -> Word8) -> IO Word8 -> Word8
    forall a b. (a -> b) -> a -> b
    $ ba -> (Ptr (ZonkAny 0) -> IO Word8) -> IO Word8
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. ba -> (Ptr p -> IO a) -> IO a
    withByteArray ba
    b ((Ptr (ZonkAny 0) -> IO Word8) -> IO Word8)
    -> (Ptr (ZonkAny 0) -> IO Word8) -> IO Word8
    forall a b. (a -> b) -> a -> b
    $ \Ptr (ZonkAny 0)
    p -> Ptr Word8 -> IO Word8
    forall a. Storable a => Ptr a -> IO a
    peek (Ptr (ZonkAny 0)
    p Ptr (ZonkAny 0) -> 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 :: 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 = 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
    forall p a. bi -> (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
            b1 <- 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
            b2 <- alloc @nbrhs $ \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)
            return (b1, 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 (forall (t :: Nat). Proxy t
    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 :: 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 ((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
    forall p a. bi -> (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 (forall (t :: Nat). Proxy t
    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 ((Ptr Word8 -> IO ()) -> bo) -> (Ptr Word8 -> IO ()) -> bo
    forall a b. (a -> b) -> a -> b
    $ \Ptr Word8
    d ->
        bi -> (Ptr (ZonkAny 3) -> IO ()) -> IO ()
    forall ba p a. ByteArrayAccess ba => ba -> (Ptr p -> IO a) -> IO a
    forall p a. bi -> (Ptr p -> IO a) -> IO a
    withByteArray bi
    bs ((Ptr (ZonkAny 3) -> IO ()) -> IO ())
    -> (Ptr (ZonkAny 3) -> IO ()) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ \Ptr (ZonkAny 3)
    s ->
        Ptr Word8 -> Ptr Word8 -> Int -> IO ()
    memCopy Ptr Word8
    d (Ptr (ZonkAny 3)
    s Ptr (ZonkAny 3) -> 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 :: 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 ((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
    forall p a. blhs -> (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
    forall p a. brhs -> (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 :: 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 ((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
    forall p a. bs1 -> (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 :: 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 =
        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)
    forall p a. Proxy n -> (Ptr p -> IO a) -> IO (a, bs2)
    allocRet (forall (t :: Nat). Proxy t
    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
    forall p a. bs1 -> (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 :: 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 ((Ptr (ZonkAny 4) -> IO ()) -> bs2)
    -> (Ptr (ZonkAny 4) -> IO ()) -> bs2
    forall a b. (a -> b) -> a -> b
    $ \Ptr (ZonkAny 4)
    d -> do
            bs1 -> Ptr (ZonkAny 4) -> IO ()
    forall p. bs1 -> Ptr p -> IO ()
    forall ba p. ByteArrayAccess ba => ba -> Ptr p -> IO ()
    copyByteArrayToPtr bs1
    bs Ptr (ZonkAny 4)
    d
            Ptr p -> IO ()
    f (Ptr (ZonkAny 4) -> Ptr p
    forall a b. Ptr a -> Ptr b
    castPtr Ptr (ZonkAny 4)
    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 ((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
    $ forall (t :: Nat). Proxy t
    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 ((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
    $ forall (t :: Nat). Proxy t
    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 (bin -> Ptr (ZonkAny 5) -> IO ()
    forall p. bin -> Ptr p -> 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 :: forall (n :: Nat) bin bout.
    (ByteArrayAccess bin, ByteArrayN n bout, KnownNat n) =>
    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
    $ forall (n :: Nat) ba p.
    (ByteArrayN n ba, KnownNat n) =>
    (Ptr p -> IO ()) -> ba
    inlineUnsafeCreate @n (bin -> Ptr (ZonkAny 6) -> IO ()
    forall p. bin -> Ptr p -> 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 (forall (t :: Nat). Proxy t
    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 -> String -> bout
    forall a. HasCallStack => String -> a
    error String
    "Invalid Size"
        Just bout
    v  -> bout
    v