{-# LANGUAGE RoleAnnotations #-}
-- | Fixed size arrays
--
-- Intended for qualified import
--
-- > import Data.FixedSizeArray (FixedSizeArray)
-- > import qualified Data.FixedSizeArray as FSA
module Data.FixedSizeArray (
    FixedSizeArray  -- opaque
  , MFixedSizeArray -- opaque
  , toArray
  , toMArray
    -- * Construction
  , fromList
  , fromArray
  , fromMArray
  , new
  ) where

import Data.Coerce (coerce)
import Data.Kind (Type)
import Data.Proxy
import Data.Vector (Vector, MVector)
import GHC.TypeLits

import qualified Data.Vector.Generic         as G
import qualified Data.Vector.Generic.Mutable as GM

{-------------------------------------------------------------------------------
  Definition
-------------------------------------------------------------------------------}

-- | Fixed size arrays
--
-- @FixedSizeArray n a@ is the Haskell counter-part to the Rust type @[A; N]@.
--
-- NOTE: For convenience, this is an instance of 'G.Vector', but the invariant
-- that the length of the vector should never change is not currently checked.
type role FixedSizeArray nominal _
newtype FixedSizeArray (n :: Nat) (a :: Type) = FromArray {
      forall (n :: Nat) a. FixedSizeArray n a -> Vector a
toArray :: Vector a
    }
  deriving stock (Int -> FixedSizeArray n a -> ShowS
forall (n :: Nat) a. Show a => Int -> FixedSizeArray n a -> ShowS
forall (n :: Nat) a. Show a => [FixedSizeArray n a] -> ShowS
forall (n :: Nat) a. Show a => FixedSizeArray n a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [FixedSizeArray n a] -> ShowS
$cshowList :: forall (n :: Nat) a. Show a => [FixedSizeArray n a] -> ShowS
show :: FixedSizeArray n a -> String
$cshow :: forall (n :: Nat) a. Show a => FixedSizeArray n a -> String
showsPrec :: Int -> FixedSizeArray n a -> ShowS
$cshowsPrec :: forall (n :: Nat) a. Show a => Int -> FixedSizeArray n a -> ShowS
Show, FixedSizeArray n a -> FixedSizeArray n a -> Bool
forall (n :: Nat) a.
Eq a =>
FixedSizeArray n a -> FixedSizeArray n a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: FixedSizeArray n a -> FixedSizeArray n a -> Bool
$c/= :: forall (n :: Nat) a.
Eq a =>
FixedSizeArray n a -> FixedSizeArray n a -> Bool
== :: FixedSizeArray n a -> FixedSizeArray n a -> Bool
$c== :: forall (n :: Nat) a.
Eq a =>
FixedSizeArray n a -> FixedSizeArray n a -> Bool
Eq, FixedSizeArray n a -> FixedSizeArray n a -> Bool
FixedSizeArray n a -> FixedSizeArray n a -> Ordering
forall {n :: Nat} {a}. Ord a => Eq (FixedSizeArray n a)
forall (n :: Nat) a.
Ord a =>
FixedSizeArray n a -> FixedSizeArray n a -> Bool
forall (n :: Nat) a.
Ord a =>
FixedSizeArray n a -> FixedSizeArray n a -> Ordering
forall (n :: Nat) a.
Ord a =>
FixedSizeArray n a -> FixedSizeArray n a -> FixedSizeArray n a
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: FixedSizeArray n a -> FixedSizeArray n a -> FixedSizeArray n a
$cmin :: forall (n :: Nat) a.
Ord a =>
FixedSizeArray n a -> FixedSizeArray n a -> FixedSizeArray n a
max :: FixedSizeArray n a -> FixedSizeArray n a -> FixedSizeArray n a
$cmax :: forall (n :: Nat) a.
Ord a =>
FixedSizeArray n a -> FixedSizeArray n a -> FixedSizeArray n a
>= :: FixedSizeArray n a -> FixedSizeArray n a -> Bool
$c>= :: forall (n :: Nat) a.
Ord a =>
FixedSizeArray n a -> FixedSizeArray n a -> Bool
> :: FixedSizeArray n a -> FixedSizeArray n a -> Bool
$c> :: forall (n :: Nat) a.
Ord a =>
FixedSizeArray n a -> FixedSizeArray n a -> Bool
<= :: FixedSizeArray n a -> FixedSizeArray n a -> Bool
$c<= :: forall (n :: Nat) a.
Ord a =>
FixedSizeArray n a -> FixedSizeArray n a -> Bool
< :: FixedSizeArray n a -> FixedSizeArray n a -> Bool
$c< :: forall (n :: Nat) a.
Ord a =>
FixedSizeArray n a -> FixedSizeArray n a -> Bool
compare :: FixedSizeArray n a -> FixedSizeArray n a -> Ordering
$ccompare :: forall (n :: Nat) a.
Ord a =>
FixedSizeArray n a -> FixedSizeArray n a -> Ordering
Ord)
  deriving newtype (forall (n :: Nat) a b.
a -> FixedSizeArray n b -> FixedSizeArray n a
forall (n :: Nat) a b.
(a -> b) -> FixedSizeArray n a -> FixedSizeArray n b
forall a b. a -> FixedSizeArray n b -> FixedSizeArray n a
forall a b. (a -> b) -> FixedSizeArray n a -> FixedSizeArray n b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> FixedSizeArray n b -> FixedSizeArray n a
$c<$ :: forall (n :: Nat) a b.
a -> FixedSizeArray n b -> FixedSizeArray n a
fmap :: forall a b. (a -> b) -> FixedSizeArray n a -> FixedSizeArray n b
$cfmap :: forall (n :: Nat) a b.
(a -> b) -> FixedSizeArray n a -> FixedSizeArray n b
Functor, forall (n :: Nat) a. Eq a => a -> FixedSizeArray n a -> Bool
forall (n :: Nat) a. Num a => FixedSizeArray n a -> a
forall (n :: Nat) a. Ord a => FixedSizeArray n a -> a
forall (n :: Nat) m. Monoid m => FixedSizeArray n m -> m
forall (n :: Nat) a. FixedSizeArray n a -> Bool
forall (n :: Nat) a. FixedSizeArray n a -> Int
forall (n :: Nat) a. FixedSizeArray n a -> [a]
forall (n :: Nat) a. (a -> a -> a) -> FixedSizeArray n a -> a
forall (n :: Nat) m a.
Monoid m =>
(a -> m) -> FixedSizeArray n a -> m
forall (n :: Nat) b a.
(b -> a -> b) -> b -> FixedSizeArray n a -> b
forall (n :: Nat) a b.
(a -> b -> b) -> b -> FixedSizeArray n a -> b
forall a. Eq a => a -> FixedSizeArray n a -> Bool
forall a. Num a => FixedSizeArray n a -> a
forall a. Ord a => FixedSizeArray n a -> a
forall m. Monoid m => FixedSizeArray n m -> m
forall a. FixedSizeArray n a -> Bool
forall a. FixedSizeArray n a -> Int
forall a. FixedSizeArray n a -> [a]
forall a. (a -> a -> a) -> FixedSizeArray n a -> a
forall m a. Monoid m => (a -> m) -> FixedSizeArray n a -> m
forall b a. (b -> a -> b) -> b -> FixedSizeArray n a -> b
forall a b. (a -> b -> b) -> b -> FixedSizeArray n a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
product :: forall a. Num a => FixedSizeArray n a -> a
$cproduct :: forall (n :: Nat) a. Num a => FixedSizeArray n a -> a
sum :: forall a. Num a => FixedSizeArray n a -> a
$csum :: forall (n :: Nat) a. Num a => FixedSizeArray n a -> a
minimum :: forall a. Ord a => FixedSizeArray n a -> a
$cminimum :: forall (n :: Nat) a. Ord a => FixedSizeArray n a -> a
maximum :: forall a. Ord a => FixedSizeArray n a -> a
$cmaximum :: forall (n :: Nat) a. Ord a => FixedSizeArray n a -> a
elem :: forall a. Eq a => a -> FixedSizeArray n a -> Bool
$celem :: forall (n :: Nat) a. Eq a => a -> FixedSizeArray n a -> Bool
length :: forall a. FixedSizeArray n a -> Int
$clength :: forall (n :: Nat) a. FixedSizeArray n a -> Int
null :: forall a. FixedSizeArray n a -> Bool
$cnull :: forall (n :: Nat) a. FixedSizeArray n a -> Bool
toList :: forall a. FixedSizeArray n a -> [a]
$ctoList :: forall (n :: Nat) a. FixedSizeArray n a -> [a]
foldl1 :: forall a. (a -> a -> a) -> FixedSizeArray n a -> a
$cfoldl1 :: forall (n :: Nat) a. (a -> a -> a) -> FixedSizeArray n a -> a
foldr1 :: forall a. (a -> a -> a) -> FixedSizeArray n a -> a
$cfoldr1 :: forall (n :: Nat) a. (a -> a -> a) -> FixedSizeArray n a -> a
foldl' :: forall b a. (b -> a -> b) -> b -> FixedSizeArray n a -> b
$cfoldl' :: forall (n :: Nat) b a.
(b -> a -> b) -> b -> FixedSizeArray n a -> b
foldl :: forall b a. (b -> a -> b) -> b -> FixedSizeArray n a -> b
$cfoldl :: forall (n :: Nat) b a.
(b -> a -> b) -> b -> FixedSizeArray n a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> FixedSizeArray n a -> b
$cfoldr' :: forall (n :: Nat) a b.
(a -> b -> b) -> b -> FixedSizeArray n a -> b
foldr :: forall a b. (a -> b -> b) -> b -> FixedSizeArray n a -> b
$cfoldr :: forall (n :: Nat) a b.
(a -> b -> b) -> b -> FixedSizeArray n a -> b
foldMap' :: forall m a. Monoid m => (a -> m) -> FixedSizeArray n a -> m
$cfoldMap' :: forall (n :: Nat) m a.
Monoid m =>
(a -> m) -> FixedSizeArray n a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> FixedSizeArray n a -> m
$cfoldMap :: forall (n :: Nat) m a.
Monoid m =>
(a -> m) -> FixedSizeArray n a -> m
fold :: forall m. Monoid m => FixedSizeArray n m -> m
$cfold :: forall (n :: Nat) m. Monoid m => FixedSizeArray n m -> m
Foldable)

instance KnownNat n => Traversable (FixedSizeArray n) where
  traverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> FixedSizeArray n a -> f (FixedSizeArray n b)
traverse a -> f b
f = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall (n :: Nat) a. KnownNat n => Vector a -> FixedSizeArray n a
fromArray forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse a -> f b
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (n :: Nat) a. FixedSizeArray n a -> Vector a
toArray

-- | Mutable fixed-size arrays
newtype MFixedSizeArray (n :: Nat) s (a :: Type) = FromMArray {
      forall (n :: Nat) s a. MFixedSizeArray n s a -> MVector s a
toMArray :: MVector s a
    }

type instance G.Mutable (FixedSizeArray n) = MFixedSizeArray n

instance GM.MVector (MFixedSizeArray n) a where
  basicLength :: forall s. MFixedSizeArray n s a -> Int
basicLength      = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> * -> *) a s. MVector v a => v s a -> Int
GM.basicLength      @MVector @a
  basicUnsafeSlice :: forall s.
