Skip to content

Commit

Permalink
impl: RequireAllSourceFieldsUsed for scala2
Browse files Browse the repository at this point in the history
  • Loading branch information
nimatrueway committed Sep 29, 2024
1 parent 154d7fa commit 693ceff
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,18 @@ final class TransformerInto[From, To, Overrides <: TransformerOverrides, Flags <
): TransformerInto[From, To, ? <: TransformerOverrides, Flags] =
macro TransformerIntoMacros.withConstructorImpl[From, To, Overrides, Flags]

/** Require that all fields of the source object except fields mentioned in `selectorFrom` are used in the
* transformation. and fail compilation otherwise.
*
* @param selectorFrom
* exception fields that are not required to be used in the transformation
* @return
*/
def requireSourceFieldsUsedExcept[T, U](
selectorFrom: From => Any*
): TransformerInto[From, To, ? <: TransformerOverrides, Flags] =
macro TransformerIntoMacros.requireSourceFieldsUsedExceptImpl[From, To, Overrides, Flags]

/** Apply configured transformation in-place.
*
* It runs macro that tries to derive instance of `Transformer[From, To]` and immediately apply it to captured
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,17 @@ private[compiletime] trait ChimneyTypesPlatform extends ChimneyTypes { this: Chi
)
}
}
object RequireSourceFieldsExcept extends RequireSourceFieldsExceptModule {
def apply[
FromPathList <: runtime.PathList: Type,
Tail <: runtime.TransformerOverrides: Type
]: Type[runtime.TransformerOverrides.RequireSourceFieldsExcept[FromPathList, Tail]] =
weakTypeTag[runtime.TransformerOverrides.RequireSourceFieldsExcept[FromPathList, Tail]]
def unapply[A](A: Type[A]): Option[(?<[runtime.PathList], ?<[runtime.TransformerOverrides])] =
A.asCtor[runtime.TransformerOverrides.RequireSourceFieldsExcept[?, ?]].map { A0 =>
(A0.param_<[runtime.PathList](0), A0.param_<[runtime.TransformerOverrides](1))
}
}
}

object TransformerFlags extends TransformerFlagsModule {
Expand Down Expand Up @@ -406,6 +417,17 @@ private[compiletime] trait ChimneyTypesPlatform extends ChimneyTypes { this: Chi
}
}

object PathList extends PathListModule {
val Empty: Type[runtime.PathList.Empty] = weakTypeTag[runtime.PathList.Empty]
object List extends ListModule {
def apply[Head <: runtime.Path: Type, Tail <: runtime.PathList: Type]: Type[runtime.PathList.List[Head, Tail]] =
weakTypeTag[runtime.PathList.List[Head, Tail]]
def unapply[A](A: Type[A]): Option[(?<[runtime.Path], ?<[runtime.PathList])] =
A.asCtor[runtime.PathList.List[?, ?]]
.map(A0 => A0.param_<[runtime.Path](0) -> A0.param_<[runtime.PathList](1))
}
}

object DefaultValue extends DefaultValueModule {
def apply[Value: Type]: Type[integrations.DefaultValue[Value]] =
weakTypeTag[integrations.DefaultValue[Value]]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.scalaland.chimney.internal.compiletime.dsl

import io.scalaland.chimney.dsl.TransformerInto
import io.scalaland.chimney.internal.runtime.{ArgumentLists, Path, TransformerFlags, TransformerOverrides}
import io.scalaland.chimney.internal.runtime.{ArgumentLists, Path, PathList, TransformerFlags, TransformerOverrides}
import io.scalaland.chimney.internal.runtime.TransformerOverrides.*

import scala.annotation.unused
Expand Down Expand Up @@ -96,4 +96,17 @@ class TransformerIntoMacros(val c: whitebox.Context) extends utils.DslMacroUtils
.addOverride(f)
.asInstanceOfExpr[TransformerInto[From, To, Constructor[Args, Path.Root, Overrides], Flags]]
}.applyFromBody(f)

def requireSourceFieldsUsedExceptImpl[
From: WeakTypeTag,
To: WeakTypeTag,
Overrides <: TransformerOverrides: WeakTypeTag,
Flags <: TransformerFlags: WeakTypeTag
](selectorFrom: Tree*): Tree = c.prefix.tree
.asInstanceOfExpr(
new ApplyFieldNamesType {
def apply[FromPathList <: PathList: WeakTypeTag]: c.WeakTypeTag[?] =
weakTypeTag[TransformerInto[From, To, RequireSourceFieldsExcept[FromPathList, Overrides], Flags]]
}.applyFromSelector(selectorFrom)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,99 @@ private[chimney] trait DslMacroUtils {
s"Expected function, instead got: $MAGENTA$t$RESET: $MAGENTA${t.tpe}$RESET"
}

private trait ExistentialPathList {
type Underlying <: runtime.PathList
val Underlying: c.WeakTypeTag[Underlying]
}
private object ExistentialPathList {
def parse(selectors: Seq[Tree]): Either[String, ExistentialPathList] =
selectors
.map(selector => ExistentialPath.parse(selector))
.foldLeft[Either[String, List[ExistentialPath]]](Right(Nil)) {
case (err @ Left(_), _) => err
case (_, Left(error)) => Left(error)
case (Right(acc), Right(path)) => Right(acc :+ path)
}
.map { params =>
new ExistentialPathList {
type Underlying = runtime.PathList
implicit val Underlying: WeakTypeTag[Underlying] = combine(params)
}
}

private def combine(paths: Seq[ExistentialPath]): WeakTypeTag[runtime.PathList] = {
object Combine {
def apply[A <: runtime.Path: WeakTypeTag, Args <: runtime.PathList: WeakTypeTag]
: WeakTypeTag[runtime.PathList.List[A, Args]] =
weakTypeTag[runtime.PathList.List[A, Args]]
}

paths
.foldLeft[WeakTypeTag[? <: runtime.PathList]](weakTypeTag[runtime.PathList.Empty]) { (acc, path) =>
Combine(path.Underlying, acc)
}
.asInstanceOf[WeakTypeTag[runtime.PathList]]
}

// selectors
// .map(ExistentialPath.parse)
//
// extractParams(t).map { params =>
// new ExistentialCtor {
// type Underlying = runtime.ArgumentLists
// implicit val Underlying: WeakTypeTag[runtime.ArgumentLists] = paramsToType(params)
// }
// }
// }
//
// private def paramsToType(paramsLists: List[List[ValDef]]): WeakTypeTag[runtime.ArgumentLists] =
// paramsLists
// .map { paramList =>
// paramList.foldRight[WeakTypeTag[? <: runtime.ArgumentList]](weakTypeTag[runtime.ArgumentList.Empty])(
// constructArgumentListType
// )
// }
// .foldRight[WeakTypeTag[? <: runtime.ArgumentLists]](weakTypeTag[runtime.ArgumentLists.Empty])(
// constructArgumentListsType
// )
// .asInstanceOf[WeakTypeTag[runtime.ArgumentLists]]
//
// private def constructArgumentListsType(
// head: WeakTypeTag[? <: runtime.ArgumentList],
// tail: WeakTypeTag[? <: runtime.ArgumentLists]
// ): WeakTypeTag[? <: runtime.ArgumentLists] = {
// object ApplyParams {
// def apply[Head <: runtime.ArgumentList: WeakTypeTag, Tail <: runtime.ArgumentLists: WeakTypeTag]
// : WeakTypeTag[runtime.ArgumentLists.List[Head, Tail]] =
// weakTypeTag[runtime.ArgumentLists.List[Head, Tail]]
// }
//
// ApplyParams(head, tail)
// }
//
// private def constructArgumentListType(
// t: ValDef,
// args: WeakTypeTag[? <: runtime.ArgumentList]
// ): WeakTypeTag[? <: runtime.ArgumentList] = {
// object ApplyParam {
// def apply[ParamName <: String: WeakTypeTag, ParamType: WeakTypeTag, Args <: runtime.ArgumentList: WeakTypeTag]
// : WeakTypeTag[runtime.ArgumentList.Argument[ParamName, ParamType, Args]] =
// weakTypeTag[runtime.ArgumentList.Argument[ParamName, ParamType, Args]]
// }
//
// ApplyParam(
// c.WeakTypeTag(c.internal.constantType(Constant(t.name.decodedName.toString))),
// c.WeakTypeTag(t.tpt.tpe),
// args
// )
// }
//
// import Console.*
//
// private def invalidConstructor(t: Tree): String =
// s"Expected function, instead got: $MAGENTA$t$RESET: $MAGENTA${t.tpe}$RESET"
}

// If we try to do:
//
// implicit val toPath = fieldName.Underlying
Expand Down Expand Up @@ -304,6 +397,16 @@ private[chimney] trait DslMacroUtils {
}
}

protected trait ApplyFieldNamesType {
def apply[A <: runtime.PathList: WeakTypeTag]: WeakTypeTag[?]

final def applyFromSelector(t: Seq[Tree]): WeakTypeTag[?] =
apply(extractSelectorAsType(t).Underlying)

private def extractSelectorAsType(t: Seq[Tree]): ExistentialPathList =
ExistentialPathList.parse(t).fold(error => c.abort(c.enclosingPosition, error), path => path)
}

/** Workaround for Java Enums, see [[io.scalaland.chimney.internal.runtime.RefinedJavaEnum]]. */
protected trait ApplyFixedCoproductType {

Expand Down

0 comments on commit 693ceff

Please sign in to comment.