packages feed

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

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

module Aztecs.ECS.Access.Internal where

import Aztecs.ECS.Class
import Aztecs.ECS.Query
import Aztecs.ECS.Query.Class
import Aztecs.ECS.Query.Internal
import Data.Kind
import GHC.Generics

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

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

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

class GenericAccess m f where
  type GenericAccessType f :: [Type]
  genericAccess :: (ValidAccessInput (GenericAccessType f)) => m (f p)

instance (Applicative m) => GenericAccess m U1 where
  type GenericAccessType U1 = '[]
  genericAccess = pure U1
  {-# INLINE genericAccess #-}

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

instance (Functor m, GenericAccess m f) => GenericAccess m (M1 i c f) where
  type GenericAccessType (M1 i c f) = GenericAccessType f
  genericAccess = M1 <$> genericAccess
  {-# INLINE genericAccess #-}

instance
  ( Applicative m,
    GenericAccess m f,
    GenericAccess m g,
    ValidAccessInput (GenericAccessType f),
    ValidAccessInput (GenericAccessType g)
  ) =>
  GenericAccess m (f :*: g)
  where
  type GenericAccessType (f :*: g) = GenericAccessType f ++ GenericAccessType g
  genericAccess = (:*:) <$> genericAccess <*> genericAccess
  {-# INLINE genericAccess #-}

instance (ECS m, Applicative m, Queryable m a) => Access m (Query a) where
  type AccessType (Query a) = QueryableAccess a
  access = queryable
  {-# INLINE access #-}

instance (Applicative m) => Access m () where
  type AccessType () = '[]
  access = pure ()
  {-# INLINE access #-}

deriveAccess ::
  forall a m cs.
  ( Functor m,
    Generic a,
    GenericAccess m (Rep a),
    ValidAccessInput (GenericAccessType (Rep a))
  ) =>
  m a
deriveAccess = to <$> genericAccess
{-# INLINE deriveAccess #-}

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

instance
  ( Applicative m,
    Access m a,
    Access m b,
    ValidAccessInput (AccessType a),
    ValidAccessInput (AccessType b),
    ValidAccessInput (AccessType a ++ AccessType b)
  ) =>
  Access m (a, b)
  where
  type AccessType (a, b) = AccessType a ++ AccessType b

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

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

instance
  ( Applicative m,
    Access m a,
    Access m b,
    Access m c,
    Access m d,
    Access 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),
    ValidAccessInput
      ( (AccessType a ++ AccessType b)
          ++ (AccessType c ++ (AccessType d ++ AccessType e))
      )
  ) =>
  Access 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
  ( Applicative m,
    Access m a,
    Access m b,
    Access m c,
    Access m d,
    Access m e,
    Access 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),
    ValidAccessInput
      ( (AccessType a ++ (AccessType b ++ AccessType c))
          ++ (AccessType d ++ (AccessType e ++ AccessType f))
      )
  ) =>
  Access 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
  ( Applicative m,
    Access m a,
    Access m b,
    Access m c,
    Access m d,
    Access m e,
    Access m f,
    Access 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)),
    ValidAccessInput
      ( (AccessType a ++ (AccessType b ++ AccessType c))
          ++ ((AccessType d ++ AccessType e) ++ (AccessType f ++ AccessType g))
      )
  ) =>
  Access 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
  ( Applicative m,
    Access m a,
    Access m b,
    Access m c,
    Access m d,
    Access m e,
    Access m f,
    Access m g,
    Access 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)),
    ValidAccessInput
      ( ((AccessType a ++ AccessType b) ++ (AccessType c ++ AccessType d))
          ++ ((AccessType e ++ AccessType f) ++ (AccessType g ++ AccessType h))
      )
  ) =>
  Access 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))
      )