diff --git a/src/main/scala-3/com/raquo/airstream/split/MacrosUtilities.scala b/src/main/scala-3/com/raquo/airstream/split/MacrosUtilities.scala index 02f11cd..5468c1b 100644 --- a/src/main/scala-3/com/raquo/airstream/split/MacrosUtilities.scala +++ b/src/main/scala-3/com/raquo/airstream/split/MacrosUtilities.scala @@ -1,73 +1,70 @@ package com.raquo.airstream.split import scala.quoted.{Expr, Quotes, Type} +import scala.annotation.tailrec +import scala.annotation.compileTimeOnly private[split] object MacrosUtilities { - def exprOfListToListOfExpr[T: Type]( - pfListExpr: Expr[List[T]] - )( - using quotes: Quotes - ): List[Expr[T]] = { - import quotes.reflect.* + type CaseAny = Any + type HandlerAny[+O] = Any - pfListExpr match { - case '{ $headExpr :: (${ tailExpr }: List[T]) } => - headExpr :: exprOfListToListOfExpr(tailExpr) - case '{ Nil } => Nil - case _ => - report.errorAndAbort( - "Macro expansion failed, please use `handleCase` instead" - ) - } + final case class MatchTypeHandler[T] private (private val underlying: Unit) extends AnyVal + object MatchTypeHandler { + @compileTimeOnly("MatchTypeHandler[T] cannot be used at runtime") + def instance[T]: MatchTypeHandler[T] = throw new UnsupportedOperationException("MatchTypeHandler[T] cannot be used at runtime") } - def listOfExprToExprOfList[T: Type]( - pfExprList: List[Expr[T]] - )( - using quotes: Quotes - ): Expr[List[T]] = { - import quotes.reflect.* + final case class MatchValueHandler[V] private (private val underlying: Unit) extends AnyVal - pfExprList match - case head :: tail => '{ $head :: ${ listOfExprToExprOfList(tail) } } - case Nil => '{ Nil } + object MatchValueHandler { + @compileTimeOnly("MatchValueHandler[V] cannot be used at runtime") + def instance[V](v: V): MatchValueHandler[V] = throw new UnsupportedOperationException("MatchValueHandler[V] cannot be used at runtime") } def innerObservableImpl[I: Type]( iExpr: Expr[I], - caseListExpr: Expr[List[PartialFunction[Any, Any]]] + caseExprSeq: Seq[Expr[CaseAny]] )( using quotes: Quotes - ): Expr[(Int, Any)] = { + ) = { import quotes.reflect.* - val caseExprList = exprOfListToListOfExpr(caseListExpr) - - val allCaseDefLists = caseExprList.reverse.zipWithIndex - .flatMap { case (caseExpr, idx) => - caseExpr.asTerm match { - case Lambda(_, Match(_, caseDefList)) => { - caseDefList.map { caseDef => - val idxExpr = Expr.apply(idx) - val newRhsExpr = '{ - val res = ${ caseDef.rhs.asExprOf[Any] }; ($idxExpr, res) - } - CaseDef.copy(caseDef)( - caseDef.pattern, - caseDef.guard, - newRhsExpr.asTerm - ) + @tailrec + def getCaseDef( + idx: Int, + term: Term + ): List[CaseDef] = { + term match { + case Inlined(_, _, inlinedTerm) => getCaseDef(idx, inlinedTerm) + case Lambda(_, Match(_, caseDefList)) => { + caseDefList.map { caseDef => + val idxExpr = Expr.apply(idx) + val newRhsExpr = '{ + val res = ${ caseDef.rhs.asExprOf[Any] }; ($idxExpr, res) } - } - case _ => - report.errorAndAbort( - "Macro expansion failed, please use `handleCase` with annonymous partial function" + CaseDef.copy(caseDef)( + caseDef.pattern, + caseDef.guard, + newRhsExpr.asTerm ) + } } + case _ => + report.errorAndAbort( + "Macro expansion failed, please use `handleCase` with annonymous partial function" + ) + } + } + + val allCaseDefLists = caseExprSeq.view + .zipWithIndex + .flatMap { case (caseExpr, idx) => + getCaseDef(idx, caseExpr.asTerm) } .map(_.changeOwner(Symbol.spliceOwner)) + .toList Match(iExpr.asTerm, allCaseDefLists).asExprOf[(Int, Any)] } diff --git a/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneMacros.scala b/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneMacros.scala index a1f7092..81e18ae 100644 --- a/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneMacros.scala +++ b/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneMacros.scala @@ -9,6 +9,9 @@ import com.raquo.airstream.core.{ import scala.quoted.{Expr, Quotes, Type} import scala.annotation.{unused, targetName} import scala.compiletime.summonInline +import scala.quoted.Varargs +import com.raquo.airstream.split.MacrosUtilities.{CaseAny, HandlerAny, MatchTypeHandler, MatchValueHandler, innerObservableImpl} +import scala.reflect.TypeTest /** `SplitMatchOneMacros` turns this code * @@ -56,11 +59,7 @@ object SplitMatchOneMacros { extension [Self[+_] <: Observable[_], I](inline observable: BaseObservable[Self, I]) { inline def splitMatchOne: SplitMatchOneObservable[Self, I, Nothing] = - SplitMatchOneObservable.build( - observable, - Nil, - Map.empty[Int, Function2[Any, Any, Nothing]] - ) + SplitMatchOneObservable.build(observable)()() } extension [Self[+_] <: Observable[_], I, O]( @@ -70,17 +69,13 @@ object SplitMatchOneMacros { handleCaseImpl('{ matchSplitObservable }, '{ casePf }, '{ handleFn }) } - inline private def handlePfType[T](inline casePf: PartialFunction[Any, T]) = ${ - handleTypeImpl[Self, I, O, T]('{ matchSplitObservable }, '{ casePf }) + inline def handleType[T]: SplitMatchOneTypeObservable[Self, I, O, T] = ${ + handleTypeImpl[Self, I, O, T]('{ matchSplitObservable }) } - inline def handleType[T]: SplitMatchOneTypeObservable[Self, I, O, T] = handlePfType[T] { case t: T => t } - - inline private def handlePfValue[V](inline casePf: PartialFunction[Any, V]) = ${ - handleValueImpl[Self, I, O, V]('{ matchSplitObservable }, '{ casePf }) + inline def handleValue[V](inline v: V)(using inline valueOf: ValueOf[V]): SplitMatchOneValueObservable[Self, I, O, V] = ${ + handleValueImpl[Self, I, O, V]('{ matchSplitObservable }, '{ v }) } - - inline def handleValue[V](inline v: V)(using inline valueOf: ValueOf[V]): SplitMatchOneValueObservable[Self, I, O, V] = handlePfValue[V] { case _: V => v } } extension [Self[+_] <: Observable[_], I, O, T](inline matchTypeObserver: SplitMatchOneTypeObservable[Self, I, O, T]) { @@ -120,19 +115,30 @@ object SplitMatchOneMacros { matchSplitObservableExpr match { case '{ - SplitMatchOneObservable.build[Self, I, O]( - $observableExpr, - $caseListExpr, - $handlerMapExpr + SplitMatchOneObservable.build[Self, I, O]($observableExpr)(${caseExpr}*)(${handlerExpr}*) + } => { + val caseExprSeq = caseExpr match { + case Varargs(caseExprSeq) => caseExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + val handlerExprSeq = handlerExpr match { + case Varargs(handlerExprSeq) => handlerExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + innerHandleCaseImpl( + observableExpr, + caseExprSeq, + handlerExprSeq, + casePfExpr, + handleFnExpr ) - } => - innerHandleCaseImpl( - observableExpr, - caseListExpr, - handlerMapExpr, - casePfExpr, - handleFnExpr - ) + } case other => report.errorAndAbort( "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" @@ -141,8 +147,7 @@ object SplitMatchOneMacros { } private def handleTypeImpl[Self[+_] <: Observable[_]: Type, I: Type, O: Type, T: Type]( - matchSplitObservableExpr: Expr[SplitMatchOneObservable[Self, I, O]], - casePfExpr: Expr[PartialFunction[T, T]] + matchSplitObservableExpr: Expr[SplitMatchOneObservable[Self, I, O]] )( using quotes: Quotes ): Expr[SplitMatchOneTypeObservable[Self, I, O, T]] = { @@ -150,18 +155,17 @@ object SplitMatchOneMacros { matchSplitObservableExpr match { case '{ - SplitMatchOneObservable.build[Self, I, O]( - $observableExpr, - $caseListExpr, - $handlerMapExpr - ) + SplitMatchOneObservable.build[Self, I, O]($observableExpr)(${caseExpr}*)(${handlerExpr}*) } => '{ SplitMatchOneTypeObservable.build[Self, I, O, T]( - $observableExpr, - $caseListExpr, - $handlerMapExpr, - $casePfExpr + $observableExpr + )( + ${caseExpr}* + )( + ${handlerExpr}* + )( + MatchTypeHandler.instance[T] ) } case other => @@ -181,17 +185,28 @@ object SplitMatchOneMacros { matchSplitObservableExpr match { case '{ - SplitMatchOneTypeObservable.build[Self, I, O, T]( - $observableExpr, - $caseListExpr, - $handlerMapExpr, - $tCaseExpr - ) + SplitMatchOneTypeObservable.build[Self, I, O, T]($observableExpr)(${caseExpr}*)(${handlerExpr}*)(MatchTypeHandler.instance[T]) } => + val caseExprSeq = caseExpr match { + case Varargs(caseExprSeq) => caseExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + val handlerExprSeq = handlerExpr match { + case Varargs(handlerExprSeq) => handlerExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + val tCaseExpr: Expr[PartialFunction[T, T]] = '{ { case t: T => t } } + innerHandleCaseImpl[Self, I, O, O1, T, T]( observableExpr, - caseListExpr, - handlerMapExpr, + caseExprSeq, + handlerExprSeq, tCaseExpr, handleFnExpr ) @@ -204,7 +219,7 @@ object SplitMatchOneMacros { private def handleValueImpl[Self[+_] <: Observable[_]: Type, I: Type, O: Type, V: Type]( matchSplitObservableExpr: Expr[SplitMatchOneObservable[Self, I, O]], - casePfExpr: Expr[PartialFunction[V, V]] + vExpr: Expr[V] )( using quotes: Quotes ): Expr[SplitMatchOneValueObservable[Self, I, O, V]] = { @@ -212,18 +227,17 @@ object SplitMatchOneMacros { matchSplitObservableExpr match { case '{ - SplitMatchOneObservable.build[Self, I, O]( - $observableExpr, - $caseListExpr, - $handlerMapExpr - ) + SplitMatchOneObservable.build[Self, I, O]($observableExpr)(${caseExpr}*)(${handlerExpr}*) } => '{ SplitMatchOneValueObservable.build[Self, I, O, V]( - $observableExpr, - $caseListExpr, - $handlerMapExpr, - $casePfExpr + $observableExpr + )( + ${caseExpr}* + )( + ${handlerExpr}* + )( + MatchValueHandler.instance[V]($vExpr) ) } case other => @@ -243,18 +257,29 @@ object SplitMatchOneMacros { matchValueObservableExpr match { case '{ - SplitMatchOneValueObservable.build[Self, I, O, V]( - $observableExpr, - $caseListExpr, - $handlerMapExpr, - $tCaseExpr - ) + SplitMatchOneValueObservable.build[Self, I, O, V]($observableExpr)(${caseExpr}*)(${handlerExpr}*)(MatchValueHandler.instance[V]($vExpr)) } => + val caseExprSeq = caseExpr match { + case Varargs(caseExprSeq) => caseExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + val handlerExprSeq = handlerExpr match { + case Varargs(handlerExprSeq) => handlerExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + val vCaseExpr: Expr[PartialFunction[V, V]] = '{ { case _: V => $vExpr } } + innerHandleCaseImpl[Self, I, O, O1, V, V]( observableExpr, - caseListExpr, - handlerMapExpr, - tCaseExpr, + caseExprSeq, + handlerExprSeq, + vCaseExpr, handleFnExpr ) case other => @@ -266,45 +291,44 @@ object SplitMatchOneMacros { private def innerHandleCaseImpl[Self[+_] <: Observable[_]: Type, I: Type, O: Type, O1 >: O: Type, A: Type, B: Type]( observableExpr: Expr[BaseObservable[Self, I]], - caseListExpr: Expr[List[PartialFunction[Any, Any]]], - handlerMapExpr: Expr[Map[Int, Function2[Any, Any, O]]], + caseExprSeq: Seq[Expr[CaseAny]], + handlerExprSeq: Seq[Expr[HandlerAny[O]]], casePfExpr: Expr[PartialFunction[A, B]], handleFnExpr: Expr[Function2[B, Signal[B], O1]] )( using quotes: Quotes ): Expr[SplitMatchOneObservable[Self, I, O1]] = { - import quotes.reflect.* - - val caseExprList = MacrosUtilities.exprOfListToListOfExpr(caseListExpr) - - val nextCaseExprList = - casePfExpr.asExprOf[PartialFunction[Any, Any]] :: caseExprList - - val nextCaseListExpr = MacrosUtilities.listOfExprToExprOfList(nextCaseExprList) '{ SplitMatchOneObservable.build[Self, I, O1]( - $observableExpr, - $nextCaseListExpr, - ($handlerMapExpr + ($handlerMapExpr.size -> $handleFnExpr - .asInstanceOf[Function2[Any, Any, O1]])) + $observableExpr + )( + ${ Varargs(caseExprSeq :+ casePfExpr.asExprOf[CaseAny]) }* + )( + ${ Varargs(handlerExprSeq :+ handleFnExpr.asExprOf[HandlerAny[O1]]) }* ) } } - private inline def toSplittableOneObservable[Self[+_] <: Observable[_], O]( + private def toSplittableOneObservable[Self[+_] <: Observable[_], O]( parentObservable: BaseObservable[Self, (Int, Any)], - handlerMap: Map[Int, Function2[Any, Any, O]] + handlers: HandlerAny[O]* ): Self[O] = { parentObservable .matchStreamOrSignal( ifStream = _.splitOne(_._1) { case (idx, (_, b), dataSignal) => val bSignal = dataSignal.map(_._2) - handlerMap.apply(idx).apply(b, bSignal) + handlers.view.zipWithIndex.map(_.swap).toMap + .getOrElse(idx, IllegalStateException("Illegal SplitMatchOne state. This is a bug in Airstream.")) + .asInstanceOf[Function2[Any, Any, O]] + .apply(b, bSignal) }, ifSignal = _.splitOne(_._1) { case (idx, (_, b), dataSignal) => val bSignal = dataSignal.map(_._2) - handlerMap.apply(idx).apply(b, bSignal) + handlers.view.zipWithIndex.map(_.swap).toMap + .getOrElse(idx, IllegalStateException("Illegal SplitMatchOne state. This is a bug in Airstream.")) + .asInstanceOf[Function2[Any, Any, O]] + .apply(b, bSignal) } ) .asInstanceOf[Self[O]] // #TODO[Integrity] Same as FlatMap/AsyncStatusObservable, how to type this properly? @@ -318,25 +342,29 @@ object SplitMatchOneMacros { import quotes.reflect.* matchSplitObservableExpr match { - case '{ SplitMatchOneObservable.build[Self, I, O]($_, Nil, $_) } => - report.errorAndAbort( - "Macro expansion failed, need at least one handleCase" - ) case '{ - SplitMatchOneObservable.build[Self, I, O]( - $observableExpr, - $caseListExpr, - $handlerMapExpr - ) + SplitMatchOneObservable.build[Self, I, O]($observableExpr)(${caseExpr}*)(${handleExpr}*) } => - '{ - toSplittableOneObservable( - $observableExpr - .map(i => ${ MacrosUtilities.innerObservableImpl('i, caseListExpr) }) - .asInstanceOf[BaseObservable[Self, (Int, Any)]], - $handlerMapExpr + val caseExprSeq = caseExpr match { + case Varargs(caseExprSeq) => caseExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" ) } + if (caseExprSeq.isEmpty) { + report.errorAndAbort( + "Macro expansion failed, need at least one handleCase" + ) + } else { + '{ + toSplittableOneObservable( + $observableExpr + .map(i => ${ innerObservableImpl('i, caseExprSeq) }) + .asInstanceOf[BaseObservable[Self, (Int, Any)]], + ${handleExpr}* + ) + } + } case _ => report.errorAndAbort( "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" diff --git a/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneObservable.scala b/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneObservable.scala index 8e7400f..f417220 100644 --- a/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneObservable.scala +++ b/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneObservable.scala @@ -2,6 +2,7 @@ package com.raquo.airstream.split import com.raquo.airstream.core.{Observable, BaseObservable} import scala.annotation.compileTimeOnly +import com.raquo.airstream.split.MacrosUtilities.{CaseAny, HandlerAny} /** * `MatchSplitObservable` served as macro's data holder for macro expansion. @@ -17,7 +18,7 @@ import scala.annotation.compileTimeOnly * will be expanded sematically into: * * ```scala - * MatchSplitObservable.build(fooSignal, ({ case baz: Baz => baz }) :: ({ case Bar(Some(str)) => str }) :: Nil, handlerMap) + * MatchSplitObservable.build(fooSignal)(({ case baz: Baz => baz }), ({ case Bar(Some(str)) => str }))(...) * ``` */ @@ -27,9 +28,11 @@ object SplitMatchOneObservable { @compileTimeOnly("`splitMatchOne` without `toSignal`/`toStream` is illegal") def build[Self[+_] <: Observable[_] , I, O]( - observable: BaseObservable[Self, I], - caseList: List[PartialFunction[Any, Any]], - handlerMap: Map[Int, Function2[Any, Any, O]] + observable: BaseObservable[Self, I] + )( + caseList: CaseAny* + )( + handleList: HandlerAny[O]* ): SplitMatchOneObservable[Self, I, O] = throw new UnsupportedOperationException("`splitMatchOne` without `toSignal`/`toStream` is illegal") } diff --git a/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneTypeObservable.scala b/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneTypeObservable.scala index 45adeab..5c7ef9a 100644 --- a/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneTypeObservable.scala +++ b/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneTypeObservable.scala @@ -2,6 +2,7 @@ package com.raquo.airstream.split import com.raquo.airstream.core.{Observable, BaseObservable} import scala.annotation.compileTimeOnly +import com.raquo.airstream.split.MacrosUtilities.{CaseAny, HandlerAny, MatchTypeHandler} /** `MatchTypeObservable` served as macro's data holder for macro expansion. * @@ -15,22 +16,13 @@ import scala.annotation.compileTimeOnly * will be expanded sematically into: * * ```scala - * MatchTypeObservable.build[*, *, *, Baz]( - * fooSignal, - * Nil, - * handlerMap, - * ({ case t: Baz => t }) - * ) + * MatchTypeObservable.build[*, *, *, Baz](fooSignal)()(???)({ case t: Baz => t }) * ``` * * and then into: * * ```scala - * MatchSplitObservable.build( - * fooSignal, - * ({ case baz: Baz => baz }) :: Nil, - * handlerMap - * ) + * MatchSplitObservable.build(fooSignal)({ case baz: Baz => baz })(???) * ``` */ @@ -40,10 +32,13 @@ object SplitMatchOneTypeObservable { @compileTimeOnly("`splitMatchOne` without `toSignal`/`toStream` is illegal") def build[Self[+_] <: Observable[_], I, O, T]( - observable: BaseObservable[Self, I], - caseList: List[PartialFunction[Any, Any]], - handlerMap: Map[Int, Function2[Any, Any, O]], - tCast: PartialFunction[T, T] + observable: BaseObservable[Self, I] + )( + caseList: CaseAny* + )( + handleList: HandlerAny[O]* + )( + tHandler: MatchTypeHandler[T] ): SplitMatchOneTypeObservable[Self, I, O, T] = throw new UnsupportedOperationException( "`splitMatchOne` without `toSignal`/`toStream` is illegal" diff --git a/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneValueObservable.scala b/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneValueObservable.scala index 280eae6..07d0b29 100644 --- a/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneValueObservable.scala +++ b/src/main/scala-3/com/raquo/airstream/split/SplitMatchOneValueObservable.scala @@ -2,6 +2,7 @@ package com.raquo.airstream.split import com.raquo.airstream.core.{Observable, BaseObservable} import scala.annotation.compileTimeOnly +import com.raquo.airstream.split.MacrosUtilities.{CaseAny, HandlerAny, MatchValueHandler} /** `MatchSingletonObservable` served as macro's data holder for macro expansion. * @@ -15,22 +16,13 @@ import scala.annotation.compileTimeOnly * will be expanded sematically into: * * ```scala - * MatchTypeObservable.build[*, *, *, Baz]( - * fooSignal, - * Nil, - * handlerMap, - * ({ case Tar => Tar }) - * ) + * MatchTypeObservable.build[*, *, *, Baz](fooSignal)()(???)({ case Tar => Tar }) * ``` * * and then into: * * ```scala - * MatchSplitObservable.build( - * fooSignal, - * ({ case Tar => Tar }) :: Nil, - * handlerMap - * ) + * MatchSplitObservable.build(fooSignal)({ case Tar => Tar })(???) * ``` */ @@ -40,10 +32,13 @@ object SplitMatchOneValueObservable { @compileTimeOnly("`splitMatchOne` without `toSignal`/`toStream` is illegal") def build[Self[+_] <: Observable[_], I, O, V]( - observable: BaseObservable[Self, I], - caseList: List[PartialFunction[Any, Any]], - handlerMap: Map[Int, Function2[Any, Any, O]], - vCast: PartialFunction[V, V] + observable: BaseObservable[Self, I] + )( + caseList: CaseAny* + )( + handleList: HandlerAny[O]* + )( + vHandler: MatchValueHandler[V] ): SplitMatchOneValueObservable[Self, I, O, V] = throw new UnsupportedOperationException( "`splitMatchOne` without `toSignal`/`toStream` is illegal" diff --git a/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqMacros.scala b/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqMacros.scala index 982e745..0402596 100644 --- a/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqMacros.scala +++ b/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqMacros.scala @@ -9,6 +9,8 @@ import com.raquo.airstream.core.{ import scala.quoted.{Expr, Quotes, Type} import scala.annotation.{unused, targetName} import scala.compiletime.summonInline +import scala.quoted.Varargs +import com.raquo.airstream.split.MacrosUtilities.{CaseAny, HandlerAny, MatchTypeHandler, MatchValueHandler, innerObservableImpl} object SplitMatchSeqMacros { @@ -18,14 +20,7 @@ object SplitMatchSeqMacros { inline distinctCompose: Function1[Signal[I], Signal[I]] = (iSignal: Signal[I]) => iSignal.distinct, inline duplicateKeysConfig: DuplicateKeysConfig = DuplicateKeysConfig.default, ) = { - SplitMatchSeqObservable.build( - keyFn, - distinctCompose, - duplicateKeysConfig, - observable, - Nil, - Map.empty[Int, Function2[Any, Any, Nothing]] - ) + SplitMatchSeqObservable.build(keyFn, distinctCompose, duplicateKeysConfig, observable)()() } } @@ -36,18 +31,14 @@ object SplitMatchSeqMacros { handleCaseImpl('{ matchSplitObservable }, '{ casePf }, '{ handleFn }) } - inline private def handlePfType[T](inline casePf: PartialFunction[Any, T]) = ${ - handleTypeImpl('{ matchSplitObservable }, '{ casePf }) + inline def handleType[T]: SplitMatchSeqTypeObservable[Self, I, K, O, CC, T] = ${ + handleTypeImpl('{ matchSplitObservable }) } - inline def handleType[T]: SplitMatchSeqTypeObservable[Self, I, K, O, CC, T] = handlePfType[T] { case t: T => t } - - inline private def handlePfValue[V](inline casePf: PartialFunction[Any, V]) = ${ - handleValueImpl('{ matchSplitObservable }, '{ casePf }) + inline def handleValue[V](inline v: V)(using inline valueOf: ValueOf[V]): SplitMatchSeqValueObservable[Self, I, K, O, CC, V] = ${ + handleValueImpl('{ matchSplitObservable }, '{ v }) } - inline def handleValue[V](inline v: V)(using inline valueOf: ValueOf[V]): SplitMatchSeqValueObservable[Self, I, K, O, CC, V] = handlePfValue[V] { case _: V => v } - inline def toSignal: Signal[CC[O]] = ${ observableImpl('{ matchSplitObservable }) } } @@ -80,21 +71,39 @@ object SplitMatchSeqMacros { $keyFnExpr, $distinctComposeExpr, $duplicateKeysConfigExpr, - $observableExpr, - $caseListExpr, - $handlerMapExpr + $observableExpr + )( + ${caseExpr}* + )( + ${handlerExpr}* ) - } => - innerHandleCaseImpl( - keyFnExpr, - distinctComposeExpr, - duplicateKeysConfigExpr, - observableExpr, - caseListExpr, - handlerMapExpr, - casePfExpr, - handleFnExpr - ) + } => { + + val caseExprSeq = caseExpr match { + case Varargs(caseExprSeq) => caseExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + val handlerExprSeq = handlerExpr match { + case Varargs(handlerExprSeq) => handlerExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + innerHandleCaseImpl( + keyFnExpr, + distinctComposeExpr, + duplicateKeysConfigExpr, + observableExpr, + caseExprSeq, + handlerExprSeq, + casePfExpr, + handleFnExpr + ) + } case other => report.errorAndAbort( "Macro expansion failed, please use `splitMatchSeq` instead of creating new SplitMatchSeqObservable explicitly" @@ -103,8 +112,7 @@ object SplitMatchSeqMacros { } private def handleTypeImpl[Self[+_] <: Observable[_]: Type, I: Type, K: Type, O: Type, CC[_]: Type, T: Type]( - matchSplitObservableExpr: Expr[SplitMatchSeqObservable[Self, I, K, O, CC]], - casePfExpr: Expr[PartialFunction[T, T]] + matchSplitObservableExpr: Expr[SplitMatchSeqObservable[Self, I, K, O, CC]] )( using quotes: Quotes ): Expr[SplitMatchSeqTypeObservable[Self, I, K, O, CC, T]] = { @@ -116,9 +124,11 @@ object SplitMatchSeqMacros { $keyFnExpr, $distinctComposeExpr, $duplicateKeysConfigExpr, - $observableExpr, - $caseListExpr, - $handlerMapExpr + $observableExpr + )( + ${caseExpr}* + )( + ${handlerExpr}* ) } => '{ @@ -126,10 +136,13 @@ object SplitMatchSeqMacros { $keyFnExpr, $distinctComposeExpr, $duplicateKeysConfigExpr, - $observableExpr, - $caseListExpr, - $handlerMapExpr, - $casePfExpr + $observableExpr + )( + ${caseExpr}* + )( + ${handlerExpr}* + )( + MatchTypeHandler.instance[T] ) } case other => @@ -153,22 +166,43 @@ object SplitMatchSeqMacros { $keyFnExpr, $distinctComposeExpr, $duplicateKeysConfigExpr, - $observableExpr, - $caseListExpr, - $handlerMapExpr, - $tCaseExpr + $observableExpr + )( + ${caseExpr}* + )( + ${handlerExpr}* + )( + MatchTypeHandler.instance[T] ) - } => - innerHandleCaseImpl( - keyFnExpr, - distinctComposeExpr, - duplicateKeysConfigExpr, - observableExpr, - caseListExpr, - handlerMapExpr, - tCaseExpr, - handleFnExpr - ) + } => { + + val caseExprSeq = caseExpr match { + case Varargs(caseExprSeq) => caseExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + val handlerExprSeq = handlerExpr match { + case Varargs(handlerExprSeq) => handlerExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + val tCaseExpr: Expr[PartialFunction[T, T]] = '{ { case t: T => t } } + + innerHandleCaseImpl( + keyFnExpr, + distinctComposeExpr, + duplicateKeysConfigExpr, + observableExpr, + caseExprSeq, + handlerExprSeq, + tCaseExpr, + handleFnExpr + ) + } case other => report.errorAndAbort( "Macro expansion failed, please use `splitMatchSeq` instead of creating new SplitMatchSeqObservable explicitly" @@ -178,7 +212,7 @@ object SplitMatchSeqMacros { private def handleValueImpl[Self[+_] <: Observable[_]: Type, I: Type, K: Type, O: Type, CC[_]: Type, V: Type]( matchSplitObservableExpr: Expr[SplitMatchSeqObservable[Self, I, K, O, CC]], - casePfExpr: Expr[PartialFunction[V, V]] + vExpr: Expr[V] )( using quotes: Quotes ): Expr[SplitMatchSeqValueObservable[Self, I, K, O, CC, V]] = { @@ -190,9 +224,11 @@ object SplitMatchSeqMacros { $keyFnExpr, $distinctComposeExpr, $duplicateKeysConfigExpr, - $observableExpr, - $caseListExpr, - $handlerMapExpr + $observableExpr + )( + ${caseExpr}* + )( + ${handlerExpr}* ) } => '{ @@ -200,10 +236,13 @@ object SplitMatchSeqMacros { $keyFnExpr, $distinctComposeExpr, $duplicateKeysConfigExpr, - $observableExpr, - $caseListExpr, - $handlerMapExpr, - $casePfExpr + $observableExpr + )( + ${caseExpr}* + )( + ${handlerExpr}* + )( + MatchValueHandler.instance($vExpr) ) } case other => @@ -227,22 +266,43 @@ object SplitMatchSeqMacros { $keyFnExpr, $distinctComposeExpr, $duplicateKeysConfigExpr, - $observableExpr, - $caseListExpr, - $handlerMapExpr, - $tCaseExpr + $observableExpr + )( + ${caseExpr}* + )( + ${handlerExpr}* + )( + MatchValueHandler.instance($vExpr) ) - } => - innerHandleCaseImpl( - keyFnExpr, - distinctComposeExpr, - duplicateKeysConfigExpr, - observableExpr, - caseListExpr, - handlerMapExpr, - tCaseExpr, - handleFnExpr - ) + } => { + + val caseExprSeq = caseExpr match { + case Varargs(caseExprSeq) => caseExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + val handlerExprSeq = handlerExpr match { + case Varargs(handlerExprSeq) => handlerExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + val vCaseExpr: Expr[PartialFunction[V, V]] = '{ { case _: V => $vExpr } } + + innerHandleCaseImpl( + keyFnExpr, + distinctComposeExpr, + duplicateKeysConfigExpr, + observableExpr, + caseExprSeq, + handlerExprSeq, + vCaseExpr, + handleFnExpr + ) + } case other => report.errorAndAbort( "Macro expansion failed, please use `splitMatchSeq` instead of creating new SplitMatchSeqObservable explicitly" @@ -255,21 +315,13 @@ object SplitMatchSeqMacros { distinctComposeExpr: Expr[Function1[Signal[I], Signal[I]]], duplicateKeysConfigExpr: Expr[DuplicateKeysConfig], observableExpr: Expr[BaseObservable[Self, CC[I]]], - caseListExpr: Expr[List[PartialFunction[Any, Any]]], - handlerMapExpr: Expr[Map[Int, Function2[Any, Any, O]]], + caseExprSeq: Seq[Expr[CaseAny]], + handlerExprSeq: Seq[Expr[HandlerAny[O]]], casePfExpr: Expr[PartialFunction[A, B]], handleFnExpr: Expr[Function2[B, Signal[B], O1]] )( using quotes: Quotes ): Expr[SplitMatchSeqObservable[Self, I, K, O1, CC]] = { - import quotes.reflect.* - - val caseExprList = MacrosUtilities.exprOfListToListOfExpr(caseListExpr) - - val nextCaseExprList = - casePfExpr.asExprOf[PartialFunction[Any, Any]] :: caseExprList - - val nextCaseListExpr = MacrosUtilities.listOfExprToExprOfList(nextCaseExprList) '{ SplitMatchSeqObservable.build[Self, I, K, O1, CC]( @@ -277,9 +329,10 @@ object SplitMatchSeqMacros { $distinctComposeExpr, $duplicateKeysConfigExpr, $observableExpr, - $nextCaseListExpr, - ($handlerMapExpr + ($handlerMapExpr.size -> $handleFnExpr - .asInstanceOf[Function2[Any, Any, O1]])) + )( + ${ Varargs(caseExprSeq :+ casePfExpr.asExprOf[CaseAny]) }* + )( + ${ Varargs(handlerExprSeq :+ handleFnExpr.asExprOf[HandlerAny[O1]]) }* ) } } @@ -291,6 +344,7 @@ object SplitMatchSeqMacros { ): Signal[(I, Int, Any)] = { val iSignal = dataSignal.map(_._1) val otherSignal = dataSignal.map(data => data._2 -> data._3) + // TODO: We are unnecessary sufferring from `otherSignal.distinct`'s cost here distinctCompose(iSignal).combineWith(otherSignal.distinct) } @@ -303,13 +357,13 @@ object SplitMatchSeqMacros { idx -> keyFn(i) } - private inline def toSplittableSeqObservable[Self[+_] <: Observable[_], I, K, O, CC[_]]( + private def toSplittableSeqObservable[Self[+_] <: Observable[_], I, K, O, CC[_]]( parentObservable: BaseObservable[Self, CC[(I, Int, Any)]], keyFn: I => K, distinctCompose: Signal[I] => Signal[I], duplicateKeysConfig: DuplicateKeysConfig, - handlerMap: Map[Int, Function2[Any, Any, O]], - splittable: Splittable[CC] + splittable: Splittable[CC], + handlers: HandlerAny[O]*, ): Signal[CC[O]] = { parentObservable .matchStreamOrSignal( @@ -319,7 +373,10 @@ object SplitMatchSeqMacros { duplicateKeys = duplicateKeysConfig ) { case ((idx, _), (_, _, b), dataSignal) => val bSignal = dataSignal.map(_._3) - handlerMap.apply(idx).apply(b, bSignal) + handlers.view.zipWithIndex.map(_.swap).toMap + .getOrElse(idx, IllegalStateException("Illegal SplitMatchSeq state. This is a bug in Airstream.")) + .asInstanceOf[Function2[Any, Any, O]] + .apply(b, bSignal) }(splittable), ifSignal = _.split( key = customKey(keyFn), @@ -327,7 +384,10 @@ object SplitMatchSeqMacros { duplicateKeys = duplicateKeysConfig ) { case ((idx, _), (_, _, b), dataSignal) => val bSignal = dataSignal.map(_._3) - handlerMap.apply(idx).apply(b, bSignal) + handlers.view.zipWithIndex.map(_.swap).toMap + .getOrElse(idx, IllegalStateException("Illegal SplitMatchSeq state. This is a bug in Airstream.")) + .asInstanceOf[Function2[Any, Any, O]] + .apply(b, bSignal) }(splittable) ) } @@ -340,33 +400,43 @@ object SplitMatchSeqMacros { import quotes.reflect.* matchSplitObservableExpr match { - case '{ SplitMatchSeqObservable.build[Self, I, K, O, CC]($_, $_, $_, $_, Nil, $_) } => - report.errorAndAbort( - "Macro expansion failed, need at least one handleCase" - ) case '{ SplitMatchSeqObservable.build[Self, I, K, O, CC]( $keyFnExpr, $distinctComposeExpr, $duplicateKeysConfigExpr, - $observableExpr, - $caseListExpr, - $handlerMapExpr + $observableExpr + )( + ${caseExpr}* + )( + ${handlerExpr}* ) } => Expr.summon[Splittable[CC]] match { case None => report.errorAndAbort( "Macro expansion failed, cannot find Splittable instance of " + MacrosUtilities.ShowType.nameOf[CC] ) - case Some(splittableExpr) => - '{ + case Some(splittableExpr) => { + val caseExprSeq = caseExpr match { + case Varargs(caseExprSeq) => caseExprSeq + case _ => report.errorAndAbort( + "Macro expansion failed, please use `splitMatchOne` instead of creating new SplitMatchOneObservable explicitly" + ) + } + + if (caseExprSeq.isEmpty) { + report.errorAndAbort( + "Macro expansion failed, need at least one handleCase" + ) + } else { + '{ toSplittableSeqObservable( $observableExpr .map { icc => $splittableExpr.map( icc, i => { - val (idx, b) = ${ MacrosUtilities.innerObservableImpl('i, caseListExpr) } + val (idx, b) = ${ innerObservableImpl('i, caseExprSeq) } (i, idx, b) } ) @@ -375,10 +445,12 @@ object SplitMatchSeqMacros { $keyFnExpr, $distinctComposeExpr, $duplicateKeysConfigExpr, - $handlerMapExpr, - $splittableExpr + $splittableExpr, + ${handlerExpr}*, ) } + } + } } case _ => report.errorAndAbort( diff --git a/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqObservable.scala b/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqObservable.scala index 7c6f78c..c572b49 100644 --- a/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqObservable.scala +++ b/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqObservable.scala @@ -3,6 +3,7 @@ package com.raquo.airstream.split import com.raquo.airstream.core.{Observable, BaseObservable} import scala.annotation.compileTimeOnly import com.raquo.airstream.core.Signal +import com.raquo.airstream.split.MacrosUtilities.{CaseAny, HandlerAny} final case class SplitMatchSeqObservable[Self[+_] <: Observable[_] , I, K, O, CC[_]] private (private val underlying: Unit) extends AnyVal @@ -13,9 +14,11 @@ object SplitMatchSeqObservable { keyFn: Function1[I, K], distinctCompose: Function1[Signal[I], Signal[I]], duplicateKeysConfig: DuplicateKeysConfig, - observable: BaseObservable[Self, CC[I]], - caseList: List[PartialFunction[Any, Any]], - handlerMap: Map[Int, Function2[Any, Any, O]] + observable: BaseObservable[Self, CC[I]] + )( + caseList: CaseAny* + )( + handleList: HandlerAny[O]* ): SplitMatchSeqObservable[Self, I, K, O, CC] = throw new UnsupportedOperationException("`splitMatchSeq` without `toSignal` is illegal") } diff --git a/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqTypeObservable.scala b/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqTypeObservable.scala index 558eaf1..092ce4d 100644 --- a/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqTypeObservable.scala +++ b/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqTypeObservable.scala @@ -3,6 +3,7 @@ package com.raquo.airstream.split import com.raquo.airstream.core.{Observable, BaseObservable} import scala.annotation.compileTimeOnly import com.raquo.airstream.core.Signal +import com.raquo.airstream.split.MacrosUtilities.{CaseAny, HandlerAny, MatchTypeHandler} final case class SplitMatchSeqTypeObservable[Self[+_] <: Observable[_] , I, K, O, CC[_], T] private (private val underlying: Unit) extends AnyVal @@ -13,10 +14,13 @@ object SplitMatchSeqTypeObservable { keyFn: Function1[I, K], distinctCompose: Function1[Signal[I], Signal[I]], duplicateKeysConfig: DuplicateKeysConfig, - observable: BaseObservable[Self, CC[I]], - caseList: List[PartialFunction[Any, Any]], - handlerMap: Map[Int, Function2[Any, Any, O]], - tCast: PartialFunction[T, T] + observable: BaseObservable[Self, CC[I]] + )( + caseList: CaseAny* + )( + handleList: HandlerAny[O]* + )( + tHandler: MatchTypeHandler[T] ): SplitMatchSeqTypeObservable[Self, I, K, O, CC, T] = throw new UnsupportedOperationException("`splitMatchSeq` without `toSignal` is illegal") } diff --git a/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqValueObservable.scala b/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqValueObservable.scala index 68709f1..f3eb77d 100644 --- a/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqValueObservable.scala +++ b/src/main/scala-3/com/raquo/airstream/split/SplitMatchSeqValueObservable.scala @@ -2,6 +2,7 @@ package com.raquo.airstream.split import com.raquo.airstream.core.{Observable, BaseObservable, Signal} import scala.annotation.compileTimeOnly +import com.raquo.airstream.split.MacrosUtilities.{CaseAny, HandlerAny, MatchValueHandler} final case class SplitMatchSeqValueObservable[Self[+_] <: Observable[_] , I, K, O, CC[_], V] private (private val underlying: Unit) extends AnyVal @@ -12,10 +13,13 @@ object SplitMatchSeqValueObservable { keyFn: Function1[I, K], distinctCompose: Function1[Signal[I], Signal[I]], duplicateKeysConfig: DuplicateKeysConfig, - observable: BaseObservable[Self, CC[I]], - caseList: List[PartialFunction[Any, Any]], - handlerMap: Map[Int, Function2[Any, Any, O]], - tCast: PartialFunction[V, V] + observable: BaseObservable[Self, CC[I]] + )( + caseList: CaseAny* + )( + handleList: HandlerAny[O]* + )( + vHandler: MatchValueHandler[V] ): SplitMatchSeqValueObservable[Self, I, K, O, CC, V] = throw new UnsupportedOperationException("`splitMatchSeq` without `toSignal` is illegal") } diff --git a/src/test/scala-3/com/raquo/airstream/split/SplitMatchOneSpec.scala b/src/test/scala-3/com/raquo/airstream/split/SplitMatchOneSpec.scala index 1e5b954..25adf76 100644 --- a/src/test/scala-3/com/raquo/airstream/split/SplitMatchOneSpec.scala +++ b/src/test/scala-3/com/raquo/airstream/split/SplitMatchOneSpec.scala @@ -471,4 +471,113 @@ class SplitMatchOneSpec extends UnitSpec { } + it("100 cases can be compiled") { + val myVar = Var[Foo](Bar(Some("initial"))) + val signal = myVar.signal + .splitMatchOne + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .handleCase { case Bar(Some(str)) => str } { (str, strSignal) => () } + .toSignal + + succeed + } + }