All Downloads are FREE. Search and download functionalities are using the official Maven repository.

indigo.shared.temporal.SignalState.scala Maven / Gradle / Ivy

The newest version!
package indigo.shared.temporal

import indigo.shared.time.Seconds

/** `SignalState` is a type of `Signal` that carries transformable state values throughout it's life.
  */
opaque type SignalState[S, A] = S => Signal[(S, A)]

object SignalState {

  def fromSignal[S, A](signal: Signal[A]): SignalState[S, A] =
    apply((s: S) => signal.map(a => (s, a)))

  def fixed[S, A](a: A): SignalState[S, A] =
    apply((s: S) => Signal.fixed((s, a)))

  inline def apply[S, A](f: S => Signal[(S, A)]): SignalState[S, A] = f

  extension [S, A](ss: SignalState[S, A])
    def run: S => Signal[(S, A)] = ss

    def toSignal(state: S): Signal[A] =
      ss(state).map(_._2)

    def modify(f: S => S): SignalState[S, Unit] =
      SignalState { (s: S) =>
        ss(s).map(p => (f(p._1), ()))
      }

    def get: SignalState[S, S] =
      SignalState { (s: S) =>
        ss(s).map(p => (p._1, p._1))
      }

    def set(newState: S): SignalState[S, Unit] =
      SignalState { (s: S) =>
        ss(s).map(_ => (newState, ()))
      }

    def merge[B, C](other: SignalState[S, B])(f: (A, B) => C): SignalState[S, C] =
      for {
        a <- ss
        b <- other
      } yield f(a, b)

    def |>[B](sf: SignalFunction[A, B]): SignalState[S, B] =
      pipe(sf)
    def pipe[B](sf: SignalFunction[A, B]): SignalState[S, B] =
      SignalState { (s: S) =>
        val sig = ss(s)
        sf.run(sig.map(_._2)).flatMap(b => sig.map(_ => (s, b)))
      }

    def |*|[B](other: SignalState[S, B]): SignalState[S, (A, B)] =
      combine(other)
    def combine[B](other: SignalState[S, B]): SignalState[S, (A, B)] =
      for {
        a <- ss
        b <- other
      } yield (a, b)

    def clampTime(from: Seconds, to: Seconds): SignalState[S, A] =
      SignalState((s: S) => ss(s).clampTime(from, to))
    def wrapTime(at: Seconds): SignalState[S, A] =
      SignalState((s: S) => ss(s).wrapTime(at))
    def affectTime(multiplyBy: Double): SignalState[S, A] =
      SignalState((s: S) => ss(s).affectTime(multiplyBy))

    def map[B](f: A => B): SignalState[S, B] =
      SignalState { (s: S) =>
        ss(s).map { case (s, a) => (s, f(a)) }
      }

    def ap[B](f: SignalState[S, A => B]): SignalState[S, B] =
      SignalState { (s: S) =>
        ss(s).flatMap { case (nextState, a) =>
          f(nextState).map { case (finalState, g) =>
            (finalState, g(a))
          }
        }
      }

    def flatMap[B](f: A => SignalState[S, B]): SignalState[S, B] =
      SignalState { (s: S) =>
        ss(s).flatMap { case (ss, aa) => f(aa)(ss) }
      }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy