packages feed

mischief-ecs-0.2.0.0: src/Mischief/ECS/Components/Bundle.hs

{-# OPTIONS_GHC -Wno-redundant-constraints #-}

module Mischief.ECS.Components.Bundle where

import Data.Bifunctor qualified
import Data.Set qualified as Set
import Data.Typeable
import Mischief.ECS.Collectable (Collectable (collect))
import Mischief.ECS.Components

newtype ProcessedBundleData = ProcessedBundleData {elements :: [ProcessedBundleElement]}

data ProcessedBundleElement = ProcessedBundleElement {id :: ComponentId, component :: ErasedComponent}

addComponentToBundleData :: forall c. (Component c) => c -> BundleData ErasedComponent -> BundleData ErasedComponent
addComponentToBundleData !c (BundleData {elements = !elements, resources = !resources, external = !external}) =
  let !rep = ComponentRep $ ComponentType (Proxy @c)
      !component = ErasedComponent c
      !element = BundleElement {rep, component}
   in BundleData {elements = Set.union elements (Set.singleton element), resources, external}

instance Eq ProcessedBundleElement where
  (==) :: ProcessedBundleElement -> ProcessedBundleElement -> Bool
  (==) ProcessedBundleElement {id = !id1} ProcessedBundleElement {id = !id2} = id1 == id2

instance Ord ProcessedBundleElement where
  compare :: ProcessedBundleElement -> ProcessedBundleElement -> Ordering
  compare ProcessedBundleElement {id = !id1} ProcessedBundleElement {id = !id2} = compare id1 id2

type Bundle b = Collectable b (BundleData ErasedComponent)

bundleData :: (Bundle b) => b -> BundleData ErasedComponent
bundleData = collect

type BundleBuilder = BundleData ErasedComponent

bundle :: (Bundle b) => b -> BundleBuilder
bundle = collect

type BundleEqBuilder = BundleData ErasedComponentEq

bundleEq :: (BundleEq b) => b -> BundleEqBuilder
bundleEq = collect

type BundleEq b = Collectable b (BundleData ErasedComponentEq)

bundleDataEq :: (BundleEq b) => b -> BundleData ErasedComponentEq
bundleDataEq = collect

bundleEqToSimple :: BundleData ErasedComponentEq -> BundleData ErasedComponent
bundleEqToSimple BundleData {elements = !elements, resources = !resources, external = !external} =
  BundleData
    (Set.map (\BundleElement {rep, component = ErasedComponentEq (!a :: s)} -> BundleElement {rep, component = ErasedComponent a}) elements)
    (Set.map (\BundleElement {rep, component = ErasedComponentEq (!a :: s)} -> BundleElement {rep, component = ErasedComponent a}) resources)
    (Set.map (Data.Bifunctor.second bundleEqToSimple) external)