{-# OPTIONS_GHC -Wno-unused-imports #-}

-- |
-- Module: Queries Tutorial
-- Description: How To Mischief.
--
-- [Previous Chapter: Keeping Track of Time]("Mischief.ECS.Tutorial.Guides.Time")
--
-- [Next Chapter: Events and Messages]("Mischief.ECS.Tutorial.Guides.Events")
--
-- [Main Page]("Mischief.ECS")
module Mischief.ECS.Tutorial.Guides.Parallelism
  ( -- * Learn You an ECS for Great Mischief! - 2.9. Parallelism and Asynchronicity
    -- $intro

    -- * The System Monads
    -- $monad

    -- * Running Systems in Parallel
    -- $par

    -- * Iterating in Parallel
    -- $parFor

    -- * Querying in Parallel
    -- $qpar

    -- * Asynchronicity
    -- $async

    -- * [Next Chapter: Events and Messages]("Mischief.ECS.Tutorial.Guides.Events")
  )
where

import Mischief.ECS

-- $intro
-- Mischief offers a few primitives for making systems run in parallel or asynchronously.

-- $monad
-- There is another monad that acts similary to @System@. It is called @ParSystem@, and
-- it doesn't allow for immediate mutations of the World.
--
-- Both @ParSystem@ and @System@ instance the @MonadSystem@ class, which you can use to write functions that work with both:
--
-- @
-- f :: (MonadSystem w m) => m ()
-- @
--
-- Functions such as @query@, @query_@, @single@ work with both monads, since they only read data.
--
-- Functions that mutate the world only work with @System@, requiring you to use @defer@ (see previous chapter) when used in @ParSystem@:
--
-- @
-- 'defer' $ 'insert' (Health 100) bob
-- @

-- $par
-- You can run a list of @ParSystems@ in parallel using the @par@ function:
--
-- @
-- par [foo, bar]
-- @

-- $parFor
-- You can iterate over Foldables in parallel using @parFor@:
--
-- @
-- names <- 'query' ['q'|Entity, Name|]
-- 'parFor' names $ \\(entity, Name name) -> do
--   'defer' $ 'insert' (Name $ name ++ \"2\") entity
-- @

-- $qpar
-- You can parallelize any @Query ParSystem a@ using @qpar@:
--
-- @
-- names <-
--   ['q'|Name / With Player|]
--   & 'qpar'
--   & 'query'
-- @

-- $async
-- Mischief has a couple of primitived that allow running systems asynchronously.
--
-- === runAfter
--
-- Asynchonicity in Mischief can be achieved using the @runAfter@ primtitive.
-- You provide it an 'IO' action that returns an @a@, and a system which consumes that @a@.
--
-- The 'IO' will be ran fully asychrnously and then will add the system to a special async-friendly deferred list that
-- will be applied at the first available sync point.
--
-- We can look at @delay@ as an example of how this may be useful:
--
-- @
-- 'delay' d system = 'runAfter' ('threadDelay' d) ('const' system)
-- @
--
-- Whcih allows delaying any system by an amount of time:
--
-- @
-- 'delay' 0.5 $ 'insert' (Health 100) player
-- @
--
-- === Repeaters
--
-- Repeaters are another way of running async systems.
--
-- A Repeater will run the given system at the given interval of time. This Repeater will
-- print \"Hello!\" once per second:
--
-- @
-- 'spawn_' 'Repeater'  1 ('info' \"Hello!\")
-- @
--
-- Repeaters can be despawned to stop them from running.