keid-frp-banana-0.1.0.0: src/Engine/ReactiveBanana/Course.hs
{-# LANGUAGE RecursiveDo #-}
module Engine.ReactiveBanana.Course
( Course(..)
, setup
, whenIdle
, whenActive
, whenFinished
, isIdle
, isActive
, isFinished
, when
, unless
) where
import RIO hiding (when, unless)
import Data.Maybe (fromJust)
import Data.These (These(..))
import Reactive.Banana qualified as RB
import Reactive.Banana.Frameworks qualified as RBF
data Course a
= Idle
| Active a
| Finished
deriving (Eq, Ord, Show, Functor)
setup
:: RB.Event a
-> RB.Event (a -> Either final a)
-> RBF.MomentIO (RB.Event a, RB.Event final, RB.Behavior (Course a))
setup triggerE stepE = mdo
(e, b) <- RB.mapAccum Idle $
fmap dispatch $
RB.merge triggerE (whenActive b stepE)
(activeE, fireActive) <- RBF.newEvent
RBF.reactimate $ (e RB.@> b) <&> \case
Active a ->
fireActive a
_ ->
pure ()
finishedE <- RB.once $
fmap fromJust $ RB.filterE isJust e
pure (activeE, finishedE, b)
where
dispatch = \case
This initial -> \case
Idle ->
(Nothing, Active initial)
Active{} ->
error "trigger not filtered when active"
Finished ->
error "trigger not filtered when finished"
That step -> \case
Idle ->
error "tick not filtered when idle"
Active current ->
case step current of
Left done ->
(Just done, Finished)
Right next ->
(Nothing, Active next)
Finished ->
error "tick not filtered when finished"
These{} ->
error "tick happened on top of trigger"
when :: (Course a -> Bool) -> RB.Behavior (Course a) -> RB.Event e -> RB.Event e
when pred course =
RB.filterApply (course <&> const . pred)
unless :: (Course a -> Bool) -> RB.Behavior (Course a) -> RB.Event e -> RB.Event e
unless pred course =
RB.filterApply (course <&> const . not . pred)
whenIdle :: RB.Behavior (Course a) -> RB.Event e -> RB.Event e
whenIdle = when isIdle
whenActive :: RB.Behavior (Course a) -> RB.Event e -> RB.Event e
whenActive = when isActive
whenFinished :: RB.Behavior (Course a) -> RB.Event e -> RB.Event e
whenFinished = when isFinished
isIdle :: Course a -> Bool
isIdle = \case
Idle -> True
_ -> False
isActive :: Course a -> Bool
isActive = \case
Active{} -> True
_ -> False
isFinished :: Course a -> Bool
isFinished = \case
Finished -> True
_ -> False