-- SPDX-FileCopyrightText: 2020 Serokell
--
-- SPDX-License-Identifier: MPL-2.0

-- | 'ByteArray' with length known at compile time. Internal module.
module Data.ByteArray.Sized.Internal
  ( OfLength (..)
  , hasRightLength

  , allocRet
  , alloc
  ) where

import Prelude hiding (length)

import Data.Bifunctor (second)
import Data.Proxy (Proxy (Proxy))
import Data.The (The)
import Foreign.Ptr (Ptr)
import GHC.TypeLits (KnownNat, Nat, natVal)

import Data.ByteArray (ByteArray, ByteArrayAccess, length)

import qualified Data.ByteArray


-- Type of byte arrays that have length @l@.
newtype OfLength (l :: Nat) ba = OfLength ba
  deriving (OfLength l ba -> Int
OfLength l ba -> Ptr p -> IO ()
OfLength l ba -> (Ptr p -> IO a) -> IO a
(OfLength l ba -> Int)
-> (forall p a. OfLength l ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. OfLength l ba -> Ptr p -> IO ())
-> ByteArrayAccess (OfLength l ba)
forall p. OfLength l ba -> Ptr p -> IO ()
forall ba.
(ba -> Int)
-> (forall p a. ba -> (Ptr p -> IO a) -> IO a)
-> (forall p. ba -> Ptr p -> IO ())
-> ByteArrayAccess ba
forall p a. OfLength l ba -> (Ptr p -> IO a) -> IO a
forall (l :: Nat) ba. ByteArrayAccess ba => OfLength l ba -> Int
forall (l :: Nat) ba p.
ByteArrayAccess ba =>
OfLength l ba -> Ptr p -> IO ()
forall (l :: Nat) ba p a.
ByteArrayAccess ba =>
OfLength l ba -> (Ptr p -> IO a) -> IO a
copyByteArrayToPtr :: OfLength l ba -> Ptr p -> IO ()
$ccopyByteArrayToPtr :: forall (l :: Nat) ba p.
ByteArrayAccess ba =>
OfLength l ba -> Ptr p -> IO ()
withByteArray :: OfLength l ba -> (Ptr p -> IO a) -> IO a
$cwithByteArray :: forall (l :: Nat) ba p a.
ByteArrayAccess ba =>
OfLength l ba -> (Ptr p -> IO a) -> IO a
length :: OfLength l ba -> Int
$clength :: forall (l :: Nat) ba. ByteArrayAccess ba => OfLength l ba -> Int
ByteArrayAccess, OfLength l ba -> OfLength l ba -> Bool
(OfLength l ba -> OfLength l ba -> Bool)
-> (OfLength l ba -> OfLength l ba -> Bool) -> Eq (OfLength l ba)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall (l :: Nat) ba.
Eq ba =>
OfLength l ba -> OfLength l ba -> Bool
/= :: OfLength l ba -> OfLength l ba -> Bool
$c/= :: forall (l :: Nat) ba.
Eq ba =>
OfLength l ba -> OfLength l ba -> Bool
== :: OfLength l ba -> OfLength l ba -> Bool
$c== :: forall (l :: Nat) ba.
Eq ba =>
OfLength l ba -> OfLength l ba -> Bool
Eq, Semigroup (OfLength l ba)
OfLength l ba
Semigroup (OfLength l ba) =>
OfLength l ba
-> (OfLength l ba -> OfLength l ba -> OfLength l ba)
-> ([OfLength l ba] -> OfLength l ba)
-> Monoid (OfLength l ba)
[OfLength l ba] -> OfLength l ba
OfLength l ba -> OfLength l ba -> OfLength l ba
forall a.
Semigroup a =>
a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
forall (l :: Nat) ba. Monoid ba => Semigroup (OfLength l ba)
forall (l :: Nat) ba. Monoid ba => OfLength l ba
forall (l :: Nat) ba. Monoid ba => [OfLength l ba] -> OfLength l ba
forall (l :: Nat) ba.
Monoid ba =>
OfLength l ba -> OfLength l ba -> OfLength l ba
mconcat :: [OfLength l ba] -> OfLength l ba
$cmconcat :: forall (l :: Nat) ba. Monoid ba => [OfLength l ba] -> OfLength l ba
mappend :: OfLength l ba -> OfLength l ba -> OfLength l ba
$cmappend :: forall (l :: Nat) ba.
Monoid ba =>
OfLength l ba -> OfLength l ba -> OfLength l ba
mempty :: OfLength l ba
$cmempty :: forall (l :: Nat) ba. Monoid ba => OfLength l ba
$cp1Monoid :: forall (l :: Nat) ba. Monoid ba => Semigroup (OfLength l ba)
Monoid, Eq (OfLength l ba)
Eq (OfLength l ba) =>
(OfLength l ba -> OfLength l ba -> Ordering)
-> (OfLength l ba -> OfLength l ba -> Bool)
-> (OfLength l ba -> OfLength l ba -> Bool)
-> (OfLength l ba -> OfLength l ba -> Bool)
-> (OfLength l ba -> OfLength l ba -> Bool)
-> (OfLength l ba -> OfLength l ba -> OfLength l ba)
-> (OfLength l ba -> OfLength l ba -> OfLength l ba)
-> Ord (OfLength l ba)
OfLength l ba -> OfLength l ba -> Bool
OfLength l ba -> OfLength l ba -> Ordering
OfLength l ba -> OfLength l ba -> OfLength l 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 (l :: Nat) ba. Ord ba => Eq (OfLength l ba)
forall (l :: Nat) ba.
Ord ba =>
OfLength l ba -> OfLength l ba -> Bool
forall (l :: Nat) ba.
Ord ba =>
OfLength l ba -> OfLength l ba -> Ordering
forall (l :: Nat) ba.
Ord ba =>
OfLength l ba -> OfLength l ba -> OfLength l ba
min :: OfLength l ba -> OfLength l ba -> OfLength l ba
$cmin :: forall (l :: Nat) ba.
Ord ba =>
OfLength l ba -> OfLength l ba -> OfLength l ba
max :: OfLength l ba -> OfLength l ba -> OfLength l ba
$cmax :: forall (l :: Nat) ba.
Ord ba =>
OfLength l ba -> OfLength l ba -> OfLength l ba
>= :: OfLength l ba -> OfLength l ba -> Bool
$c>= :: forall (l :: Nat) ba.
Ord ba =>
OfLength l ba -> OfLength l ba -> Bool
> :: OfLength l ba -> OfLength l ba -> Bool
$c> :: forall (l :: Nat) ba.
Ord ba =>
OfLength l ba -> OfLength l ba -> Bool
<= :: OfLength l ba -> OfLength l ba -> Bool
$c<= :: forall (l :: Nat) ba.
Ord ba =>
OfLength l ba -> OfLength l ba -> Bool
< :: OfLength l ba -> OfLength l ba -> Bool
$c< :: forall (l :: Nat) ba.
Ord ba =>
OfLength l ba -> OfLength l ba -> Bool
compare :: OfLength l ba -> OfLength l ba -> Ordering
$ccompare :: forall (l :: Nat) ba.
Ord ba =>
OfLength l ba -> OfLength l ba -> Ordering
$cp1Ord :: forall (l :: Nat) ba. Ord ba => Eq (OfLength l ba)
Ord, b -> OfLength l ba -> OfLength l ba
NonEmpty (OfLength l ba) -> OfLength l ba
OfLength l ba -> OfLength l ba -> OfLength l ba
(OfLength l ba -> OfLength l ba -> OfLength l ba)
-> (NonEmpty (OfLength l ba) -> OfLength l ba)
-> (forall b. Integral b => b -> OfLength l ba -> OfLength l ba)
-> Semigroup (OfLength l ba)
forall b. Integral b => b -> OfLength l ba -> OfLength l ba
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
forall (l :: Nat) ba.
Semigroup ba =>
NonEmpty (OfLength l ba) -> OfLength l ba
forall (l :: Nat) ba.
Semigroup ba =>
OfLength l ba -> OfLength l ba -> OfLength l ba
forall (l :: Nat) ba b.
(Semigroup ba, Integral b) =>
b -> OfLength l ba -> OfLength l ba
stimes :: b -> OfLength l ba -> OfLength l ba
$cstimes :: forall (l :: Nat) ba b.
(Semigroup ba, Integral b) =>
b -> OfLength l ba -> OfLength l ba
sconcat :: NonEmpty (OfLength l ba) -> OfLength l ba
$csconcat :: forall (l :: Nat) ba.
Semigroup ba =>
NonEmpty (OfLength l ba) -> OfLength l ba
<> :: OfLength l ba -> OfLength l ba -> OfLength l ba
$c<> :: forall (l :: Nat) ba.
Semigroup ba =>
OfLength l ba -> OfLength l ba -> OfLength l ba
Semigroup)

instance The (OfLength l ba) ba


-- | Check that the byte array has the given length.
hasRightLength
  :: forall ba n. (ByteArrayAccess ba, KnownNat n)
  => ba
  -> Maybe (OfLength n ba)
hasRightLength :: ba -> Maybe (OfLength n ba)
hasRightLength ba :: ba
ba
  | Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ba -> Int
forall ba. ByteArrayAccess ba => ba -> Int
length ba
ba) Integer -> Integer -> Bool
forall a. Eq a => a -> a -> Bool
== Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n
forall k (t :: k). Proxy t
Proxy :: Proxy n) = OfLength n ba -> Maybe (OfLength n ba)
forall a. a -> Maybe a
Just (OfLength n ba -> Maybe (OfLength n ba))
-> OfLength n ba -> Maybe (OfLength n ba)
forall a b. (a -> b) -> a -> b
$ ba -> OfLength n ba
forall (l :: Nat) ba. ba -> OfLength l ba
OfLength ba
ba
  | Bool
otherwise = Maybe (OfLength n ba)
forall a. Maybe a
Nothing

-- | Allocate a new byte array of the given length, and perform the given operation.
--
-- This is the same as 'Data.ByteArray.allocRet'.
allocRet
  :: forall ba n p a. (ByteArray ba, KnownNat n)
  => (Ptr p -> IO a)
  -> IO (a, OfLength n ba)
