Skip to content

Commit

Permalink
Prototype OptionToOption and ToOption fallbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
MateuszKubuszok committed Jan 13, 2025
1 parent e52ee43 commit 668a3aa
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,21 @@ object Implicits {

def pure[A](a: A): List[A] = List(a)
}

implicit val vectorApplicativeTraverse: ApplicativeTraverse[Vector] = new ApplicativeTraverse[Vector] {

def traverse[G[_]: Applicative, A, B](fa: Vector[A])(f: A => G[B]): G[Vector[B]] =
fa.foldLeft(new ListBuffer[B].pure[G]) { (bufferG, a) =>
bufferG.map2(f(a)) { (buf: ListBuffer[B], b: B) => buf.append(b); buf } // can't use append 'cause 2.12
}.map(_.toVector)

Check warning on line 43 in chimney-macro-commons/src/main/scala/io/scalaland/chimney/internal/compiletime/fp/Implicits.scala

View check run for this annotation

Codecov / codecov/patch

chimney-macro-commons/src/main/scala/io/scalaland/chimney/internal/compiletime/fp/Implicits.scala#L40-L43

Added lines #L40 - L43 were not covered by tests

def parTraverse[G[_]: Parallel, A, B](fa: Vector[A])(f: A => G[B]): G[Vector[B]] =
fa.foldLeft(new ListBuffer[B].pure[G]) { (bufferG, a) =>
bufferG.parMap2(f(a)) { (buf: ListBuffer[B], b: B) => buf.append(b); buf } // can't use append 'cause 2.12
}.map(_.toVector)

Check warning on line 48 in chimney-macro-commons/src/main/scala/io/scalaland/chimney/internal/compiletime/fp/Implicits.scala

View check run for this annotation

Codecov / codecov/patch

chimney-macro-commons/src/main/scala/io/scalaland/chimney/internal/compiletime/fp/Implicits.scala#L45-L48

Added lines #L45 - L48 were not covered by tests

def map2[A, B, C](fa: Vector[A], fb: Vector[B])(f: (A, B) => C): Vector[C] = fa.zip(fb).map(f.tupled)

Check warning on line 50 in chimney-macro-commons/src/main/scala/io/scalaland/chimney/internal/compiletime/fp/Implicits.scala

View check run for this annotation

Codecov / codecov/patch

chimney-macro-commons/src/main/scala/io/scalaland/chimney/internal/compiletime/fp/Implicits.scala#L50

Added line #L50 was not covered by tests

def pure[A](a: A): Vector[A] = Vector(a)

Check warning on line 52 in chimney-macro-commons/src/main/scala/io/scalaland/chimney/internal/compiletime/fp/Implicits.scala

View check run for this annotation

Codecov / codecov/patch

chimney-macro-commons/src/main/scala/io/scalaland/chimney/internal/compiletime/fp/Implicits.scala#L52

Added line #L52 was not covered by tests
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@ private[compiletime] trait ResultOps { this: Derivation =>
def existential[F[_], A: Type](fa: F[A]): DerivationResult[Existential[F]] =
DerivationResult.pure(Existential[F, A](fa))

def totalExpr[To](expr: Expr[To]): DerivationResult[TransformationExpr[To]] =
DerivationResult.pure(TransformationExpr.fromTotal(expr))
def partialExpr[To](expr: Expr[partial.Result[To]]): DerivationResult[TransformationExpr[To]] =
DerivationResult.pure(TransformationExpr.fromPartial(expr))

def expanded[To](expr: TransformationExpr[To]): DerivationResult[Rule.ExpansionResult[To]] =
DerivationResult.pure(Rule.ExpansionResult.Expanded(expr))

def expandedTotal[To](expr: Expr[To]): DerivationResult[Rule.ExpansionResult[To]] =
DerivationResult.pure(Rule.ExpansionResult.Expanded(TransformationExpr.TotalExpr[To](expr)))

def expandedPartial[To](expr: Expr[partial.Result[To]]): DerivationResult[Rule.ExpansionResult[To]] =
DerivationResult.pure(Rule.ExpansionResult.Expanded(TransformationExpr.PartialExpr[To](expr)))

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package io.scalaland.chimney.internal.compiletime.derivation.transformer.rules

import io.scalaland.chimney.dsl as dsls
import io.scalaland.chimney.internal.compiletime.DerivationResult
import io.scalaland.chimney.internal.compiletime.derivation.transformer.Derivation
import io.scalaland.chimney.internal.compiletime.fp.Implicits.*
import io.scalaland.chimney.partial

private[compiletime] trait TransformOptionToOptionRuleModule {
Expand All @@ -22,8 +24,25 @@ private[compiletime] trait TransformOptionToOptionRuleModule {
to2.{Underlying as InnerTo, value as optionalTo}
DerivationResult.log(
s"Resolved ${Type.prettyPrint[From]} (${from2.value}) and ${Type.prettyPrint[To]} (${to2.value}) as optional types"
) >>
mapOptions[From, To, InnerFrom, InnerTo](optionalFrom, optionalTo)
) >> {
def srcToResult = mapOptions[From, To, InnerFrom, InnerTo](optionalFrom, optionalTo)

def fallbackToResult = mapFallbackOptions[From, To, InnerTo](optionalTo)

Check warning on line 30 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala#L30

Added line #L30 was not covered by tests

val merge = ctx match {
case TransformationContext.ForTotal(_) => mergeTotal(optionalTo)
case TransformationContext.ForPartial(_, failFast) => mergePartial(optionalTo, failFast)
}

(ctx.config.flags.optionFallbackMerge match {
case None =>
srcToResult
case Some(dsls.SourceOrElseFallback) =>
srcToResult.parMap2(fallbackToResult)((srcTo, fallbackTo) => fallbackTo.foldLeft(srcTo)(merge))
case Some(dsls.FallbackOrElseSource) =>
srcToResult.parMap2(fallbackToResult)((srcTo, fallbackTo) => fallbackTo.foldRight(srcTo)(merge))

Check warning on line 43 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala#L40-L43

Added lines #L40 - L43 were not covered by tests
}).flatMap(DerivationResult.expanded(_))
}
case _ =>
DerivationResult.attemptNextRule
}
Expand All @@ -33,7 +52,7 @@ private[compiletime] trait TransformOptionToOptionRuleModule {
optionalTo: OptionalValue[To, InnerTo]
)(implicit
ctx: TransformationContext[From, To]
): DerivationResult[Rule.ExpansionResult[To]] =
): DerivationResult[TransformationExpr[To]] =
ExprPromise
.promise[InnerFrom](ExprPromise.NameGenerationStrategy.FromType)
.traverse { (newFromExpr: Expr[InnerFrom]) =>
Expand All @@ -50,7 +69,7 @@ private[compiletime] trait TransformOptionToOptionRuleModule {
// We're constructing:
// ${ src }.fold[$To](None, innerFrom: $InnerFrom => Some(${ innerFrom }))
// but working with every OptionalValue
DerivationResult.expandedTotal(
DerivationResult.totalExpr(
optionalFrom.fold[To](
ctx.src,
optionalTo.empty,
Expand All @@ -63,7 +82,7 @@ private[compiletime] trait TransformOptionToOptionRuleModule {
// ${ derivedResultInnerTo }.map(Option(_))
// }
// but working with every OptionalValue
DerivationResult.expandedPartial(
DerivationResult.partialExpr(
optionalFrom.fold[partial.Result[To]](
ctx.src,
ChimneyExpr.PartialResult.Value(optionalTo.empty).upcastToExprOf[partial.Result[To]],
Expand All @@ -78,5 +97,46 @@ private[compiletime] trait TransformOptionToOptionRuleModule {
)
}
}

private def mapFallbackOptions[From, To, InnerTo: Type](optionalTo: OptionalValue[To, InnerTo])(implicit

Check warning on line 101 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala#L101

Added line #L101 was not covered by tests
ctx: TransformationContext[From, To]
): DerivationResult[Vector[TransformationExpr[To]]] = ctx.config.filterCurrentOverridesForFallbacks.view
.map { case TransformerOverride.Fallback(fallback) =>

Check warning on line 104 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala#L103-L104

Added lines #L103 - L104 were not covered by tests
import fallback.{Underlying as Fallback, value as fallbackExpr}
Type[Fallback] match {
case OptionalValue(fallback2) =>
import fallback2.{Underlying as InnerFallback, value as optionalFallback}

Check warning on line 108 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala#L106-L108

Added lines #L106 - L108 were not covered by tests
implicit val fallbackCtx: TransformationContext[Fallback, To] =
ctx.updateFromTo[Fallback, To](fallbackExpr, updateFallbacks = _ => Vector.empty)(Fallback, ctx.To)
Some(mapOptions[Fallback, To, InnerFallback, InnerTo](optionalFallback, optionalTo))
case _ => None

Check warning on line 112 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala#L110-L112

Added lines #L110 - L112 were not covered by tests
}
}
.collect { case Some(result) => result }
.toVector
.sequence

Check warning on line 117 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala#L115-L117

Added lines #L115 - L117 were not covered by tests

private def mergeTotal[To, InnerTo](
optionalTo: OptionalValue[To, InnerTo]
): (TransformationExpr[To], TransformationExpr[To]) => TransformationExpr[To] =
(texpr1, texpt2) => TransformationExpr.fromTotal(optionalTo.orElse(texpr1.ensureTotal, texpt2.ensureTotal))

Check warning on line 122 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala#L122

Added line #L122 was not covered by tests

private def mergePartial[To: Type, InnerTo](
optionalTo: OptionalValue[To, InnerTo],
failFast: Expr[Boolean]
): (TransformationExpr[To], TransformationExpr[To]) => TransformationExpr[To] = {
case (TransformationExpr.TotalExpr(expr1), TransformationExpr.TotalExpr(expr2)) =>
TransformationExpr.fromTotal(optionalTo.orElse(expr1, expr2))
case (texpr1, texpr2) =>
TransformationExpr.fromPartial(
ChimneyExpr.PartialResult.map2(
texpr1.ensurePartial,
texpr2.ensurePartial,
Expr.Function2.instance(optionalTo.orElse(_, _)),

Check warning on line 135 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformOptionToOptionRuleModule.scala#L128-L135

Added lines #L128 - L135 were not covered by tests
failFast
)
)
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,16 @@ private[compiletime] trait TransformToOptionRuleModule { this: Derivation & Tran
): DerivationResult[Rule.ExpansionResult[To]] =
// We're constructing:
// '{ ${ derivedTo2 } /* created from Option(src) */ }
TransformOptionToOptionRule.expand(ctx.updateFromTo[Option[From], To](Expr.Option(ctx.src)))
TransformOptionToOptionRule.expand(
ctx.updateFromTo[Option[From], To](Expr.Option(ctx.src), updateFallbacks = wrapFallbacks)
)

private val wrapFallbacks: TransformerOverride.ForFallback => Vector[TransformerOverride.ForFallback] = {
case fb @ TransformerOverride.Fallback(fallback) =>
import fallback.{Underlying as Fallback, value as fallbackExpr}
Vector(Type[Fallback] match {
case OptionalValue(_) => fb
case _ => TransformerOverride.Fallback(Expr.Option(fallbackExpr).as_??)

Check warning on line 42 in chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformToOptionRuleModule.scala

View check run for this annotation

Codecov / codecov/patch

chimney/src/main/scala/io/scalaland/chimney/internal/compiletime/derivation/transformer/rules/TransformToOptionRuleModule.scala#L38-L42

Added lines #L38 - L42 were not covered by tests
})
}
}

0 comments on commit 668a3aa

Please sign in to comment.