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

com.github.fbaierl.rxpuppeteer.RxPuppeteer.scala Maven / Gradle / Ivy

The newest version!
package com.github.fbaierl.rxpuppeteer

import com.github.fbaierl.tarjan.TarjanRecursive._
import rx.{Obs, Rx}

import scala.collection.mutable
import scala.language.{existentials, implicitConversions}

/**
  * Manages rx "dependencies".
  */
object RxPuppeteer {

  private var deps: List[(Rx[_], Rx[_])] = List()

  private def activate (x: Rx[_], y: Rx[_], condition: () => Boolean, runBefore: () => Unit, runAfter: () => Unit,
                        triggerLater: Boolean)(implicit ownerCtx : rx.Ctx.Owner): Obs = {
    def func: () => Unit = () => {
      runBefore()
      if(condition()){ y.recalc() }
      runAfter()
    }
    if(triggerLater){
      x.triggerLater {
        func()
      }
    } else {
      x.trigger {
        func()
      }
    }
  }

  private def cyclic: List[(Rx[_], Rx[_])] => Boolean = ds => {
    var eles = mutable.MutableList.empty[Rx[_]]
    ds.foreach { d =>
      if(!eles.contains(d._1)){
        eles += d._1
      }
      if(!eles.contains(d._2)){
        eles += d._2
      }
    }
    // input format needed for tarjan
    val tarjanInput = mutable.Map.empty[Int, List[Int]]
    eles.foreach { el =>
      tarjanInput.put(eles.indexOf(el), ds.filter(p => p._1 == el).map(p => eles.indexOf(p._2)))
    }
    tarjan(collection.immutable.Map(tarjanInput.toList: _*)).exists(partition => partition.size > 1)
  }

  /**
    * Activates a rx dependency x => y, which is the same as writing:
    * {{{
    * x.triggerLater { y.recalc() }
    * }}}, but only if this does not add a cyclic or duplicate relationship to the previously activated rx dependencies.
    */
  def add (x: Rx[_], y: Rx[_], condition: () => Boolean, runBefore: () => Unit, runAfter: () => Unit,
           triggerLater: Boolean)(implicit ownerCtx : rx.Ctx.Owner): Obs = {
    val newList: List[(Rx[_], Rx[_])] = (x,y) :: deps
    if(cyclic(newList) || x == y){
      throw RxDependencyException(
        s"""Unable to add rx dependency:
            | $x --> $y
            | Reason: Dependency would introduce a cyclic relationship!""".stripMargin)
    }
    if(deps.contains((x,y))){
      throw RxDependencyException(
        s"""Did not add rx dependency:
           | $x --> $y
           | Reason: Dependency already activated!""".stripMargin)
    } else {
      deps = newList
      activate(x, y, condition, runBefore, runAfter, triggerLater)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy