module Plutarch.Builtin.Array (
  PArray (PArray),
  plengthOfArray,
  plistToArray,
  pindexArray,
) where

import Data.Kind (Type)
import GHC.Generics (Generic)
import Generics.SOP qualified as SOP
import Plutarch.Builtin.Data (PBuiltinList)
import Plutarch.Builtin.Integer (PInteger)
import Plutarch.Internal.Term (
  S,
  Term,
  pforce,
  phoistAcyclic,
  punsafeBuiltin,
  (:-->),
 )
import PlutusCore qualified as PLC

{- | A packed collection of values.

@since 1.11.0
-}
newtype PArray (a :: S -> Type) (s :: S)
  = PArray (Term s (PArray a))
  deriving stock
    ( -- | @since 1.11.0
      (forall x. PArray a s -> Rep (PArray a s) x)
-> (forall x. Rep (PArray a s) x -> PArray a s)
-> Generic (PArray a s)
forall x. Rep (PArray a s) x -> PArray a s
forall x. PArray a s -> Rep (PArray a s) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (a :: S -> Type) (s :: S) x.
Rep (PArray a s) x -> PArray a s
forall (a :: S -> Type) (s :: S) x.
PArray a s -> Rep (PArray a s) x
$cfrom :: forall (a :: S -> Type) (s :: S) x.
PArray a s -> Rep (PArray a s) x
from :: forall x. PArray a s -> Rep (PArray a s) x
$cto :: forall (a :: S -> Type) (s :: S) x.
Rep (PArray a s) x -> PArray a s
to :: forall x. Rep (PArray a s) x -> PArray a s
Generic
    )
  deriving anyclass
    ( -- | @since 1.11.0
      All @[Type] (SListI @Type) (Code (PArray a s))
All @[Type] (SListI @Type) (Code (PArray a s)) =>
(PArray a s -> Rep (PArray a s))
-> (Rep (PArray a s) -> PArray a s) -> Generic (PArray a s)
Rep (PArray a s) -> PArray a s
PArray a s -> Rep (PArray a s)
forall a.
All @[Type] (SListI @Type) (Code a) =>
(a -> Rep a) -> (Rep a -> a) -> Generic a
forall (a :: S -> Type) (s :: S).
All @[Type] (SListI @Type) (Code (PArray a s))
forall (a :: S -> Type) (s :: S). Rep (PArray a s) -> PArray a s
forall (a :: S -> Type) (s :: S). PArray a s -> Rep (PArray a s)
$cfrom :: forall (a :: S -> Type) (s :: S). PArray a s -> Rep (PArray a s)
from :: PArray a s -> Rep (PArray a s)
$cto :: forall (a :: S -> Type) (s :: S). Rep (PArray a s) -> PArray a s
to :: Rep (PArray a s) -> PArray a s
SOP.Generic
    )

{- | Get the length of an array, as per
[CIP-138](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0138).

@since 1.11.0
-}
plengthOfArray ::
  forall (a :: S -> Type) (s :: S).
  Term s (PArray a :--> PInteger)