Int -> Int -> MFixedSizeArray n s a -> MFixedSizeArray n s a
basicUnsafeSlice = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> * -> *) a s.
MVector v a =>
Int -> Int -> v s a -> v s a
GM.basicUnsafeSlice @MVector @a
  basicOverlaps :: forall s. MFixedSizeArray n s a -> MFixedSizeArray n s a -> Bool
basicOverlaps    = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> * -> *) a s.
MVector v a =>
v s a -> v s a -> Bool
GM.basicOverlaps    @MVector @a
  basicUnsafeNew :: forall s. Int -> ST s (MFixedSizeArray n s a)
basicUnsafeNew   = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> * -> *) a s. MVector v a => Int -> ST s (v s a)
GM.basicUnsafeNew   @MVector @a
  basicInitialize :: forall s. MFixedSizeArray n s a -> ST s ()
basicInitialize  = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> * -> *) a s. MVector v a => v s a -> ST s ()
GM.basicInitialize  @MVector @a
  basicUnsafeRead :: forall s. MFixedSizeArray n s a -> Int -> ST s a
basicUnsafeRead  = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> * -> *) a s.
MVector v a =>
v s a -> Int -> ST s a
GM.basicUnsafeRead  @MVector @a
  basicUnsafeWrite :: forall s. MFixedSizeArray n s a -> Int -> a -> ST s ()