allocRet :: (Ptr p -> IO a) -> IO (a, OfLength n ba)
allocRet
  = ((a, ba) -> (a, OfLength n ba))
-> IO (a, ba) -> IO (a, OfLength n ba)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ba -> OfLength n ba) -> (a, ba) -> (a, OfLength n ba)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ba -> OfLength n ba
forall (l :: Nat) ba. ba -> OfLength l ba
OfLength)
  (IO (a, ba) -> IO (a, OfLength n ba))
-> ((Ptr p -> IO a) -> IO (a, ba))
-> (Ptr p -> IO a)
-> IO (a, OfLength n ba)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> (Ptr p -> IO a) -> IO (a, ba)
forall ba p a. ByteArray ba => Int -> (Ptr p -> IO a) -> IO (a, ba)
Data.ByteArray.allocRet (Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n
forall k (t :: k). Proxy t
Proxy :: Proxy n))

-- | Allocate a new byte array of the given length, and run the initialiser.
--
-- This is the same as 'Data.ByteArray.alloc'.
alloc
  :: forall ba n p. (ByteArray ba, KnownNat n)
  => (Ptr p -> IO ())
  -> IO (OfLength n ba)
alloc :: (Ptr p -> IO ()) -> IO (OfLength n ba)
alloc
  = (ba -> OfLength n ba) -> IO ba -> IO (OfLength n ba)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ba -> OfLength n ba
forall (l :: Nat) ba. ba -> OfLength l ba
OfLength
  (IO ba -> IO (OfLength n ba))
-> ((Ptr p -> IO ()) -> IO ba)
-> (Ptr p -> IO ())
-> IO (OfLength n ba)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> (Ptr p -> IO ()) -> IO ba
forall ba p. ByteArray ba => Int -> (Ptr p -> IO ()) -> IO ba
Data.ByteArray.alloc (Integer -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Integer -> Int) -> Integer -> Int
forall a b. (a -> b) -> a -> b
$ Proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (Proxy n
forall k (t :: k). Proxy t
Proxy :: Proxy n))