plengthOfArray :: forall (a :: S -> Type) (s :: S). Term s (PArray a :--> PInteger)
plengthOfArray = (forall (s' :: S). Term s' (PArray a :--> PInteger))
-> Term s (PArray a :--> PInteger)
forall (a :: S -> Type) (s :: S).
HasCallStack =>
(forall (s' :: S). Term s' a) -> Term s a
phoistAcyclic ((forall (s' :: S). Term s' (PArray a :--> PInteger))
 -> Term s (PArray a :--> PInteger))
-> (forall (s' :: S). Term s' (PArray a :--> PInteger))
-> Term s (PArray a :--> PInteger)
forall a b. (a -> b) -> a -> b
$ Term s' (PDelayed (PArray a :--> PInteger))
-> Term s' (PArray a :--> PInteger)
forall (s :: S) (a :: S -> Type). Term s (PDelayed a) -> Term s a
pforce (Term s' (PDelayed (PArray a :--> PInteger))
 -> Term s' (PArray a :--> PInteger))
-> Term s' (PDelayed (PArray a :--> PInteger))
-> Term s' (PArray a :--> PInteger)
forall a b. (a -> b) -> a -> b
$ DefaultFun -> Term s' (PDelayed (PArray a :--> PInteger))
forall (s :: S) (a :: S -> Type). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.LengthOfArray

{- | Convert a (builtin) list to an array with the same contents in the same
order, as per
[CIP-138](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0138).

@since 1.11.0
-}
plistToArray ::
  forall (a :: S -> Type) (s :: S).
  Term s (PBuiltinList a :--> PArray a)
plistToArray :: forall (a :: S -> Type) (s :: S).
Term s (PBuiltinList a :--> PArray a)
plistToArray = (forall (s' :: S). Term s' (PBuiltinList a :--> PArray a))
-> Term s (PBuiltinList a :--> PArray a)
forall (a :: S -> Type) (s :: S).
HasCallStack =>
(forall (s' :: S). Term s' a) -> Term s a
phoistAcyclic ((forall (s' :: S). Term s' (PBuiltinList a :--> PArray a))
 -> Term s (PBuiltinList a :--> PArray a))
-> (forall (s' :: S). Term s' (PBuiltinList a :--> PArray a))
-> Term s (PBuiltinList a :--> PArray a)
forall a b. (a -> b) -> a -> b
$ Term s' (PDelayed (PBuiltinList a :--> PArray a))
-> Term s' (PBuiltinList a :--> PArray a)
forall (s :: S) (a :: S -> Type). Term s (PDelayed a) -> Term s a
pforce (Term s' (PDelayed (PBuiltinList a :--> PArray a))
 -> Term s' (PBuiltinList a :--> PArray a))
-> Term s' (PDelayed (PBuiltinList a :--> PArray a))
-> Term s' (PBuiltinList a :--> PArray a)
forall a b. (a -> b) -> a -> b
$ DefaultFun -> Term s' (PDelayed (PBuiltinList a :--> PArray a))
forall (s :: S) (a :: S -> Type). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.ListToArray

{- | Index an array, as per
[CIP-138](https://github.com/cardano-foundation/CIPs/tree/master/CIP-0138).

@since 1.11.0
-}
pindexArray ::
  forall (a :: S -> Type) (s :: S).
  Term s (PArray a :--> PInteger :--> a)
pindexArray :: forall (a :: S -> Type) (s :: S).
Term s (PArray a :--> (PInteger :--> a))
pindexArray = (forall (s' :: S). Term s' (PArray a :--> (PInteger :--> a)))
-> Term s (PArray a :--> (PInteger :--> a))
forall (a :: S -> Type) (s :: S).
HasCallStack =>
(forall (s' :: S). Term s' a) -> Term s a
phoistAcyclic ((forall (s' :: S). Term s' (PArray a :--> (PInteger :--> a)))
 -> Term s (PArray a :--> (PInteger :--> a)))
-> (forall (s' :: S). Term s' (PArray a :--> (PInteger :--> a)))
-> Term s (PArray a :--> (PInteger :--> a))
forall a b. (a -> b) -> a -> b
$ Term s' (PDelayed (PArray a :--> (PInteger :--> a)))
-> Term s' (PArray a :--> (PInteger :--> a))
forall (s :: S) (a :: S -> Type). Term s (PDelayed a) -> Term s a
pforce (Term s' (PDelayed (PArray a :--> (PInteger :--> a)))
 -> Term s' (PArray a :--> (PInteger :--> a)))
-> Term s' (PDelayed (PArray a :--> (PInteger :--> a)))
-> Term s' (PArray a :--> (PInteger :--> a))
forall a b. (a -> b) -> a -> b
$ DefaultFun -> Term s' (PDelayed (PArray a :--> (PInteger :--> a)))
forall (s :: S) (a :: S -> Type). DefaultFun -> Term s a
punsafeBuiltin DefaultFun
PLC.IndexArray