basicUnsafeWrite = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> * -> *) a s.
MVector v a =>
v s a -> Int -> a -> ST s ()
GM.basicUnsafeWrite @MVector @a

instance G.Vector (FixedSizeArray n) a where
  basicUnsafeFreeze :: forall s.
Mutable (FixedSizeArray n) s a -> ST s (FixedSizeArray n a)
basicUnsafeFreeze = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> *) a s. Vector v a => Mutable v s a -> ST s (v a)
G.basicUnsafeFreeze @Vector @a
  basicUnsafeThaw :: forall s.
FixedSizeArray n a -> ST s (Mutable (FixedSizeArray n) s a)
basicUnsafeThaw   = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> *) a s. Vector v a => v a -> ST s (Mutable v s a)
G.basicUnsafeThaw   @Vector @a
  basicLength :: FixedSizeArray n a -> Int
basicLength       = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> *) a. Vector v a => v a -> Int
G.basicLength       @Vector @a
  basicUnsafeSlice :: Int -> Int -> FixedSizeArray n a -> FixedSizeArray n a
basicUnsafeSlice  = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> *) a. Vector v a => Int -> Int -> v a -> v a
G.basicUnsafeSlice  @Vector @a
  basicUnsafeIndexM :: FixedSizeArray n a -> Int -> Box a
basicUnsafeIndexM = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ forall (v :: * -> *) a. Vector v a => v a -> Int -> Box a
G.basicUnsafeIndexM @Vector @a

{-------------------------------------------------------------------------------
  Construction
-------------------------------------------------------------------------------}

-- | Construct 'FixedSizeArray' from list of unknown size
--
-- Throws an exception if the list does not have the right number of elements.
fromList :: forall n a. KnownNat n => [a] -> FixedSizeArray n a
fromList :: forall (n :: Nat) a. KnownNat n => [a] -> FixedSizeArray n a
fromList = forall (n :: Nat) a. KnownNat n => Vector a -> FixedSizeArray n a
fromArray forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (v :: * -> *) a. Vector v a => [a] -> v a
G.fromList

-- | Construct 'FixedSizeArray' from array of unknown size
--
-- Throws an exception if the array does not have the right size.
fromArray :: forall n a. KnownNat n => Vector a -> FixedSizeArray n a
fromArray :: forall (n :: Nat) a. KnownNat n => Vector a -> FixedSizeArray n a
fromArray Vector a
v
  | forall (v :: * -> *) a. Vector v a => v a -> Int
G.length Vector a
v forall a. Eq a => a -> a -> Bool
== forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @n)) = forall (n :: Nat) a. Vector a -> FixedSizeArray n a
FromArray Vector a
v
  | Bool
otherwise = forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [
        String
"fromArray: invalid length. "
      , String
"expected " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @n))
      , String
", but got "
      , forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$ forall (v :: * -> *) a. Vector v a => v a -> Int
G.length Vector a
v
      ]

-- | Construct 'FixedSizeArray' from mutable array of unknown size
--
-- Throws an exception if the array does not have the right size.
fromMArray :: forall n s a. KnownNat n => MVector s a -> MFixedSizeArray n s a
fromMArray :: forall (n :: Nat) s a.
KnownNat n =>
MVector s a -> MFixedSizeArray n s a
fromMArray MVector s a
v
  | forall (v :: * -> * -> *) a s. MVector v a => v s a -> Int
GM.length MVector s a
v forall a. Eq a => a -> a -> Bool
== forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @n)) = forall (n :: Nat) s a. MVector s a -> MFixedSizeArray n s a
FromMArray MVector s a
v
  | Bool
otherwise = forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [
        String
"fromArray: invalid length. "
      , String
"expected " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @n))
      , String
", but got "
      , forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$ forall (v :: * -> * -> *) a s. MVector v a => v s a -> Int
GM.length MVector s a
v
      ]

-- | Construct new mutable array of the appropriate size
new :: forall m n a.
     (GM.PrimMonad m, KnownNat n)
  => m (MFixedSizeArray n (GM.PrimState m) a)
new :: forall (m :: * -> *) (n :: Nat) a.
(PrimMonad m, KnownNat n) =>
m (MFixedSizeArray n (PrimState m) a)
new = forall (n :: Nat) s a. MVector s a -> MFixedSizeArray n s a
FromMArray forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) (v :: * -> * -> *) a.
(HasCallStack, PrimMonad m, MVector v a) =>
Int -> m (v (PrimState m) a)
GM.new (forall a b. (Integral a, Num b) => a -> b
fromIntegral forall a b. (a -> b) -> a -> b
$ forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal (forall {k} (t :: k). Proxy t
Proxy @n))