-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CaseClass1Rep support for Scala 3. Enabling kebs-instances. (#187)
* Fixing `enum` and some macro warnings. * Adding basic CaseClass1Rep support for Scala 3. Enabling kebs-instances. * Creating EnumOf typeclass (with a macro) to support Scala 3's enums.
- Loading branch information
Showing
19 changed files
with
172 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
4 changes: 2 additions & 2 deletions
4
instances/src/test/scala/pl/iterators/kebs/instances/net/NetInstancesTests.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
macro-utils/src/main/scala-3/pl/iterators/kebs/macros/CaseClassReps.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,11 @@ | ||
package pl.iterators.kebs.macros | ||
|
||
import scala.deriving.Mirror | ||
|
||
final class CaseClass1Rep[CC, F1](val apply: F1 => CC, val unapply: CC => F1) | ||
|
||
object CaseClass1Rep { | ||
inline given[T <: Product, F1](using m: Mirror.ProductOf[T], teq: m.MirroredElemTypes =:= F1 *: EmptyTuple.type): CaseClass1Rep[T, F1] = { | ||
new CaseClass1Rep[T, F1](f1 => m.fromProduct(Tuple1(f1)), _.productElement(0).asInstanceOf[F1]) | ||
} | ||
} |
29 changes: 29 additions & 0 deletions
29
macro-utils/src/main/scala-3/pl/iterators/kebs/macros/enums/EnumEntryMacros.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package pl.iterators.kebs.macros.enums | ||
|
||
import scala.quoted._ | ||
|
||
trait EnumLike[T] { | ||
def values: Array[T] | ||
def valueOf(name: String): T | ||
def fromOrdinal(ordinal: Int): T | ||
} | ||
|
||
class EnumOf[E](val `enum`: EnumLike[E]) | ||
|
||
object EnumOf { | ||
inline given [E]: EnumOf[E] = ${EnumOf.impl[E]()} | ||
|
||
private def impl[T]()(using Quotes, Type[T]): Expr[EnumOf[T]] = { | ||
import quotes.reflect._ | ||
val companion = Ref(TypeRepr.of[T].typeSymbol.companionModule) | ||
'{ | ||
new EnumOf( | ||
new EnumLike[T] { | ||
def values: Array[T] = ${Select.unique(companion, "values").asExprOf[Array[T]]} | ||
def valueOf(name: String): T = ${Apply(Select.unique(companion, "valueOf"), List('{name}.asTerm)).asExprOf[T]} | ||
def fromOrdinal(ordinal: Int): T = ${Apply(Select.unique(companion, "fromOrdinal"), List('{ordinal}.asTerm)).asExprOf[T]} | ||
} | ||
) | ||
} | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
macro-utils/src/main/scala-3/pl/iterators/kebs/support/EquivSupport.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package pl.iterators.kebs.support | ||
|
||
import pl.iterators.kebs.macros.CaseClass1Rep | ||
|
||
trait EquivSupport { | ||
|
||
implicit def equivFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], equivRep: Equiv[Rep]): Equiv[A] = | ||
(x: A, y: A) => equivRep.equiv(cc1Rep.unapply(x), cc1Rep.unapply(y)) | ||
|
||
} |
25 changes: 25 additions & 0 deletions
25
macro-utils/src/main/scala-3/pl/iterators/kebs/support/FractionalSupport.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package pl.iterators.kebs.support | ||
|
||
import pl.iterators.kebs.macros.CaseClass1Rep | ||
|
||
trait FractionalSupport { | ||
|
||
implicit def fractionalFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], | ||
fractionalRep: Fractional[Rep], | ||
numeric: Numeric[A]): Fractional[A] = | ||
new Fractional[A] { | ||
override def div(x: A, y: A): A = cc1Rep.apply(fractionalRep.div(cc1Rep.unapply(x), cc1Rep.unapply(y))) | ||
override def plus(x: A, y: A): A = numeric.plus(x, y) | ||
override def minus(x: A, y: A): A = numeric.minus(x, y) | ||
override def times(x: A, y: A): A = numeric.times(x, y) | ||
override def negate(x: A): A = numeric.negate(x) | ||
override def fromInt(x: Int): A = numeric.fromInt(x) | ||
override def parseString(str: String): Option[A] = numeric.parseString(str) | ||
override def toInt(x: A): Int = numeric.toInt(x) | ||
override def toLong(x: A): Long = numeric.toLong(x) | ||
override def toFloat(x: A): Float = numeric.toFloat(x) | ||
override def toDouble(x: A): Double = numeric.toDouble(x) | ||
override def compare(x: A, y: A): Int = numeric.compare(x, y) | ||
} | ||
|
||
} |
26 changes: 26 additions & 0 deletions
26
macro-utils/src/main/scala-3/pl/iterators/kebs/support/IntegralSupport.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package pl.iterators.kebs.support | ||
|
||
import pl.iterators.kebs.macros.CaseClass1Rep | ||
|
||
trait IntegralSupport { | ||
|
||
implicit def integralFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], | ||
integralRep: Integral[Rep], | ||
numeric: Numeric[A]): Integral[A] = | ||
new Integral[A] { | ||
override def quot(x: A, y: A): A = cc1Rep.apply(integralRep.quot(cc1Rep.unapply(x), cc1Rep.unapply(y))) | ||
override def rem(x: A, y: A): A = cc1Rep.apply(integralRep.rem(cc1Rep.unapply(x), cc1Rep.unapply(y))) | ||
override def plus(x: A, y: A): A = numeric.plus(x, y) | ||
override def minus(x: A, y: A): A = numeric.minus(x, y) | ||
override def times(x: A, y: A): A = numeric.times(x, y) | ||
override def negate(x: A): A = numeric.negate(x) | ||
override def fromInt(x: Int): A = numeric.fromInt(x) | ||
override def parseString(str: String): Option[A] = numeric.parseString(str) | ||
override def toInt(x: A): Int = numeric.toInt(x) | ||
override def toLong(x: A): Long = numeric.toLong(x) | ||
override def toFloat(x: A): Float = numeric.toFloat(x) | ||
override def toDouble(x: A): Double = numeric.toDouble(x) | ||
override def compare(x: A, y: A): Int = numeric.compare(x, y) | ||
} | ||
|
||
} |
23 changes: 23 additions & 0 deletions
23
macro-utils/src/main/scala-3/pl/iterators/kebs/support/NumericSupport.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package pl.iterators.kebs.support | ||
|
||
import pl.iterators.kebs.macros.CaseClass1Rep | ||
|
||
trait NumericSupport { | ||
|
||
implicit def numericFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], numericRep: Numeric[Rep]): Numeric[A] = { | ||
new Numeric[A] { | ||
override def plus(x: A, y: A): A = cc1Rep.apply(numericRep.plus(cc1Rep.unapply(x), cc1Rep.unapply(y))) | ||
override def minus(x: A, y: A): A = cc1Rep.apply(numericRep.minus(cc1Rep.unapply(x), cc1Rep.unapply(y))) | ||
override def times(x: A, y: A): A = cc1Rep.apply(numericRep.times(cc1Rep.unapply(x), cc1Rep.unapply(y))) | ||
override def negate(x: A): A = cc1Rep.apply(numericRep.negate(cc1Rep.unapply(x))) | ||
override def fromInt(x: Int): A = cc1Rep.apply(numericRep.fromInt(x)) | ||
override def toInt(x: A): Int = numericRep.toInt(cc1Rep.unapply(x)) | ||
override def toLong(x: A): Long = numericRep.toLong(cc1Rep.unapply(x)) | ||
override def toFloat(x: A): Float = numericRep.toFloat(cc1Rep.unapply(x)) | ||
override def toDouble(x: A): Double = numericRep.toDouble(cc1Rep.unapply(x)) | ||
override def compare(x: A, y: A): Int = numericRep.compare(cc1Rep.unapply(x), cc1Rep.unapply(y)) | ||
override def parseString(str: String): Option[A] = numericRep.parseString(str).map(cc1Rep.apply) | ||
} | ||
} | ||
|
||
} |
14 changes: 14 additions & 0 deletions
14
macro-utils/src/main/scala-3/pl/iterators/kebs/support/PartialOrderingSupport.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package pl.iterators.kebs.support | ||
|
||
import pl.iterators.kebs.macros.CaseClass1Rep | ||
|
||
trait PartialOrderingSupport { | ||
|
||
implicit def partialOrderingFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], | ||
partialOrderingRep: PartialOrdering[Rep]): PartialOrdering[A] = | ||
new PartialOrdering[A] { | ||
override def tryCompare(x: A, y: A): Option[Int] = partialOrderingRep.tryCompare(cc1Rep.unapply(x), cc1Rep.unapply(y)) | ||
override def lteq(x: A, y: A): Boolean = partialOrderingRep.lteq(cc1Rep.unapply(x), cc1Rep.unapply(y)) | ||
} | ||
|
||
} |
3 changes: 3 additions & 0 deletions
3
macro-utils/src/main/scala-3/pl/iterators/kebs/support/package.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package pl.iterators.kebs | ||
|
||
package object support extends FractionalSupport with IntegralSupport with NumericSupport with PartialOrderingSupport with EquivSupport |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import org.scalacheck.Prop.forAll | ||
import org.scalacheck.{Gen, Properties} | ||
import pl.iterators.kebs.macros.CaseClass1Rep | ||
import pl.iterators.kebs.macros.enums.EnumOf | ||
|
||
object DerivingSpecification extends Properties("Deriving") { | ||
case class CC1Ex(whatever: String) | ||
|
||
property("CaseClass1Rep derives properly from 1-element case class") = forAll { (stringValue: String) => | ||
val tc = implicitly[CaseClass1Rep[CC1Ex, String]] | ||
tc.apply(stringValue) == CC1Ex(stringValue) && tc.unapply(CC1Ex(stringValue)) == stringValue | ||
} | ||
|
||
enum Color { | ||
case Red, Green, Blue | ||
} | ||
|
||
property("EnumOf derives properly for an enum") = forAll(Gen.oneOf(Color.values.toList)) { (color: Color) => | ||
val tc = implicitly[EnumOf[Color]] | ||
tc.`enum`.values.contains(color) && tc.`enum`.valueOf(color.toString) == color && tc.`enum`.fromOrdinal(color.ordinal) == color | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.