module TheatreDev.Terminal.StatefulActorSpec where

import TheatreDev.Prelude

data StatefulActorSpec message = forall state.
  StatefulActorSpec
  { ()
enter :: Concurrently state,
    ()
step :: state -> NonEmpty message -> Concurrently state,
    ()
exit :: state -> Concurrently ()
  }

instance Semigroup (StatefulActorSpec message) where
  StatefulActorSpec Concurrently state
leftEnter state -> NonEmpty message -> Concurrently state
leftStep state -> Concurrently ()
leftExit <> :: StatefulActorSpec message
-> StatefulActorSpec message -> StatefulActorSpec message
<> StatefulActorSpec Concurrently state
rightEnter state -> NonEmpty message -> Concurrently state
rightStep state -> Concurrently ()
rightExit =
    StatefulActorSpec
      { enter :: Concurrently (state, state)
enter =
          (,) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Concurrently state
leftEnter forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Concurrently state
rightEnter,
        step :: (state, state) -> NonEmpty message -> Concurrently (state, state)
step = \(state
leftState, state
rightState) NonEmpty message
messages ->
          (,)
            forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> state -> NonEmpty message -> Concurrently state
leftStep state
leftState NonEmpty message
messages
            forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> state -> NonEmpty message -> Concurrently state
rightStep state
rightState NonEmpty message
messages,
        exit :: (state, state) -> Concurrently ()
exit = \(state
leftState, state
rightState) ->
          state -> Concurrently ()
leftExit state
leftState forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> state -> Concurrently ()
rightExit state
rightState
      }

instance Monoid (StatefulActorSpec message) where
  mempty :: StatefulActorSpec message
mempty =
    StatefulActorSpec
      { enter :: Concurrently ()
enter = forall (f :: * -> *) a. Applicative f => a -> f a
pure (),
        step :: () -> NonEmpty message -> Concurrently ()
step = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure (),
        exit :: () -> Concurrently ()
exit = forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
      }

individual :: IO state -> (state -> message -> IO state) -> (state -> IO ()) -> StatefulActorSpec message
individual :: forall state message.
IO state
-> (state -> message -> IO state)
-> (state -> IO ())
-> StatefulActorSpec message
individual IO state
enter state -> message -> IO state
step state -> IO ()
exit =
  StatefulActorSpec
    { enter :: Concurrently state
enter = forall a. IO a -> Concurrently a
Concurrently IO state
enter,
      step :: state -> NonEmpty message -> Concurrently state
step = \state
state NonEmpty message
messages -> forall a. IO a -> Concurrently a
Concurrently (forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM state -> message -> IO state
step state
state NonEmpty message
messages),
      exit :: state -> Concurrently ()
exit = \state
state -> forall a. IO a -> Concurrently a
Concurrently (state -> IO ()
exit state
state)
    }