Skip to content

Commit

Permalink
add new resetFold
Browse files Browse the repository at this point in the history
  • Loading branch information
Bob Reynders authored and Bob Reynders committed Feb 8, 2018
1 parent 896ae22 commit 276efe1
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 37 deletions.
5 changes: 3 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ resolvers += "Sonatype OSS Snapshots" at
"https://oss.sonatype.org/content/repositories/snapshots"

organization in ThisBuild := "be.tzbob"
scalaVersion in ThisBuild := "2.12.1"
scalaVersion in ThisBuild := "2.12.4"
crossScalaVersions in ThisBuild := Seq("2.11.8", "2.12.1")
version in ThisBuild := "0.4.4-SNAPSHOT"
version in ThisBuild := "0.4.5-SNAPSHOT"
isSnapshot in ThisBuild := true

scalacOptions in ThisBuild ++= Seq(
"-encoding",
Expand Down
33 changes: 25 additions & 8 deletions core/jvm/src/test/scala/hokko/core/IBehaviorTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -36,25 +36,42 @@ class IBehaviorTest extends FunSuite with FRPSuite with Checkers {
test("IBehaviors incrementally map 2") {}

test("IBehaviors can be reset without producing pulses") {
val init = 5

val source = Event.source[Int]
val resetter = Event.source[Int]
val const = IBehavior.constant(5)
val resetted = const.resetState(resetter)

val reset = source.resetFold(resetter)(init)(_ + _)

check { (ints: List[Int]) =>
val cBehavior = resetted.toCBehavior
val cBehavior = reset.toCBehavior

val initAfterReset = (init :: ints).last
val totalSum = (initAfterReset :: ints).sum

val occs =
mkOccurrencesWithDependencies(resetted.changes)(cBehavior) {
mkOccurrencesWithDependencies(reset.changes)(cBehavior) {
implicit
engine =>
// Tests resetting value
fireAll(resetter, ints)
val currentValues = engine.askCurrentValues()
val value = currentValues(cBehavior)
println(value)
value.get === (5 :: ints).last
val resetResult = currentValues(cBehavior)

val isValueReset = resetResult.get === initAfterReset

// Tests if fold starts from reset value
fireAll(source, ints)
val foldAfterResetResult = engine.askCurrentValues()(cBehavior)

val doesFoldStartFromReset = resetResult.get === totalSum

isValueReset && doesFoldStartFromReset
}

occs === List()

val changes = ints.scan(initAfterReset)(_ + _).drop(1)
occs === changes
}
}
}
10 changes: 7 additions & 3 deletions core/shared/src/main/scala/hokko/core/Event.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import hokko.syntax.EventSyntax

sealed trait Event[+A] extends Primitive[A] {
override private[core] val node: Push[A]

def resetFold[B](resetter: Event[B])(init: B)(
f: (B, A) => B): IBehavior[B, A] =
IBehavior.resetFolded(this, resetter, init, f)
}

final class EventSource[+A](private[core] val node: Push[A]) extends Event[A]
Expand Down Expand Up @@ -40,9 +44,9 @@ object Event extends EventSyntax[Event, IBehavior] with FunctorSyntax {
def source[A]: EventSource[A] = new EventSource[A](empty[A].node)

def merge[A](events: Seq[Event[A]]): Event[Seq[A]] = events match {
case Seq() => empty
case Seq(x) => x.map(Seq(_))
case Seq(x, xs @ _ *) => x.mergeWith(xs: _*)
case Seq() => empty
case Seq(x) => x.map(Seq(_))
case Seq(x, xs @ _*) => x.mergeWith(xs: _*)
}

// primitive node implementations
Expand Down
47 changes: 23 additions & 24 deletions core/shared/src/main/scala/hokko/core/IBehavior.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ trait IBehavior[+A, +DeltaA] extends Primitive[A] {
}

def toCBehavior[AA >: A]: CBehavior[AA] = toDBehavior.toCBehavior

def resetState[AA >: A](resetter: Event[AA]): IBehavior[AA, DeltaA] =
IBehavior.reset(resetter, this)

}

object IBehavior
Expand All @@ -83,7 +79,7 @@ object IBehavior
private[core] def folded[A, DeltaA](foldee: Event[DeltaA],
init: A,
f: (A, DeltaA) => A) = {
val foldNode = FoldNode(foldee, init, f)
val foldNode = new FoldNode(foldee, init, f)
new IBehavior[A, DeltaA] {
val initial = init
val node: Pull[A] = foldNode
Expand All @@ -92,12 +88,12 @@ object IBehavior
}
}

private case class FoldNode[A, DeltaA](
private class FoldNode[A, DeltaA](
ev: Event[DeltaA],
init: A,
f: (A, DeltaA) => A
) extends DBehavior.PullStatePush[A] {
val dependencies = List(ev.node)
val dependencies: List[Node[_]] = List(ev.node)
def pulse(context: TickContext): Option[A] = {
val evPulse = context.getPulse(ev.node)
evPulse.map { pulse =>
Expand All @@ -109,27 +105,30 @@ object IBehavior
Thunk.eager(c.getPulse(this).orElse(c.getState(this)).getOrElse(init))
}

private def reset[A, DeltaA](ev: Event[A], ib: IBehavior[A, DeltaA]) =
private[core] def resetFolded[A, DeltaA](foldee: Event[DeltaA],
resetter: Event[A],
init: A,
f: (A, DeltaA) => A) = {
val foldNode = ResetFoldNode(foldee, resetter, init, f)
new IBehavior[A, DeltaA] {
val initial: A = ib.initial
override private[core] val node = new ResetNode(ev, ib)
def changes = ib.changes
def deltas = ib.deltas
val initial = init
val node: Pull[A] = foldNode
val changes: Event[A] = Event.fromNode(foldNode)
val deltas: Event[DeltaA] = foldee
}
}

private case class ResetNode[A, DeltaA](
ev: Event[A],
ib: IBehavior[A, DeltaA]
) extends DBehavior.PullStatePush[A] {
val dependencies = List(ev.node, ib.node)
private case class ResetFoldNode[A, DeltaA](
ev: Event[DeltaA],
resetter: Event[A],
init: A,
f: (A, DeltaA) => A
) extends FoldNode[A, DeltaA](ev, init, f) {
override val dependencies = List(ev.node, resetter.node)

// If the resetter produces a pulse, reset the state to that pulse
override def state(context: TickContext): Option[A] =
context.getPulse(ev.node)

def pulse(context: TickContext): Option[A] =
context.getPulse(ib.changes.node)

def thunk(c: TickContext): Thunk[A] =
c.getPulse(ev.node).map(Thunk.eager).orElse(c.getThunk(ib.node)).get
context.getPulse(resetter.node).orElse(super.state(context))
}

}

0 comments on commit 276efe1

Please sign in to comment.