packages feed

aztecs-0.13.0: src/Aztecs/ECS/Access/Internal.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

module Aztecs.ECS.Access.Internal where

import Aztecs.ECS.HSet
import Aztecs.ECS.Query
import Aztecs.ECS.Queryable
import Aztecs.ECS.Queryable.Internal
import Aztecs.ECS.World
import Control.Monad.Primitive
import Data.Kind
import GHC.Generics

type family ValidAccessInput (accesses :: [Type]) :: Constraint where
  ValidAccessInput accesses =
    ( ValidAccess accesses,
      NoOverlappingWrites accesses
    )

type family NoOverlappingWrites (accesses :: [Type]) :: Constraint where
  NoOverlappingWrites accesses =
    (HasDuplicateWrites (WriteComponents accesses) ~ 'False)

type family HasDuplicateWrites (components :: [Type]) :: Bool where
  HasDuplicateWrites '[] = 'False
  HasDuplicateWrites (c ': rest) = Or (Contains c rest) (HasDuplicateWrites rest)

class (PrimMonad m) => Access cs m a where
  type AccessType a :: [Type]
  access ::
    ( Subset (AccessToComponents (AccessType a)) cs,
      ValidAccessInput (AccessType a)
    ) =>
    World m cs ->
    a
  default access ::
    ( Generic a,
      GenericAccess cs m (Rep a),
      Subset (AccessToComponents (GenericAccessType (Rep a))) cs,
      ValidAccessInput (GenericAccessType (Rep a)),
      AccessType a ~ GenericAccessType (Rep a)
    ) =>
    World m cs ->
    a
  access = deriveAccess
  {-# INLINE access #-}

class GenericAccess cs m f where
  type GenericAccessType f :: [Type]
  genericAccess ::
    ( Subset (AccessToComponents (GenericAccessType f)) cs,
      ValidAccessInput (GenericAccessType f)
    ) =>
    World m cs ->
    f p

instance GenericAccess cs m U1 where
  type GenericAccessType U1 = '[]
  genericAccess _ = U1
  {-# INLINE genericAccess #-}

instance (Access cs m c) => GenericAccess cs m (K1 i c) where
  type GenericAccessType (K1 i c) = AccessType c
  genericAccess world = K1 (access world)
  {-# INLINE genericAccess #-}

instance (GenericAccess cs m f) => GenericAccess cs m (M1 i c f) where
  type GenericAccessType (M1 i c f) = GenericAccessType f
  genericAccess world = M1 (genericAccess world)
  {-# INLINE genericAccess #-}

instance
  ( GenericAccess cs m f,
    GenericAccess cs m g,
    Subset (AccessToComponents (GenericAccessType f)) cs,
    ValidAccessInput (GenericAccessType f),
    Subset (AccessToComponents (GenericAccessType g)) cs,
    ValidAccessInput (GenericAccessType g)
  ) =>
  GenericAccess cs m (f :*: g)
  where
  type GenericAccessType (f :*: g) = GenericAccessType f ++ GenericAccessType g
  genericAccess world = genericAccess world :*: genericAccess world
  {-# INLINE genericAccess #-}

instance (PrimMonad m, Queryable cs m a) => Access cs m (Query m a) where
  type AccessType (Query m a) = QueryableAccess a
  access = query
  {-# INLINE access #-}

instance (PrimMonad m) => Access cs m () where
  type AccessType () = '[]
  access _ = ()
  {-# INLINE access #-}

deriveAccess ::
  forall a m cs.
  ( Generic a,
    GenericAccess cs m (Rep a),
    Subset (AccessToComponents (GenericAccessType (Rep a))) cs,
    ValidAccessInput (GenericAccessType (Rep a))
  ) =>
  World m cs ->
  a
deriveAccess world = to (genericAccess world)
{-# INLINE deriveAccess #-}

type family DeriveAccessType (rep :: Type -> Type) :: [Type] where
  DeriveAccessType rep = GenericAccessType rep

instance
  ( Access cs m a,
    Access cs m b,
    ValidAccessInput (AccessType a),
    ValidAccessInput (AccessType b),
    Subset (AccessToComponents (AccessType a)) cs,
    Subset (AccessToComponents (AccessType b)) cs
  ) =>
  Access cs m (a, b)
  where
  type AccessType (a, b) = AccessType a ++ AccessType b

instance
  ( Access cs m a,
    Access cs m b,
    Access cs m c,
    ValidAccessInput (AccessType a),
    ValidAccessInput (AccessType b),
    ValidAccessInput (AccessType c),
    ValidAccessInput (AccessType b ++ AccessType c),
    Subset (AccessToComponents (AccessType a)) cs,
    Subset (AccessToComponents (AccessType b)) cs,
    Subset (AccessToComponents (AccessType c)) cs,
    Subset (AccessToComponents (AccessType b ++ AccessType c)) cs,
    Subset (AccessToComponents (AccessType a ++ (AccessType b ++ AccessType c))) cs
  ) =>
  Access cs m (a, b, c)
  where
  type AccessType (a, b, c) = AccessType a ++ (AccessType b ++ AccessType c)

instance
  ( Access cs m a,
    Access cs m b,
    Access cs m c,
    Access cs m d,
    ValidAccessInput (AccessType a),
    ValidAccessInput (AccessType b),
    ValidAccessInput (AccessType c),
    ValidAccessInput (AccessType d),
    ValidAccessInput (AccessType a ++ AccessType b),
    ValidAccessInput (AccessType c ++ AccessType d),
    Subset (AccessToComponents (AccessType a)) cs,
    Subset (AccessToComponents (AccessType b)) cs,
    Subset (AccessToComponents (AccessType c)) cs,
    Subset (AccessToComponents (AccessType d)) cs,
    Subset (AccessToComponents (AccessType a ++ AccessType b)) cs,
    Subset (AccessToComponents (AccessType c ++ AccessType d)) cs
  ) =>
  Access cs m (a, b, c, d)
  where
  type
    AccessType (a, b, c, d) =
      ((AccessType a ++ AccessType b) ++ (AccessType c ++ AccessType d))

instance
  ( Access cs m a,
    Access cs m b,
    Access cs m c,
    Access cs m d,
    Access cs m e,
    ValidAccessInput (AccessType a),
    ValidAccessInput (AccessType b),
    ValidAccessInput (AccessType c),
    ValidAccessInput (AccessType d),
    ValidAccessInput (AccessType e),
    ValidAccessInput (AccessType a ++ AccessType b),
    ValidAccessInput ((AccessType c ++ (AccessType d ++ AccessType e))),
    ValidAccessInput (AccessType d ++ AccessType e),
    Subset (AccessToComponents (AccessType a)) cs,
    Subset (AccessToComponents (AccessType b)) cs,
    Subset (AccessToComponents (AccessType c)) cs,
    Subset (AccessToComponents (AccessType d)) cs,
    Subset (AccessToComponents (AccessType e)) cs,
    Subset (AccessToComponents (AccessType a ++ AccessType b)) cs,
    Subset
      (AccessToComponents (AccessType d ++ AccessType e))
      cs,
    Subset
      ( AccessToComponents
          (AccessType c ++ (AccessType d ++ AccessType e))
      )
      cs,
    Subset
      ( AccessToComponents
          ( ( (AccessType a ++ AccessType b)
                ++ (AccessType c ++ (AccessType d ++ AccessType e))
            )
          )
      )
      cs
  ) =>
  Access cs m (a, b, c, d, e)
  where
  type
    AccessType (a, b, c, d, e) =
      ( (AccessType a ++ AccessType b)
          ++ (AccessType c ++ (AccessType d ++ AccessType e))
      )

instance
  ( Access cs m a,
    Access cs m b,
    Access cs m c,
    Access cs m d,
    Access cs m e,
    Access cs m f,
    ValidAccessInput (AccessType a),
    ValidAccessInput (AccessType b),
    ValidAccessInput (AccessType c),
    ValidAccessInput (AccessType d),
    ValidAccessInput (AccessType e),
    ValidAccessInput (AccessType f),
    ValidAccessInput (AccessType e ++ AccessType f),
    ValidAccessInput (AccessType d ++ (AccessType e ++ AccessType f)),
    ValidAccessInput (AccessType a ++ (AccessType b ++ AccessType c)),
    ValidAccessInput (AccessType b ++ AccessType c),
    Subset (AccessToComponents (AccessType a)) cs,
    Subset (AccessToComponents (AccessType b)) cs,
    Subset (AccessToComponents (AccessType c)) cs,
    Subset (AccessToComponents (AccessType d)) cs,
    Subset (AccessToComponents (AccessType e)) cs,
    Subset (AccessToComponents (AccessType f)) cs,
    Subset (AccessToComponents (AccessType b ++ AccessType c)) cs,
    Subset (AccessToComponents (AccessType e ++ AccessType f)) cs,
    Subset
      ( AccessToComponents
          (AccessType a ++ (AccessType b ++ AccessType c))
      )
      cs,
    Subset
      ( AccessToComponents
          (AccessType d ++ (AccessType e ++ AccessType f))
      )
      cs
  ) =>
  Access cs m (a, b, c, d, e, f)
  where
  type
    AccessType (a, b, c, d, e, f) =
      ( (AccessType a ++ (AccessType b ++ AccessType c))
          ++ (AccessType d ++ (AccessType e ++ AccessType f))
      )

instance
  ( Access cs m a,
    Access cs m b,
    Access cs m c,
    Access cs m d,
    Access cs m e,
    Access cs m f,
    Access cs m g,
    ValidAccessInput (AccessType a),
    ValidAccessInput (AccessType b),
    ValidAccessInput (AccessType c),
    ValidAccessInput (AccessType d),
    ValidAccessInput (AccessType e),
    ValidAccessInput (AccessType f),
    ValidAccessInput (AccessType g),
    ValidAccessInput (AccessType b ++ AccessType c),
    ValidAccessInput (AccessType d ++ AccessType e),
    ValidAccessInput (AccessType f ++ AccessType g),
    ValidAccessInput (AccessType a ++ (AccessType b ++ AccessType c)),
    ValidAccessInput ((AccessType d ++ AccessType e) ++ (AccessType f ++ AccessType g)),
    Subset (AccessToComponents (AccessType a)) cs,
    Subset (AccessToComponents (AccessType b)) cs,
    Subset (AccessToComponents (AccessType c)) cs,
    Subset (AccessToComponents (AccessType d)) cs,
    Subset (AccessToComponents (AccessType e)) cs,
    Subset (AccessToComponents (AccessType f)) cs,
    Subset (AccessToComponents (AccessType g)) cs,
    Subset (AccessToComponents (AccessType b ++ AccessType c)) cs,
    Subset (AccessToComponents (AccessType d ++ AccessType e)) cs,
    Subset (AccessToComponents (AccessType f ++ AccessType g)) cs,
    Subset
      ( AccessToComponents
          (AccessType a ++ (AccessType b ++ AccessType c))
      )
      cs,
    Subset
      ( AccessToComponents
          ((AccessType d ++ AccessType e) ++ (AccessType f ++ AccessType g))
      )
      cs
  ) =>
  Access cs m (a, b, c, d, e, f, g)
  where
  type
    AccessType (a, b, c, d, e, f, g) =
      ( (AccessType a ++ (AccessType b ++ AccessType c))
          ++ ((AccessType d ++ AccessType e) ++ (AccessType f ++ AccessType g))
      )

instance
  ( Access cs m a,
    Access cs m b,
    Access cs m c,
    Access cs m d,
    Access cs m e,
    Access cs m f,
    Access cs m g,
    Access cs m h,
    ValidAccessInput (AccessType a),
    ValidAccessInput (AccessType b),
    ValidAccessInput (AccessType c),
    ValidAccessInput (AccessType d),
    ValidAccessInput (AccessType e),
    ValidAccessInput (AccessType f),
    ValidAccessInput (AccessType g),
    ValidAccessInput (AccessType h),
    ValidAccessInput (AccessType a ++ AccessType b),
    ValidAccessInput (AccessType c ++ AccessType d),
    ValidAccessInput (AccessType e ++ AccessType f),
    ValidAccessInput (AccessType g ++ AccessType h),
    ValidAccessInput ((AccessType a ++ AccessType b) ++ (AccessType c ++ AccessType d)),
    ValidAccessInput ((AccessType e ++ AccessType f) ++ (AccessType g ++ AccessType h)),
    Subset (AccessToComponents (AccessType a)) cs,
    Subset (AccessToComponents (AccessType b)) cs,
    Subset (AccessToComponents (AccessType c)) cs,
    Subset (AccessToComponents (AccessType d)) cs,
    Subset (AccessToComponents (AccessType e)) cs,
    Subset (AccessToComponents (AccessType f)) cs,
    Subset (AccessToComponents (AccessType g)) cs,
    Subset (AccessToComponents (AccessType h)) cs,
    Subset (AccessToComponents (AccessType a ++ AccessType b)) cs,
    Subset (AccessToComponents (AccessType c ++ AccessType d)) cs,
    Subset (AccessToComponents (AccessType e ++ AccessType f)) cs,
    Subset (AccessToComponents (AccessType g ++ AccessType h)) cs,
    Subset
      ( AccessToComponents
          ((AccessType a ++ AccessType b) ++ (AccessType c ++ AccessType d))
      )
      cs,
    Subset
      ( AccessToComponents
          ((AccessType e ++ AccessType f) ++ (AccessType g ++ AccessType h))
      )
      cs
  ) =>
  Access cs m (a, b, c, d, e, f, g, h)
  where
  type
    AccessType (a, b, c, d, e, f, g, h) =
      ( ((AccessType a ++ AccessType b) ++ (AccessType c ++ AccessType d))
          ++ ((AccessType e ++ AccessType f) ++ (AccessType g ++ AccessType h))
      )