Skip to content

Instantly share code, notes, and snippets.

@felher
Created October 18, 2022 15:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save felher/5515eb1124268b0e10eadc78778f49a8 to your computer and use it in GitHub Desktop.
Save felher/5515eb1124268b0e10eadc78778f49a8 to your computer and use it in GitHub Desktop.
Sum-Type Splitter for Laminar with Exhaustiveness-Checks
import com.raquo.laminar.api.L.*
import scala.deriving.*
import scala.compiletime.*
object SplitEnum:
final case class Splitter[A, Todo <: Tuple, O](sig: Signal[A], keyer: A => Int, handlers: Array[Any => O]):
inline def close: Signal[O] =
inline erasedValue[Todo] match
case _: EmptyTuple.type =>
sig.splitOne(keyer)((key, _, subSig) => handlers(key)(subSig))
case _: *:[h, t] =>
error(
"You can only close the split after all cases are handled.\nCase " + Util
.nameOuter[h] + " is not handled yet.\nAdd another handler with .handle((in: Signal[" + Util
.nameOuter[h] + "]) => result))"
)
def handle[OO >: O](caseHandler: Signal[Tuple.Elem[Todo, 0]] => OO): Splitter[A, Tuple.Drop[Todo, 1], OO] =
Splitter(sig, keyer, handlers :+ caseHandler.asInstanceOf)
extension [A](sig: Signal[A])
def splitEnum(using mirror: Mirror.SumOf[A]): Splitter[A, mirror.MirroredElemTypes, Nothing] =
Splitter(sig, mirror.ordinal, Array.empty)
import scala.quoted.*
// Needs to be in an extra files since macros need to be in an extra file
object Util:
def nameOf[A](using t: Type[A], ctx: Quotes): Expr[String] = Expr(Type.show[A])
inline def nameOuter[A] = ${ nameOf[A] }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment