Created
January 18, 2024 22:01
-
-
Save arturaz/d29f622fcb7ae3c4303d8f3bd667e49b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package app.webclient_prelude.utils | |
import com.raquo.airstream.core.Signal | |
import com.raquo.airstream.split.SplittableSignal | |
import com.raquo.airstream.state.Var | |
/** Like [[Var.zoom]] but is not required to have an [[com.raquo.airstream.ownership.Owner]]. */ | |
trait UpdatableSignal[A] { self => | |
/** The [[Signal]] which is most likely mapped from a [[Var]]. */ | |
def signal: Signal[A] | |
/** Performs the modification on the underlying data source so that [[signal]] value changes. | |
*/ | |
def update: UpdatableSignal.UpdateFn[A] | |
/** Returns a new [[UpdatableSignal]] which is mapped. | |
* | |
* Example: | |
* {{{ | |
* lineItem.bimap(_.name)((item, value) => item.copy(name = value)) | |
* }}} | |
*/ | |
def bimap[PartOfA]( | |
get: A => PartOfA | |
)(set: UpdatableSignal.Setter[A, PartOfA]): UpdatableSignal[PartOfA] = | |
UpdatableSignal[PartOfA]( | |
signal.map(get), | |
updatePartOfA => | |
self.update { a => | |
val partOfA = get(a) | |
set(a, updatePartOfA(partOfA)) | |
}, | |
) | |
/** Returns a new [[UpdatableSignal]] which is constructed from a [[Signal]] (obtained via one of the | |
* [[SplittableSignal.split]] methods) and an update function. | |
* | |
* Example: | |
* {{{ | |
* val lineItems: UpdatableSignal[NonEmptyVector[LineItem]] = ??? | |
* | |
* div( | |
* children <-- lineItems.signal.splitByIndex((idx, _, signal) => | |
* LineItem( | |
* lineItems.bimapFromSplit(signal)(_.updatedWith(idx, _)), | |
* ) | |
* ) | |
* ) | |
* }}} | |
* | |
* @param signal | |
* the [[Signal]] that represents a part of [[A]], usually obtained via one of the `split` methods. | |
* @param update | |
* the function that updates the underlying data source. The first argument is the current value of | |
* [[self.signal]], the second argument is a function that updates the given part of [[A]]. | |
*/ | |
def bimapFromSplit[PartOfA](signal: Signal[PartOfA])( | |
update: UpdatableSignal.Updater[A, PartOfA] | |
): UpdatableSignal[PartOfA] = UpdatableSignal[PartOfA]( | |
signal, | |
updateB => self.update(a => update(a, updateB)), | |
) | |
} | |
object UpdatableSignal { | |
/** Receives a value and returns the modified value. */ | |
// noinspection ScalaWeakerAccess | |
type UpdateFn[A] = (A => A) => Unit | |
/** Receives a value as the first argument and an update function as the second argument. | |
* | |
* The update function receives a part of the value and returns the updated part. | |
* | |
* @return | |
* the modified value. | |
*/ | |
// noinspection ScalaWeakerAccess | |
type Updater[A, PartOfA] = (A, PartOfA => PartOfA) => A | |
/** Sets [[PartOfA]] in [[A]] and returns the modified [[A]]. */ | |
// noinspection ScalaWeakerAccess | |
type Setter[A, PartOfA] = (A, PartOfA) => A | |
/** Creates an instance from a [[Signal]] and [[UpdateFn]]. */ | |
def apply[A]( | |
signal: Signal[A], | |
update: UpdateFn[A], | |
): UpdatableSignal[A] = { | |
val s = signal | |
val u = update | |
new UpdatableSignal[A] { | |
override def signal: Signal[A] = s | |
override def update: UpdateFn[A] = u | |
} | |
} | |
/** Creates an instance from a [[Var]] and mapping functions. */ | |
implicit def fromVar[A]( | |
rxVar: Var[A] | |
): UpdatableSignal[A] = UpdatableSignal[A]( | |
rxVar.signal, | |
update => rxVar.update(update), | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment