Skip to content

Commit

Permalink
WIP: composeEither
Browse files Browse the repository at this point in the history
  • Loading branch information
raquo committed Feb 29, 2024
1 parent b1ef93f commit bfe46a9
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.raquo.airstream.compose

import com.raquo.airstream.common.{InternalTryObserver, SingleParentSignal}
import com.raquo.airstream.compose.ComposeEitherSignal.NoValueError
import com.raquo.airstream.core.{AirstreamError, Protected, Signal, Transaction, WritableSignal}
import com.raquo.ew.JsArray

import scala.util.Try

class ComposeEitherSignal[A, B, A2, B2](
parent: Signal[Either[A, B]],
makeLeftSignal: Signal[A] => Signal[A2],
makeRightSignal: Signal[B] => Signal[B2]
) extends WritableSignal[Either[A2, B2]] {

// #TODO
// We could make a FilteredSignal class that would just skip updates that don't match the predicate,
// and... avoid... initializing... the initial value, somehow
// >>> Or maybe we should just implement all this based on streams?

private val leftInputSignal: Signal[A] = parent.map(_.swap.getOrElse(throw new NoValueError))

private val rightInputSignal: Signal[B] = parent.map(_.getOrElse(throw new NoValueError))

private val leftOutputSignal: Signal[A2] = makeLeftSignal(leftInputSignal)

private val rightOutputSignal: Signal[B2] = makeRightSignal(rightInputSignal)

private val parents = JsArray(parent, leftOutputSignal, rightOutputSignal)

override protected val topoRank: Int = Protected.maxTopoRank(parents) + 1

// #TODO
// - leftInputSignal and rightInputSignal
// - Should be started when this signal is started... I think? Or not?
// - Add internal observers to them here
// - Note that output signals might in theory not depend on them...
// - Output
// - leftOutputSignal and rightOutputSignal should be merged, with logic similar to MergeEventStream
// - basically we add internal observers to them, and re-emit their updates
// - may need to filter out NoValueError?
// - Pulling value from parent
// - including initial value
// - look at parent.now(), if it's right(), get the value of rightOutputSignal, otherwise, get the value of leftOutputSignal
// - will that actually work? I'm not sure

// override protected def onTry(
// nextValue: Try[Either[A, B]],
// transaction: Transaction
// ): Unit = {
// nextValue.fold(
// nextErr => ???,
// nextEither => nextEither.fold(
// leftInput => leftInputSignal.emit(leftInput),
// rightInput => rightInputSignal.emit(rightInput),
// )
// )
// }

// private val metaSignal = parent.splitEither(
// (_, leftSignal) => makeLeftSignal(leftSignal).map(Right(_)),
// (_, rightSignal) => makeRightSignal(rightSignal).map(Left(_)),
// )

override protected def onWillStart(): Unit = {
// #TODO
???
}

override protected def currentValueFromParent(): Try[Either[A2, B2]] = {
???
}
}

object ComposeEitherSignal {

// #TODO Dunno about this. disable stack trace or something
class NoValueError() extends Throwable
}
12 changes: 12 additions & 0 deletions src/main/scala/com/raquo/airstream/extensions/EitherSignal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,16 @@ class EitherSignal[A, B](val signal: Signal[Either[A, B]]) extends AnyVal {
)
}

def composeEither[A2, B2](
left: Signal[A] => Signal[A2],
right: Signal[B] => Signal[B2]
): Signal[Either[A2, B2]] =
???

def composeFoldEither[C](
left: Signal[A] => Signal[C],
right: Signal[B] => Signal[C]
): Signal[C] =
composeEither(left, right).map(_.merge)

}
13 changes: 12 additions & 1 deletion src/main/scala/com/raquo/airstream/extensions/EitherStream.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.raquo.airstream.extensions

import com.raquo.airstream.core.{EventStream, Signal}
import com.raquo.airstream.core.{EventStream, Observable, Signal}
import com.raquo.airstream.split.SplittableOneStream

/** See also: [[EitherObservable]] */
Expand Down Expand Up @@ -50,4 +50,15 @@ class EitherStream[A, B](val stream: EventStream[Either[A, B]]) extends AnyVal {
)
}

def composeEither[A2, B2](
left: Signal[A] => Observable[A2],
right: Signal[B] => Observable[B2]
): EventStream[Either[A2, B2]] =
???

def composeFoldEither[C](
left: Signal[A] => Observable[C],
right: Signal[B] => Observable[C]
): EventStream[C] =
composeEither(left, right).map(_.merge)
}

0 comments on commit bfe46a9

Please sign in to comment.