From fd8808530509559acfb765bad9c9ade40e4c44a9 Mon Sep 17 00:00:00 2001 From: Roman-Statsura Date: Wed, 8 May 2024 11:33:05 +0400 Subject: [PATCH 1/4] Add support Scala 3 for module derivation --- build.sbt | 11 ++- .../scala-2/tofu/common/derived/display.scala | 5 +- .../tofu/data/derived/InitDerivation.scala | 4 +- .../scala-2/tofu/data/derived/Merge.scala | 10 +-- .../tofu/higherKind/derived/derived.scala | 7 +- .../main/scala-2/tofu/magnolia/compat.scala | 8 +++ .../scala-3/tofu/common/derived/display.scala | 67 ++++++++++++++++++ .../scala-3/tofu/common/derived/package.scala | 9 +++ .../scala-3/tofu/data/derived/Merge.scala | 70 +++++++++++++++++++ .../main/scala-3/tofu/magnolia/compat.scala | 8 +++ .../tofu/data/derived/MerkatorFromCats.scala | 0 .../tofu/data/derived/package.scala | 0 .../higherKind/derived/ContextEmbed.scala | 0 .../tofu/syntax/merge.scala | 0 .../tofu/common/derived/DisplayData.scala | 40 +++++++++++ .../scala-2/tofu/data/derived/MergeData.scala | 11 +++ .../tofu/higherKind/derived/EmbedSuite.scala | 13 ++-- .../derived/RepresentableKSuite.scala | 20 +++--- .../derived/RepresentableKVarArgSuite.scala | 6 +- .../tofu/common/derived/DisplayData.scala | 34 +++++++++ .../scala-3/tofu/data/derived/MergeData.scala | 8 +++ .../tofu/common/derived/DisplaySpec.scala | 35 +--------- .../tofu/data/derived/MergeSuite.scala | 16 ++--- 23 files changed, 303 insertions(+), 79 deletions(-) create mode 100644 modules/derivation/src/main/scala-2/tofu/magnolia/compat.scala create mode 100644 modules/derivation/src/main/scala-3/tofu/common/derived/display.scala create mode 100644 modules/derivation/src/main/scala-3/tofu/common/derived/package.scala create mode 100644 modules/derivation/src/main/scala-3/tofu/data/derived/Merge.scala create mode 100644 modules/derivation/src/main/scala-3/tofu/magnolia/compat.scala rename modules/derivation/src/main/{scala-2 => scala}/tofu/data/derived/MerkatorFromCats.scala (100%) rename modules/derivation/src/main/{scala-2 => scala}/tofu/data/derived/package.scala (100%) rename modules/derivation/src/main/{scala-2 => scala}/tofu/higherKind/derived/ContextEmbed.scala (100%) rename modules/derivation/src/main/{scala-2 => scala}/tofu/syntax/merge.scala (100%) create mode 100644 modules/derivation/src/test/scala-2/tofu/common/derived/DisplayData.scala create mode 100644 modules/derivation/src/test/scala-2/tofu/data/derived/MergeData.scala create mode 100644 modules/derivation/src/test/scala-3/tofu/common/derived/DisplayData.scala create mode 100644 modules/derivation/src/test/scala-3/tofu/data/derived/MergeData.scala rename modules/derivation/src/test/{scala-2 => scala}/tofu/common/derived/DisplaySpec.scala (73%) rename modules/derivation/src/test/{scala-2 => scala}/tofu/data/derived/MergeSuite.scala (94%) diff --git a/build.sbt b/build.sbt index 17d9a573b..7f5914a33 100644 --- a/build.sbt +++ b/build.sbt @@ -322,10 +322,17 @@ lazy val derivation = projectMatrix .in(modules / "derivation") .settings( defaultSettings, - libraryDependencies ++= Seq(magnolia2, derevo, catsTaglessMacros), + scala3MigratedModuleOptions, + libraryDependencies ++= { + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, _)) => Seq(derevo, magnolia2, catsTaglessMacros) + case Some((3, _)) => Seq(magnolia3) + case _ => Seq.empty + } + }, name := "tofu-derivation", ) - .jvmPlatform(scala2Versions) + .jvmPlatform(scalaVersions = scala2And3Versions) .dependsOn(kernel) val zioInterop = modules / "interop" / "zio1" diff --git a/modules/derivation/src/main/scala-2/tofu/common/derived/display.scala b/modules/derivation/src/main/scala-2/tofu/common/derived/display.scala index 0194111df..3bdb8d059 100644 --- a/modules/derivation/src/main/scala-2/tofu/common/derived/display.scala +++ b/modules/derivation/src/main/scala-2/tofu/common/derived/display.scala @@ -4,6 +4,7 @@ import cats.Eval import derevo.Derivation import magnolia1.{CaseClass, Magnolia, SealedTrait} import tofu.common.Display +import tofu.magnolia.compat /** Derivation of [[Display]] typeclass for case classes and sealed traits * @@ -16,7 +17,7 @@ object display extends Derivation[Display] { private type Typeclass[T] = Display[T] def join[T](ctx: CaseClass[Typeclass, T]): Display[T] = (cfg: Display.Config, a: T) => { - import cfg.{fieldSeparator, indent, brackets, fieldAssign, newline} + import cfg.* val nestedIndent = indent + indent @@ -46,7 +47,7 @@ object display extends Derivation[Display] { alreadyDisplayed <- acc nestedCfg = cfg.copy(indent = nestedIndent, brackets = brackets.copy(right = indent + brackets.right)) label = if (cfg.showFieldLabels) current.label + fieldAssign else "" - displayedParameterValue <- current.typeclass.displayBuild(nestedCfg, current.dereference(a)) + displayedParameterValue <- current.typeclass.displayBuild(nestedCfg, compat.deref[Typeclass, T](current)(a)) // this value has at least one element in it by construction, // but we avoid using NEVector here due to performance and simplicity adapted :+ value = adaptDisplayedParameter(label, displayedParameterValue) diff --git a/modules/derivation/src/main/scala-2/tofu/data/derived/InitDerivation.scala b/modules/derivation/src/main/scala-2/tofu/data/derived/InitDerivation.scala index d0ef4187e..b085d9d6f 100644 --- a/modules/derivation/src/main/scala-2/tofu/data/derived/InitDerivation.scala +++ b/modules/derivation/src/main/scala-2/tofu/data/derived/InitDerivation.scala @@ -1,8 +1,8 @@ package tofu.data.derived + import cats.Monad import derevo.Derivation -import magnolia1.{CaseClass, Magnolia} -import magnolia1.Monadic +import magnolia1.{CaseClass, Magnolia, Monadic} import tofu.Init class InitDerivation[F[_]: Monad] extends Derivation[Init[F, *]] { diff --git a/modules/derivation/src/main/scala-2/tofu/data/derived/Merge.scala b/modules/derivation/src/main/scala-2/tofu/data/derived/Merge.scala index 8913d95af..3a2bccd3e 100644 --- a/modules/derivation/src/main/scala-2/tofu/data/derived/Merge.scala +++ b/modules/derivation/src/main/scala-2/tofu/data/derived/Merge.scala @@ -1,13 +1,14 @@ package tofu.data package derived -import java.time.{Instant, LocalDate, LocalDateTime, ZonedDateTime} import cats.kernel.Semigroup -import magnolia1.{CaseClass, Magnolia, SealedTrait} import derevo.Derivation +import magnolia1.{CaseClass, Magnolia, SealedTrait} import tofu.compat.unused - import tofu.internal.DataComp +import tofu.magnolia.compat + +import java.time.{Instant, LocalDate, LocalDateTime, ZonedDateTime} trait Merge[A] { def merge(a: A, b: A): A @@ -17,7 +18,8 @@ trait MergeInstances1 { type Typeclass[A] = Merge[A] def join[T](caseClass: CaseClass[Typeclass, T]): Typeclass[T] = - (a, b) => caseClass.construct(p => p.typeclass.merge(p.dereference(a), p.dereference(b))) + (a, b) => + caseClass.construct(p => p.typeclass.merge(compat.deref[Typeclass, T](p)(a), compat.deref[Typeclass, T](p)(b))) def split[T](sealedTrait: SealedTrait[Typeclass, T]): Typeclass[T] = (a, b) => sealedTrait.split(a) { h => if (h.cast.isDefinedAt(b)) h.typeclass.merge(h.cast(a), h.cast(b)) else a } diff --git a/modules/derivation/src/main/scala-2/tofu/higherKind/derived/derived.scala b/modules/derivation/src/main/scala-2/tofu/higherKind/derived/derived.scala index 2f10b21b3..454d66434 100644 --- a/modules/derivation/src/main/scala-2/tofu/higherKind/derived/derived.scala +++ b/modules/derivation/src/main/scala-2/tofu/higherKind/derived/derived.scala @@ -1,9 +1,8 @@ package tofu.higherKind.derived -import derevo.DerivationK2 + +import derevo.{DerivationK2, DerivationKN11} +import tofu.higherKind.bi.{EmbedBK, RepresentableB} import tofu.higherKind.{Embed, RepresentableK} -import derevo.DerivationKN11 -import tofu.higherKind.bi.RepresentableB -import tofu.higherKind.bi.EmbedBK object representableK extends DerivationK2[RepresentableK] { def instance[T[_[_]]]: RepresentableK[T] = macro HigherKindedMacros.representableK[T] diff --git a/modules/derivation/src/main/scala-2/tofu/magnolia/compat.scala b/modules/derivation/src/main/scala-2/tofu/magnolia/compat.scala new file mode 100644 index 000000000..bf15cf9e4 --- /dev/null +++ b/modules/derivation/src/main/scala-2/tofu/magnolia/compat.scala @@ -0,0 +1,8 @@ +package tofu.magnolia + +object compat { + type Param[Typeclass[_], Type] = magnolia1.Param[Typeclass, Type] + + def deref[Typeclass[_], Type](p: Param[Typeclass, Type]): Type => p.PType = tpe => p.dereference(tpe) + +} diff --git a/modules/derivation/src/main/scala-3/tofu/common/derived/display.scala b/modules/derivation/src/main/scala-3/tofu/common/derived/display.scala new file mode 100644 index 000000000..24aacf55d --- /dev/null +++ b/modules/derivation/src/main/scala-3/tofu/common/derived/display.scala @@ -0,0 +1,67 @@ +package tofu.common.derived + +import cats.Eval +import magnolia1.* +import tofu.common.Display +import tofu.magnolia.compat +import scala.deriving.Mirror + + +/** Derivation of [[Display]] typeclass for case classes and sealed traits + * + * @note + * Derived [[Display]] instances will indent nested structures if those are supposed to be on newline. You can see + * examples in the tests. + */ +object display extends AutoDerivation[Display] { + + private type Typeclass[T] = Display[T] + + def join[T](ctx: CaseClass[Typeclass, T]): Display[T] = (cfg: Display.Config, a: T) => { + import cfg.* + + val nestedIndent = indent + indent + + def adaptDisplayedParameter(label: String, displayedParameterValue: Vector[String]): Vector[String] = { + displayedParameterValue match { + case value +: Vector() => + Vector(indent + label + value) + case typeHeader +: innerValueParams => + val labeledTypeHeader = + indent + label + typeHeader + labeledTypeHeader +: innerValueParams // .map(indent + _) + case _ => Vector(indent + label) + } + } + + val shortName: String = ctx.typeInfo.short + + ctx.parameters.zipWithIndex + .foldLeft( + Eval.now( + Vector( + s"$shortName ${brackets.left}$newline", + ) + ) + ) { case (acc, (current, index)) => + for { + alreadyDisplayed <- acc + nestedCfg = cfg.copy(indent = nestedIndent, brackets = brackets.copy(right = indent + brackets.right)) + label = if (cfg.showFieldLabels) current.label + fieldAssign else "" + displayedParameterValue <- current.typeclass.displayBuild(nestedCfg, compat.deref[Typeclass, T](current)(a)) + // this value has at least one element in it by construction, + // but we avoid using NEVector here due to performance and simplicity + adapted :+ value = adaptDisplayedParameter(label, displayedParameterValue) + separator = if (index + 1 < ctx.parameters.size) fieldSeparator else "" + adaptedIndentedValueWithSeparator = value + separator + newline + separatedLabelValue = adapted :+ adaptedIndentedValueWithSeparator + } yield alreadyDisplayed ++: separatedLabelValue + } + .map(s => s :+ brackets.right) + } + def split[T](ctx: SealedTrait[Typeclass, T]): Display[T] = (cfg: Display.Config, a: T) => + ctx.choose(a)(adtCase => adtCase.typeclass.displayBuild(cfg, adtCase.cast(a))) + + inline def instance[T](using Mirror.Of[T]): Display[T] = autoDerived[T] + +} diff --git a/modules/derivation/src/main/scala-3/tofu/common/derived/package.scala b/modules/derivation/src/main/scala-3/tofu/common/derived/package.scala new file mode 100644 index 000000000..849849930 --- /dev/null +++ b/modules/derivation/src/main/scala-3/tofu/common/derived/package.scala @@ -0,0 +1,9 @@ +package tofu.common + +import scala.deriving.Mirror + + +package object derived { + extension (x: Display.type) inline def derived[A](using Mirror.Of[A]): Display[A] = display.derived[A] + +} diff --git a/modules/derivation/src/main/scala-3/tofu/data/derived/Merge.scala b/modules/derivation/src/main/scala-3/tofu/data/derived/Merge.scala new file mode 100644 index 000000000..829c494ab --- /dev/null +++ b/modules/derivation/src/main/scala-3/tofu/data/derived/Merge.scala @@ -0,0 +1,70 @@ +package tofu.data.derived + +import cats.kernel.Semigroup +import magnolia1.* +import tofu.compat.unused +import tofu.internal.DataComp +import tofu.magnolia.compat +import scala.deriving.Mirror + +import java.time.{Instant, LocalDate, LocalDateTime, ZonedDateTime} + +trait Merge[A] { + def merge(a: A, b: A): A +} + +trait MergeInstances1 { + type Typeclass[A] = Merge[A] + + def join[T](caseClass: CaseClass[Typeclass, T]): Typeclass[T] = + (a, b) => + caseClass.construct(p => p.typeclass.merge(compat.deref[Typeclass, T](p)(a), compat.deref[Typeclass, T](p)(b))) + + def split[T](sealedTrait: SealedTrait[Typeclass, T]): Typeclass[T] = + (a, b) => sealedTrait.choose(a) { h => if (h.cast.isDefinedAt(b)) h.typeclass.merge(h.cast(a), h.cast(b)) else a } + +} + +object Merge extends AutoDerivation[Merge] with MergeInstances1 with DataComp[Merge] { + implicit def optionInstance[A](implicit m: Merge[A]): Merge[Option[A]] = + (ao, bo) => ao.fold(bo)(a => bo.fold(ao)(b => Some(m.merge(a, b)))) + + implicit def primitiveInstance[A](implicit @unused ev: Primitive[A]): Merge[A] = (a: A, _: A) => a + + inline def instance[A](using Mirror.Of[A]): Merge[A] = autoDerived[A] + + val ops: tofu.syntax.merge.type = tofu.syntax.merge + + sealed class Primitive[A] + implicit object primitiveByte extends Primitive[Byte] + implicit object primitiveShort extends Primitive[Short] + implicit object primitiveInt extends Primitive[Int] + implicit object primitiveLong extends Primitive[Long] + implicit object primitiveChar extends Primitive[Char] + implicit object primitiveFloat extends Primitive[Float] + implicit object primitiveDouble extends Primitive[Double] + implicit object primitiveUnit extends Primitive[Unit] + implicit object primitiveBigDecimal extends Primitive[BigDecimal] + implicit object primitiveBigInt extends Primitive[BigInt] + implicit object primitiveLocalDateTime extends Primitive[LocalDateTime] + implicit object primitiveZonedDateTime extends Primitive[ZonedDateTime] + implicit object primitiveLocalDate extends Primitive[LocalDate] + implicit object primitiveInstant extends Primitive[Instant] + implicit object primitiveString extends Primitive[String] +} + +object Merged { + trait OpaqueTag extends Any + type Base = Any { type MergedOpaque } + + type Mer[A] <: Base with OpaqueTag + + def apply[A](value: A): Mer[A] = value.asInstanceOf[Mer[A]] + + implicit final class MergedOps[A](private val mer: Mer[A]) extends AnyVal { + def value: A = mer.asInstanceOf[A] + } + + implicit def mergedSemigroup[A: Merge]: Semigroup[Merged[A]] = + (x, y) => apply(Merge[A].merge(x.value, y.value)) +} diff --git a/modules/derivation/src/main/scala-3/tofu/magnolia/compat.scala b/modules/derivation/src/main/scala-3/tofu/magnolia/compat.scala new file mode 100644 index 000000000..a31e41a7f --- /dev/null +++ b/modules/derivation/src/main/scala-3/tofu/magnolia/compat.scala @@ -0,0 +1,8 @@ +package tofu.magnolia + +object compat { + type Param[Typeclass[_], Type] = magnolia1.CaseClass.Param[Typeclass, Type] + + def deref[Typeclass[_], Type](p: Param[Typeclass, Type]): Type => p.PType = tpe => p.deref(tpe) + +} diff --git a/modules/derivation/src/main/scala-2/tofu/data/derived/MerkatorFromCats.scala b/modules/derivation/src/main/scala/tofu/data/derived/MerkatorFromCats.scala similarity index 100% rename from modules/derivation/src/main/scala-2/tofu/data/derived/MerkatorFromCats.scala rename to modules/derivation/src/main/scala/tofu/data/derived/MerkatorFromCats.scala diff --git a/modules/derivation/src/main/scala-2/tofu/data/derived/package.scala b/modules/derivation/src/main/scala/tofu/data/derived/package.scala similarity index 100% rename from modules/derivation/src/main/scala-2/tofu/data/derived/package.scala rename to modules/derivation/src/main/scala/tofu/data/derived/package.scala diff --git a/modules/derivation/src/main/scala-2/tofu/higherKind/derived/ContextEmbed.scala b/modules/derivation/src/main/scala/tofu/higherKind/derived/ContextEmbed.scala similarity index 100% rename from modules/derivation/src/main/scala-2/tofu/higherKind/derived/ContextEmbed.scala rename to modules/derivation/src/main/scala/tofu/higherKind/derived/ContextEmbed.scala diff --git a/modules/derivation/src/main/scala-2/tofu/syntax/merge.scala b/modules/derivation/src/main/scala/tofu/syntax/merge.scala similarity index 100% rename from modules/derivation/src/main/scala-2/tofu/syntax/merge.scala rename to modules/derivation/src/main/scala/tofu/syntax/merge.scala diff --git a/modules/derivation/src/test/scala-2/tofu/common/derived/DisplayData.scala b/modules/derivation/src/test/scala-2/tofu/common/derived/DisplayData.scala new file mode 100644 index 000000000..104a36abf --- /dev/null +++ b/modules/derivation/src/test/scala-2/tofu/common/derived/DisplayData.scala @@ -0,0 +1,40 @@ +package tofu.common.derived + +import cats.Eval +import derevo.derive +import tofu.common.Display +import tofu.common.Display.Config + +object DisplayData { + @derive(display) + case class Bar(value: Int, another: String) + + @derive(display) + case class Foo(bar: Bar, field: Double, xs: List[Int]) + + @derive(display) + sealed trait FooBar + object FooBar { + case class Barn(i: Int) extends FooBar + case class Darn(j: Double) extends FooBar + } + + case class Emptiness() + object Emptiness { + implicit val displayEmptiness: Display[Emptiness] = + (_: Config, _: Emptiness) => Eval.now(Vector.empty[String]) + } + + @derive(display) + case class Bjarn(i: Emptiness) + + case class Nested(a: Int, b: Int, c: Int) + object Nested { + implicit val displayNested: Display[Nested] = + (_: Config, ns: Nested) => Eval.now(Vector("Nested {", s"a = ${ns.a}, ", s"b = ${ns.b}, ", s"c = ${ns.c}", "}")) + } + + @derive(display) + case class Cont(a: Int, b: Nested) + +} diff --git a/modules/derivation/src/test/scala-2/tofu/data/derived/MergeData.scala b/modules/derivation/src/test/scala-2/tofu/data/derived/MergeData.scala new file mode 100644 index 000000000..44d9247a2 --- /dev/null +++ b/modules/derivation/src/test/scala-2/tofu/data/derived/MergeData.scala @@ -0,0 +1,11 @@ +package tofu.data.derived + +import derevo.derive + +object MergeData { + @derive(Merge) + final case class Foo(a: Int, b: Option[String], c: Option[Double]) + + @derive(Merge) + final case class Bar(x: Foo, y: Option[Foo]) +} diff --git a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/EmbedSuite.scala b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/EmbedSuite.scala index 2097e6486..4a3baff15 100644 --- a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/EmbedSuite.scala +++ b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/EmbedSuite.scala @@ -5,12 +5,13 @@ import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import cats.data.OptionT import EmbedSuite.Foo -import tofu.syntax.monadic._ -import tofu.syntax.embed._ -import cats.instances.either._ -import cats.instances.option._ -import cats.syntax.traverse._ -import cats.syntax.either._ +import tofu.syntax.monadic.* +import tofu.syntax.embed.* +import cats.instances.either.* +import cats.instances.option.* +import cats.syntax.traverse.* +import cats.syntax.either.* + import scala.util.Try class EmbedSuite extends AnyFlatSpec with Matchers { diff --git a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKSuite.scala b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKSuite.scala index 997f5fd10..bd819161b 100644 --- a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKSuite.scala +++ b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKSuite.scala @@ -1,21 +1,21 @@ package tofu.higherKind.derived -import RepresentableKSuite.{Foo} +import RepresentableKSuite.Foo import cats.data.{OptionT, Tuple2K} -import cats.instances.either._ -import cats.instances.option._ -import cats.syntax.either._ -import cats.syntax.functor._ -import cats.syntax.traverse._ -import cats.syntax.option._ -import cats.tagless.syntax.functorK._ -import cats.tagless.syntax.semigroupalK._ +import cats.instances.either.* +import cats.instances.option.* +import cats.syntax.either.* +import cats.syntax.functor.* +import cats.syntax.traverse.* +import cats.syntax.option.* +import cats.tagless.syntax.functorK.* +import cats.tagless.syntax.semigroupalK.* import cats.{Id, ~>} import derevo.derive import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import tofu.data.Embedded -import tofu.syntax.embed._ +import tofu.syntax.embed.* import tofu.syntax.funk.funK import scala.util.Try diff --git a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKVarArgSuite.scala b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKVarArgSuite.scala index 7824dc274..944c44d0e 100644 --- a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKVarArgSuite.scala +++ b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKVarArgSuite.scala @@ -3,9 +3,9 @@ package tofu.higherKind.derived import cats.data.Tuple2K import cats.{Id, ~>} import derevo.derive -import tofu.syntax.embed._ -import cats.tagless.syntax.functorK._ -import cats.tagless.syntax.semigroupalK._ +import tofu.syntax.embed.* +import cats.tagless.syntax.functorK.* +import cats.tagless.syntax.semigroupalK.* import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import tofu.higherKind.derived.RepresentableKVarArgSuite.Foo diff --git a/modules/derivation/src/test/scala-3/tofu/common/derived/DisplayData.scala b/modules/derivation/src/test/scala-3/tofu/common/derived/DisplayData.scala new file mode 100644 index 000000000..861631ff6 --- /dev/null +++ b/modules/derivation/src/test/scala-3/tofu/common/derived/DisplayData.scala @@ -0,0 +1,34 @@ +package tofu.common.derived + +import cats.Eval +import tofu.common.Display +import tofu.common.Display.Config + +object DisplayData { + + case class Bar(value: Int, another: String) derives Display + + case class Foo(bar: Bar, field: Double, xs: List[Int]) derives Display + + sealed trait FooBar derives Display + object FooBar { + case class Barn(i: Int) extends FooBar + case class Darn(j: Double) extends FooBar + } + + case class Emptiness() + object Emptiness { + implicit val displayEmptiness: Display[Emptiness] = + (_: Config, _: Emptiness) => Eval.now(Vector.empty[String]) + } + + case class Bjarn(i: Emptiness) derives Display + + case class Nested(a: Int, b: Int, c: Int) + object Nested { + implicit val displayNested: Display[Nested] = + (_: Config, ns: Nested) => Eval.now(Vector("Nested {", s"a = ${ns.a}, ", s"b = ${ns.b}, ", s"c = ${ns.c}", "}")) + } + + case class Cont(a: Int, b: Nested) derives Display +} diff --git a/modules/derivation/src/test/scala-3/tofu/data/derived/MergeData.scala b/modules/derivation/src/test/scala-3/tofu/data/derived/MergeData.scala new file mode 100644 index 000000000..37d155879 --- /dev/null +++ b/modules/derivation/src/test/scala-3/tofu/data/derived/MergeData.scala @@ -0,0 +1,8 @@ +package tofu.data.derived + + +object MergeData { + final case class Foo(a: Int, b: Option[String], c: Option[Double]) derives Merge + + final case class Bar(x: Foo, y: Option[Foo]) derives Merge +} diff --git a/modules/derivation/src/test/scala-2/tofu/common/derived/DisplaySpec.scala b/modules/derivation/src/test/scala/tofu/common/derived/DisplaySpec.scala similarity index 73% rename from modules/derivation/src/test/scala-2/tofu/common/derived/DisplaySpec.scala rename to modules/derivation/src/test/scala/tofu/common/derived/DisplaySpec.scala index 79bb54cd7..f792c8e5f 100644 --- a/modules/derivation/src/test/scala-2/tofu/common/derived/DisplaySpec.scala +++ b/modules/derivation/src/test/scala/tofu/common/derived/DisplaySpec.scala @@ -1,21 +1,14 @@ package tofu.common.derived -import cats.Eval -import derevo.derive import org.scalatest.funspec.AnyFunSpec import org.scalatest.matchers.should.Matchers import tofu.common.Display import tofu.common.Display._ +import tofu.common.derived.DisplayData._ class DisplaySpec extends AnyFunSpec with Matchers { describe("derivation") { - @derive(display) - case class Bar(value: Int, another: String) - - @derive(display) - case class Foo(bar: Bar, field: Double, xs: List[Int]) - describe("simple cases") { val bar = Bar( 3, @@ -50,25 +43,11 @@ class DisplaySpec extends AnyFunSpec with Matchers { } it("should display sealed traits") { - @derive(display) - sealed trait FooBar - object FooBar { - case class Barn(i: Int) extends FooBar - case class Darn(j: Double) extends FooBar - } val adt: FooBar = FooBar.Barn(3) adt.display() shouldBe "Barn {\n\ti = 3\n}" } it("should display empty display as empty string") { - case class Emptiness() - object Emptiness { - implicit val displayEmptiness: Display[Emptiness] = - (_: Config, _: Emptiness) => Eval.now(Vector.empty[String]) - } - - @derive(display) - case class Bjarn(i: Emptiness) Bjarn(Emptiness()).display() shouldBe "Bjarn {\n\ti = \n}" } @@ -115,18 +94,6 @@ class DisplaySpec extends AnyFunSpec with Matchers { } it("should display nested non newlined case classes without indents") { - - case class Nested(a: Int, b: Int, c: Int) - - object Nested { - implicit val displayNested: Display[Nested] = - (_: Config, ns: Nested) => - Eval.now(Vector("Nested {", s"a = ${ns.a}, ", s"b = ${ns.b}, ", s"c = ${ns.c}", "}")) - } - - @derive(display) - case class Cont(a: Int, b: Nested) - val cont: Cont = Cont(4, Nested(5, 6, 7)) val expectedCont: String = """Cont { diff --git a/modules/derivation/src/test/scala-2/tofu/data/derived/MergeSuite.scala b/modules/derivation/src/test/scala/tofu/data/derived/MergeSuite.scala similarity index 94% rename from modules/derivation/src/test/scala-2/tofu/data/derived/MergeSuite.scala rename to modules/derivation/src/test/scala/tofu/data/derived/MergeSuite.scala index e1fe45f50..7407aef6a 100644 --- a/modules/derivation/src/test/scala-2/tofu/data/derived/MergeSuite.scala +++ b/modules/derivation/src/test/scala/tofu/data/derived/MergeSuite.scala @@ -1,12 +1,11 @@ package tofu.data.derived -import java.time.LocalDate - import cats.syntax.option._ -import derevo.derive -import MergeSuite.{Bar, Foo} import org.scalatest.flatspec.AnyFlatSpec -import Merge.ops._ +import tofu.data.derived.Merge.ops._ +import tofu.data.derived.MergeData._ + +import java.time.LocalDate class MergeSuite extends AnyFlatSpec { "simple merge" should "prefer left value" in { @@ -179,10 +178,3 @@ class MergeSuite extends AnyFlatSpec { } -object MergeSuite { - @derive(Merge) - final case class Foo(a: Int, b: Option[String], c: Option[Double]) - - @derive(Merge) - final case class Bar(x: Foo, y: Option[Foo]) -} From f00daca5293d054162ffd54ff546395ade782495 Mon Sep 17 00:00:00 2001 From: Roman-Statsura Date: Wed, 8 May 2024 12:46:28 +0400 Subject: [PATCH 2/4] moved common for display and merge --- ...play.scala => DisplayDerivationImpl.scala} | 10 +-- .../tofu/data/derived/MergeInstances1.scala | 19 +++++ ...play.scala => DisplayDerivationImpl.scala} | 8 +-- .../scala-3/tofu/common/derived/package.scala | 4 +- .../scala-3/tofu/data/derived/Merge.scala | 70 ------------------- .../tofu/data/derived/MergeInstances1.scala | 19 +++++ .../scala/tofu/common/derived/display.scala | 12 ++++ .../tofu/data/derived/Merge.scala | 21 +----- 8 files changed, 56 insertions(+), 107 deletions(-) rename modules/derivation/src/main/scala-2/tofu/common/derived/{display.scala => DisplayDerivationImpl.scala} (88%) create mode 100644 modules/derivation/src/main/scala-2/tofu/data/derived/MergeInstances1.scala rename modules/derivation/src/main/scala-3/tofu/common/derived/{display.scala => DisplayDerivationImpl.scala} (89%) delete mode 100644 modules/derivation/src/main/scala-3/tofu/data/derived/Merge.scala create mode 100644 modules/derivation/src/main/scala-3/tofu/data/derived/MergeInstances1.scala create mode 100644 modules/derivation/src/main/scala/tofu/common/derived/display.scala rename modules/derivation/src/main/{scala-2 => scala}/tofu/data/derived/Merge.scala (73%) diff --git a/modules/derivation/src/main/scala-2/tofu/common/derived/display.scala b/modules/derivation/src/main/scala-2/tofu/common/derived/DisplayDerivationImpl.scala similarity index 88% rename from modules/derivation/src/main/scala-2/tofu/common/derived/display.scala rename to modules/derivation/src/main/scala-2/tofu/common/derived/DisplayDerivationImpl.scala index 3bdb8d059..9cf7b6fec 100644 --- a/modules/derivation/src/main/scala-2/tofu/common/derived/display.scala +++ b/modules/derivation/src/main/scala-2/tofu/common/derived/DisplayDerivationImpl.scala @@ -6,18 +6,12 @@ import magnolia1.{CaseClass, Magnolia, SealedTrait} import tofu.common.Display import tofu.magnolia.compat -/** Derivation of [[Display]] typeclass for case classes and sealed traits - * - * @note - * Derived [[Display]] instances will indent nested structures if those are supposed to be on newline. You can see - * examples in the tests. - */ -object display extends Derivation[Display] { +trait DisplayDerivationImpl extends Derivation[Display] { private type Typeclass[T] = Display[T] def join[T](ctx: CaseClass[Typeclass, T]): Display[T] = (cfg: Display.Config, a: T) => { - import cfg.* + import cfg._ val nestedIndent = indent + indent diff --git a/modules/derivation/src/main/scala-2/tofu/data/derived/MergeInstances1.scala b/modules/derivation/src/main/scala-2/tofu/data/derived/MergeInstances1.scala new file mode 100644 index 000000000..511b17cac --- /dev/null +++ b/modules/derivation/src/main/scala-2/tofu/data/derived/MergeInstances1.scala @@ -0,0 +1,19 @@ +package tofu.data +package derived + +import derevo.Derivation +import magnolia1.{CaseClass, Magnolia, SealedTrait} +import tofu.magnolia.compat + +trait MergeInstances1 extends Derivation[Merge] { + type Typeclass[A] = Merge[A] + + def join[T](caseClass: CaseClass[Typeclass, T]): Typeclass[T] = + (a, b) => + caseClass.construct(p => p.typeclass.merge(compat.deref[Typeclass, T](p)(a), compat.deref[Typeclass, T](p)(b))) + + def split[T](sealedTrait: SealedTrait[Typeclass, T]): Typeclass[T] = + (a, b) => sealedTrait.split(a) { h => if (h.cast.isDefinedAt(b)) h.typeclass.merge(h.cast(a), h.cast(b)) else a } + + implicit def instance[A]: Merge[A] = macro Magnolia.gen[A] +} diff --git a/modules/derivation/src/main/scala-3/tofu/common/derived/display.scala b/modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala similarity index 89% rename from modules/derivation/src/main/scala-3/tofu/common/derived/display.scala rename to modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala index 24aacf55d..90f034d22 100644 --- a/modules/derivation/src/main/scala-3/tofu/common/derived/display.scala +++ b/modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala @@ -7,13 +7,7 @@ import tofu.magnolia.compat import scala.deriving.Mirror -/** Derivation of [[Display]] typeclass for case classes and sealed traits - * - * @note - * Derived [[Display]] instances will indent nested structures if those are supposed to be on newline. You can see - * examples in the tests. - */ -object display extends AutoDerivation[Display] { +trait DisplayDerivationImpl extends AutoDerivation[Display] { private type Typeclass[T] = Display[T] diff --git a/modules/derivation/src/main/scala-3/tofu/common/derived/package.scala b/modules/derivation/src/main/scala-3/tofu/common/derived/package.scala index 849849930..c82228d17 100644 --- a/modules/derivation/src/main/scala-3/tofu/common/derived/package.scala +++ b/modules/derivation/src/main/scala-3/tofu/common/derived/package.scala @@ -2,8 +2,6 @@ package tofu.common import scala.deriving.Mirror - package object derived { - extension (x: Display.type) inline def derived[A](using Mirror.Of[A]): Display[A] = display.derived[A] - + extension (x: Display.type) inline def derived[A](using Mirror.Of[A]): Display[A] = display.derived[A] } diff --git a/modules/derivation/src/main/scala-3/tofu/data/derived/Merge.scala b/modules/derivation/src/main/scala-3/tofu/data/derived/Merge.scala deleted file mode 100644 index 829c494ab..000000000 --- a/modules/derivation/src/main/scala-3/tofu/data/derived/Merge.scala +++ /dev/null @@ -1,70 +0,0 @@ -package tofu.data.derived - -import cats.kernel.Semigroup -import magnolia1.* -import tofu.compat.unused -import tofu.internal.DataComp -import tofu.magnolia.compat -import scala.deriving.Mirror - -import java.time.{Instant, LocalDate, LocalDateTime, ZonedDateTime} - -trait Merge[A] { - def merge(a: A, b: A): A -} - -trait MergeInstances1 { - type Typeclass[A] = Merge[A] - - def join[T](caseClass: CaseClass[Typeclass, T]): Typeclass[T] = - (a, b) => - caseClass.construct(p => p.typeclass.merge(compat.deref[Typeclass, T](p)(a), compat.deref[Typeclass, T](p)(b))) - - def split[T](sealedTrait: SealedTrait[Typeclass, T]): Typeclass[T] = - (a, b) => sealedTrait.choose(a) { h => if (h.cast.isDefinedAt(b)) h.typeclass.merge(h.cast(a), h.cast(b)) else a } - -} - -object Merge extends AutoDerivation[Merge] with MergeInstances1 with DataComp[Merge] { - implicit def optionInstance[A](implicit m: Merge[A]): Merge[Option[A]] = - (ao, bo) => ao.fold(bo)(a => bo.fold(ao)(b => Some(m.merge(a, b)))) - - implicit def primitiveInstance[A](implicit @unused ev: Primitive[A]): Merge[A] = (a: A, _: A) => a - - inline def instance[A](using Mirror.Of[A]): Merge[A] = autoDerived[A] - - val ops: tofu.syntax.merge.type = tofu.syntax.merge - - sealed class Primitive[A] - implicit object primitiveByte extends Primitive[Byte] - implicit object primitiveShort extends Primitive[Short] - implicit object primitiveInt extends Primitive[Int] - implicit object primitiveLong extends Primitive[Long] - implicit object primitiveChar extends Primitive[Char] - implicit object primitiveFloat extends Primitive[Float] - implicit object primitiveDouble extends Primitive[Double] - implicit object primitiveUnit extends Primitive[Unit] - implicit object primitiveBigDecimal extends Primitive[BigDecimal] - implicit object primitiveBigInt extends Primitive[BigInt] - implicit object primitiveLocalDateTime extends Primitive[LocalDateTime] - implicit object primitiveZonedDateTime extends Primitive[ZonedDateTime] - implicit object primitiveLocalDate extends Primitive[LocalDate] - implicit object primitiveInstant extends Primitive[Instant] - implicit object primitiveString extends Primitive[String] -} - -object Merged { - trait OpaqueTag extends Any - type Base = Any { type MergedOpaque } - - type Mer[A] <: Base with OpaqueTag - - def apply[A](value: A): Mer[A] = value.asInstanceOf[Mer[A]] - - implicit final class MergedOps[A](private val mer: Mer[A]) extends AnyVal { - def value: A = mer.asInstanceOf[A] - } - - implicit def mergedSemigroup[A: Merge]: Semigroup[Merged[A]] = - (x, y) => apply(Merge[A].merge(x.value, y.value)) -} diff --git a/modules/derivation/src/main/scala-3/tofu/data/derived/MergeInstances1.scala b/modules/derivation/src/main/scala-3/tofu/data/derived/MergeInstances1.scala new file mode 100644 index 000000000..9be75a4b6 --- /dev/null +++ b/modules/derivation/src/main/scala-3/tofu/data/derived/MergeInstances1.scala @@ -0,0 +1,19 @@ +package tofu.data.derived + +import magnolia1.* +import tofu.magnolia.compat +import scala.deriving.Mirror + + +trait MergeInstances1 extends AutoDerivation[Merge] { + type Typeclass[A] = Merge[A] + + def join[T](caseClass: CaseClass[Typeclass, T]): Typeclass[T] = + (a, b) => + caseClass.construct(p => p.typeclass.merge(compat.deref[Typeclass, T](p)(a), compat.deref[Typeclass, T](p)(b))) + + def split[T](sealedTrait: SealedTrait[Typeclass, T]): Typeclass[T] = + (a, b) => sealedTrait.choose(a) { h => if (h.cast.isDefinedAt(b)) h.typeclass.merge(h.cast(a), h.cast(b)) else a } + + inline def instance[A](using Mirror.Of[A]): Merge[A] = autoDerived[A] +} diff --git a/modules/derivation/src/main/scala/tofu/common/derived/display.scala b/modules/derivation/src/main/scala/tofu/common/derived/display.scala new file mode 100644 index 000000000..8e6155ede --- /dev/null +++ b/modules/derivation/src/main/scala/tofu/common/derived/display.scala @@ -0,0 +1,12 @@ +package tofu.common.derived + +import tofu.common.Display + + +/** Derivation of [[Display]] typeclass for case classes and sealed traits + * + * @note + * Derived [[Display]] instances will indent nested structures if those are supposed to be on newline. You can see + * examples in the tests. + */ +object display extends DisplayDerivationImpl diff --git a/modules/derivation/src/main/scala-2/tofu/data/derived/Merge.scala b/modules/derivation/src/main/scala/tofu/data/derived/Merge.scala similarity index 73% rename from modules/derivation/src/main/scala-2/tofu/data/derived/Merge.scala rename to modules/derivation/src/main/scala/tofu/data/derived/Merge.scala index 3a2bccd3e..244c2ad84 100644 --- a/modules/derivation/src/main/scala-2/tofu/data/derived/Merge.scala +++ b/modules/derivation/src/main/scala/tofu/data/derived/Merge.scala @@ -1,12 +1,8 @@ -package tofu.data -package derived +package tofu.data.derived import cats.kernel.Semigroup -import derevo.Derivation -import magnolia1.{CaseClass, Magnolia, SealedTrait} import tofu.compat.unused import tofu.internal.DataComp -import tofu.magnolia.compat import java.time.{Instant, LocalDate, LocalDateTime, ZonedDateTime} @@ -14,20 +10,7 @@ trait Merge[A] { def merge(a: A, b: A): A } -trait MergeInstances1 { - type Typeclass[A] = Merge[A] - - def join[T](caseClass: CaseClass[Typeclass, T]): Typeclass[T] = - (a, b) => - caseClass.construct(p => p.typeclass.merge(compat.deref[Typeclass, T](p)(a), compat.deref[Typeclass, T](p)(b))) - - def split[T](sealedTrait: SealedTrait[Typeclass, T]): Typeclass[T] = - (a, b) => sealedTrait.split(a) { h => if (h.cast.isDefinedAt(b)) h.typeclass.merge(h.cast(a), h.cast(b)) else a } - - implicit def instance[A]: Merge[A] = macro Magnolia.gen[A] -} - -object Merge extends Derivation[Merge] with MergeInstances1 with DataComp[Merge] { +object Merge extends MergeInstances1 with DataComp[Merge] { implicit def optionInstance[A](implicit m: Merge[A]): Merge[Option[A]] = (ao, bo) => ao.fold(bo)(a => bo.fold(ao)(b => Some(m.merge(a, b)))) From 6b43d323ffab1876df79bfcf54e45629b467b5be Mon Sep 17 00:00:00 2001 From: Roman-Statsura Date: Wed, 8 May 2024 13:01:04 +0400 Subject: [PATCH 3/4] scalafmt fix --- build.sbt | 2 +- .../common/derived/DisplayDerivationImpl.scala | 1 - .../tofu/data/derived/MergeInstances1.scala | 1 - .../scala/tofu/common/derived/display.scala | 11 +++++------ .../tofu/higherKind/derived/EmbedSuite.scala | 12 ++++++------ .../derived/RepresentableKSuite.scala | 18 +++++++++--------- .../derived/RepresentableKVarArgSuite.scala | 6 +++--- .../tofu/common/derived/DisplayData.scala | 2 +- .../scala-3/tofu/data/derived/MergeData.scala | 1 - .../scala/tofu/data/derived/MergeSuite.scala | 1 - 10 files changed, 25 insertions(+), 30 deletions(-) diff --git a/build.sbt b/build.sbt index 7f5914a33..a573edf40 100644 --- a/build.sbt +++ b/build.sbt @@ -327,7 +327,7 @@ lazy val derivation = projectMatrix CrossVersion.partialVersion(scalaVersion.value) match { case Some((2, _)) => Seq(derevo, magnolia2, catsTaglessMacros) case Some((3, _)) => Seq(magnolia3) - case _ => Seq.empty + case _ => Seq.empty } }, name := "tofu-derivation", diff --git a/modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala b/modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala index 90f034d22..2910e7b63 100644 --- a/modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala +++ b/modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala @@ -6,7 +6,6 @@ import tofu.common.Display import tofu.magnolia.compat import scala.deriving.Mirror - trait DisplayDerivationImpl extends AutoDerivation[Display] { private type Typeclass[T] = Display[T] diff --git a/modules/derivation/src/main/scala-3/tofu/data/derived/MergeInstances1.scala b/modules/derivation/src/main/scala-3/tofu/data/derived/MergeInstances1.scala index 9be75a4b6..4069ca4ca 100644 --- a/modules/derivation/src/main/scala-3/tofu/data/derived/MergeInstances1.scala +++ b/modules/derivation/src/main/scala-3/tofu/data/derived/MergeInstances1.scala @@ -4,7 +4,6 @@ import magnolia1.* import tofu.magnolia.compat import scala.deriving.Mirror - trait MergeInstances1 extends AutoDerivation[Merge] { type Typeclass[A] = Merge[A] diff --git a/modules/derivation/src/main/scala/tofu/common/derived/display.scala b/modules/derivation/src/main/scala/tofu/common/derived/display.scala index 8e6155ede..b923e37e2 100644 --- a/modules/derivation/src/main/scala/tofu/common/derived/display.scala +++ b/modules/derivation/src/main/scala/tofu/common/derived/display.scala @@ -2,11 +2,10 @@ package tofu.common.derived import tofu.common.Display - /** Derivation of [[Display]] typeclass for case classes and sealed traits - * - * @note - * Derived [[Display]] instances will indent nested structures if those are supposed to be on newline. You can see - * examples in the tests. - */ + * + * @note + * Derived [[Display]] instances will indent nested structures if those are supposed to be on newline. You can see + * examples in the tests. + */ object display extends DisplayDerivationImpl diff --git a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/EmbedSuite.scala b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/EmbedSuite.scala index 4a3baff15..8b301ce74 100644 --- a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/EmbedSuite.scala +++ b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/EmbedSuite.scala @@ -5,12 +5,12 @@ import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import cats.data.OptionT import EmbedSuite.Foo -import tofu.syntax.monadic.* -import tofu.syntax.embed.* -import cats.instances.either.* -import cats.instances.option.* -import cats.syntax.traverse.* -import cats.syntax.either.* +import tofu.syntax.monadic._ +import tofu.syntax.embed._ +import cats.instances.either._ +import cats.instances.option._ +import cats.syntax.traverse._ +import cats.syntax.either._ import scala.util.Try diff --git a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKSuite.scala b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKSuite.scala index bd819161b..9f7e518ac 100644 --- a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKSuite.scala +++ b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKSuite.scala @@ -2,20 +2,20 @@ package tofu.higherKind.derived import RepresentableKSuite.Foo import cats.data.{OptionT, Tuple2K} -import cats.instances.either.* -import cats.instances.option.* -import cats.syntax.either.* -import cats.syntax.functor.* -import cats.syntax.traverse.* -import cats.syntax.option.* -import cats.tagless.syntax.functorK.* -import cats.tagless.syntax.semigroupalK.* +import cats.instances.either._ +import cats.instances.option._ +import cats.syntax.either._ +import cats.syntax.functor._ +import cats.syntax.traverse._ +import cats.syntax.option._ +import cats.tagless.syntax.functorK._ +import cats.tagless.syntax.semigroupalK._ import cats.{Id, ~>} import derevo.derive import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import tofu.data.Embedded -import tofu.syntax.embed.* +import tofu.syntax.embed._ import tofu.syntax.funk.funK import scala.util.Try diff --git a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKVarArgSuite.scala b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKVarArgSuite.scala index 944c44d0e..7824dc274 100644 --- a/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKVarArgSuite.scala +++ b/modules/derivation/src/test/scala-2/tofu/higherKind/derived/RepresentableKVarArgSuite.scala @@ -3,9 +3,9 @@ package tofu.higherKind.derived import cats.data.Tuple2K import cats.{Id, ~>} import derevo.derive -import tofu.syntax.embed.* -import cats.tagless.syntax.functorK.* -import cats.tagless.syntax.semigroupalK.* +import tofu.syntax.embed._ +import cats.tagless.syntax.functorK._ +import cats.tagless.syntax.semigroupalK._ import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers import tofu.higherKind.derived.RepresentableKVarArgSuite.Foo diff --git a/modules/derivation/src/test/scala-3/tofu/common/derived/DisplayData.scala b/modules/derivation/src/test/scala-3/tofu/common/derived/DisplayData.scala index 861631ff6..4e468feef 100644 --- a/modules/derivation/src/test/scala-3/tofu/common/derived/DisplayData.scala +++ b/modules/derivation/src/test/scala-3/tofu/common/derived/DisplayData.scala @@ -5,7 +5,7 @@ import tofu.common.Display import tofu.common.Display.Config object DisplayData { - + case class Bar(value: Int, another: String) derives Display case class Foo(bar: Bar, field: Double, xs: List[Int]) derives Display diff --git a/modules/derivation/src/test/scala-3/tofu/data/derived/MergeData.scala b/modules/derivation/src/test/scala-3/tofu/data/derived/MergeData.scala index 37d155879..c067d9730 100644 --- a/modules/derivation/src/test/scala-3/tofu/data/derived/MergeData.scala +++ b/modules/derivation/src/test/scala-3/tofu/data/derived/MergeData.scala @@ -1,6 +1,5 @@ package tofu.data.derived - object MergeData { final case class Foo(a: Int, b: Option[String], c: Option[Double]) derives Merge diff --git a/modules/derivation/src/test/scala/tofu/data/derived/MergeSuite.scala b/modules/derivation/src/test/scala/tofu/data/derived/MergeSuite.scala index 7407aef6a..540fe7e44 100644 --- a/modules/derivation/src/test/scala/tofu/data/derived/MergeSuite.scala +++ b/modules/derivation/src/test/scala/tofu/data/derived/MergeSuite.scala @@ -177,4 +177,3 @@ class MergeSuite extends AnyFlatSpec { } } - From cb2ded4bbdbd397ad46221efdb51e43dcefd0e9c Mon Sep 17 00:00:00 2001 From: Roman-Statsura Date: Wed, 8 May 2024 13:35:34 +0400 Subject: [PATCH 4/4] fix warnings --- .../derived/DisplayDerivationImpl.scala | 6 ++++ .../derived/DisplayDerivationImpl.scala | 8 ++++- .../scala/tofu/common/derived/display.scala | 8 ----- .../main/scala/tofu/data/derived/Merge.scala | 30 +++++++++---------- 4 files changed, 28 insertions(+), 24 deletions(-) diff --git a/modules/derivation/src/main/scala-2/tofu/common/derived/DisplayDerivationImpl.scala b/modules/derivation/src/main/scala-2/tofu/common/derived/DisplayDerivationImpl.scala index 9cf7b6fec..f4f243e18 100644 --- a/modules/derivation/src/main/scala-2/tofu/common/derived/DisplayDerivationImpl.scala +++ b/modules/derivation/src/main/scala-2/tofu/common/derived/DisplayDerivationImpl.scala @@ -6,6 +6,12 @@ import magnolia1.{CaseClass, Magnolia, SealedTrait} import tofu.common.Display import tofu.magnolia.compat +/** Derivation of [[Display]] typeclass for case classes and sealed traits + * + * @note + * Derived [[Display]] instances will indent nested structures if those are supposed to be on newline. You can see + * examples in the tests. + */ trait DisplayDerivationImpl extends Derivation[Display] { private type Typeclass[T] = Display[T] diff --git a/modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala b/modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala index 2910e7b63..6935aab74 100644 --- a/modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala +++ b/modules/derivation/src/main/scala-3/tofu/common/derived/DisplayDerivationImpl.scala @@ -6,6 +6,12 @@ import tofu.common.Display import tofu.magnolia.compat import scala.deriving.Mirror +/** Derivation of [[Display]] typeclass for case classes and sealed traits + * + * @note + * Derived [[Display]] instances will indent nested structures if those are supposed to be on newline. You can see + * examples in the tests. + */ trait DisplayDerivationImpl extends AutoDerivation[Display] { private type Typeclass[T] = Display[T] @@ -44,7 +50,7 @@ trait DisplayDerivationImpl extends AutoDerivation[Display] { displayedParameterValue <- current.typeclass.displayBuild(nestedCfg, compat.deref[Typeclass, T](current)(a)) // this value has at least one element in it by construction, // but we avoid using NEVector here due to performance and simplicity - adapted :+ value = adaptDisplayedParameter(label, displayedParameterValue) + adapted :+ value = adaptDisplayedParameter(label, displayedParameterValue): @unchecked separator = if (index + 1 < ctx.parameters.size) fieldSeparator else "" adaptedIndentedValueWithSeparator = value + separator + newline separatedLabelValue = adapted :+ adaptedIndentedValueWithSeparator diff --git a/modules/derivation/src/main/scala/tofu/common/derived/display.scala b/modules/derivation/src/main/scala/tofu/common/derived/display.scala index b923e37e2..343241241 100644 --- a/modules/derivation/src/main/scala/tofu/common/derived/display.scala +++ b/modules/derivation/src/main/scala/tofu/common/derived/display.scala @@ -1,11 +1,3 @@ package tofu.common.derived -import tofu.common.Display - -/** Derivation of [[Display]] typeclass for case classes and sealed traits - * - * @note - * Derived [[Display]] instances will indent nested structures if those are supposed to be on newline. You can see - * examples in the tests. - */ object display extends DisplayDerivationImpl diff --git a/modules/derivation/src/main/scala/tofu/data/derived/Merge.scala b/modules/derivation/src/main/scala/tofu/data/derived/Merge.scala index 244c2ad84..397d334ae 100644 --- a/modules/derivation/src/main/scala/tofu/data/derived/Merge.scala +++ b/modules/derivation/src/main/scala/tofu/data/derived/Merge.scala @@ -19,21 +19,21 @@ object Merge extends MergeInstances1 with DataComp[Merge] { val ops: tofu.syntax.merge.type = tofu.syntax.merge sealed class Primitive[A] - final implicit object primitiveByte extends Primitive[Byte] - final implicit object primitiveShort extends Primitive[Short] - final implicit object primitiveInt extends Primitive[Int] - final implicit object primitiveLong extends Primitive[Long] - final implicit object primitiveChar extends Primitive[Char] - final implicit object primitiveFloat extends Primitive[Float] - final implicit object primitiveDouble extends Primitive[Double] - final implicit object primitiveUnit extends Primitive[Unit] - final implicit object primitiveBigDecimal extends Primitive[BigDecimal] - final implicit object primitiveBigInt extends Primitive[BigInt] - final implicit object primitiveLocalDateTime extends Primitive[LocalDateTime] - final implicit object primitiveZonedDateTime extends Primitive[ZonedDateTime] - final implicit object primitiveLocalDate extends Primitive[LocalDate] - final implicit object primitiveInstant extends Primitive[Instant] - final implicit object primitiveString extends Primitive[String] + implicit object primitiveByte extends Primitive[Byte] + implicit object primitiveShort extends Primitive[Short] + implicit object primitiveInt extends Primitive[Int] + implicit object primitiveLong extends Primitive[Long] + implicit object primitiveChar extends Primitive[Char] + implicit object primitiveFloat extends Primitive[Float] + implicit object primitiveDouble extends Primitive[Double] + implicit object primitiveUnit extends Primitive[Unit] + implicit object primitiveBigDecimal extends Primitive[BigDecimal] + implicit object primitiveBigInt extends Primitive[BigInt] + implicit object primitiveLocalDateTime extends Primitive[LocalDateTime] + implicit object primitiveZonedDateTime extends Primitive[ZonedDateTime] + implicit object primitiveLocalDate extends Primitive[LocalDate] + implicit object primitiveInstant extends Primitive[Instant] + implicit object primitiveString extends Primitive[String] } object Merged {