Skip to content

Commit

Permalink
Initial support for opaque types in Deriver (zio#517)
Browse files Browse the repository at this point in the history
* Initial support for opaque types in Deriver

* Generate readme

* Fix 2.12

* Fix

* 2.12 fix

* Missing file

* Cleanup

* Removed prints
  • Loading branch information
vigoo authored Mar 10, 2023
1 parent 114f038 commit 7c06f4b
Show file tree
Hide file tree
Showing 11 changed files with 437 additions and 301 deletions.
593 changes: 307 additions & 286 deletions zio-schema-derivation/shared/src/main/scala-3/zio/schema/Derive.scala

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package zio.schema

import java.util.concurrent.{ ConcurrentHashMap, ConcurrentMap }

import scala.reflect.ClassTag

import zio.Chunk
import zio.schema.CachedDeriver.{ Cache, CacheKey }
import zio.schema.Deriver.WrappedF
Expand All @@ -27,6 +29,14 @@ private[schema] class CachedDeriver[F[_]] private (deriver: Deriver[F], val cach
deriver.derivePrimitive(st, summoned)
}

override def derivePrimitiveAlias[A: ClassTag, U](st: StandardType[U], summoned: => Option[F[A]]): F[A] = {
val key = CacheKey.PrimitiveAlias(st, implicitly[ClassTag[A]])
cache.get(key) match {
case None => cache.put(key, deriver.derivePrimitiveAlias[A, U](st, summoned))
case Some(g) => g
}
}

override def deriveOption[A](
option: Schema.Optional[A],
inner: => F[A],
Expand Down Expand Up @@ -106,15 +116,16 @@ private[schema] object CachedDeriver {
sealed trait CacheKey[A]

object CacheKey {
final case class Primitive[A](standardType: StandardType[A]) extends CacheKey[A]
final case class WithId[A](typeId: TypeId) extends CacheKey[A]
final case class WithIdentityObject[A](inner: CacheKey[_], id: Any) extends CacheKey[A]
final case class Optional[A](key: CacheKey[A]) extends CacheKey[A]
final case class Either[A, B](leftKey: CacheKey[A], rightKey: CacheKey[B]) extends CacheKey[Either[A, B]]
final case class Tuple2[A, B](leftKey: CacheKey[A], rightKey: CacheKey[B]) extends CacheKey[(A, B)]
final case class Set[A](element: CacheKey[A]) extends CacheKey[Set[A]]
final case class Map[K, V](key: CacheKey[K], valuew: CacheKey[V]) extends CacheKey[Map[K, V]]
final case class Misc[A](schema: Schema[A]) extends CacheKey[A]
final case class Primitive[A](standardType: StandardType[A]) extends CacheKey[A]
final case class PrimitiveAlias[A, U](standardType: StandardType[U], classTag: ClassTag[A]) extends CacheKey[A]
final case class WithId[A](typeId: TypeId) extends CacheKey[A]
final case class WithIdentityObject[A](inner: CacheKey[_], id: Any) extends CacheKey[A]
final case class Optional[A](key: CacheKey[A]) extends CacheKey[A]
final case class Either[A, B](leftKey: CacheKey[A], rightKey: CacheKey[B]) extends CacheKey[Either[A, B]]
final case class Tuple2[A, B](leftKey: CacheKey[A], rightKey: CacheKey[B]) extends CacheKey[(A, B)]
final case class Set[A](element: CacheKey[A]) extends CacheKey[Set[A]]
final case class Map[K, V](key: CacheKey[K], valuew: CacheKey[V]) extends CacheKey[Map[K, V]]
final case class Misc[A](schema: Schema[A]) extends CacheKey[A]

def fromStandardType[A](st: StandardType[A]): CacheKey[A] = Primitive(st)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package zio.schema

import scala.annotation.nowarn
import scala.reflect.ClassTag

import zio.Chunk
Expand Down Expand Up @@ -62,6 +63,10 @@ trait Deriver[F[_]] extends VersionSpecificDeriver[F] { self =>
def deriveEnum[A](`enum`: Schema.Enum[A], cases: => Chunk[WrappedF[F, _]], summoned: => Option[F[A]]): F[A]

def derivePrimitive[A](st: StandardType[A], summoned: => Option[F[A]]): F[A]

@nowarn def derivePrimitiveAlias[A: ClassTag, U](st: StandardType[U], summoned: => Option[F[A]]): F[A] =
deriveUnknown(summoned)

def deriveOption[A](option: Schema.Optional[A], inner: => F[A], summoned: => Option[F[Option[A]]]): F[Option[A]]

def deriveSequence[C[_], A](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package zio.schema

import scala.annotation.nowarn

import zio.test._

trait VersionSpecificDeriveSchemaSpec {
case class ContainerFields(field1: Option[String])

Expand All @@ -14,4 +16,6 @@ trait VersionSpecificDeriveSchemaSpec {
class FieldNameVerifier[F] {
@nowarn def apply(name: String): Boolean = true // Cannot check as we don't have singleton types
}

def versionSpecificSuite: Spec[Any, Nothing] = Spec.labeled("Scala 2.12 specific tests", Spec.empty)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package zio.schema

import zio.test._

trait VersionSpecificDeriveSpec extends ZIOSpecDefault {

def versionSpecificSuite: Spec[Any, Nothing] = Spec.labeled("Scala 2.12 specific tests", Spec.empty)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package zio.schema

import scala.annotation.nowarn

trait VersionSpecificDeriveSchemaSpec {
import zio.test._

trait VersionSpecificDeriveSchemaSpec extends ZIOSpecDefault {
case class ContainerFields(field1: Option[String])

object ContainerFields {
Expand All @@ -15,4 +17,6 @@ trait VersionSpecificDeriveSchemaSpec {
class FieldNameVerifier[F] {
@nowarn def apply[S <: String & scala.Singleton](name: S)(implicit ev: F =:= S): Boolean = true
}

def versionSpecificSuite: Spec[Any, Nothing] = Spec.labeled("Scala 2.13 specific tests", Spec.empty)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package zio.schema

import zio.test._

trait VersionSpecificDeriveSpec extends ZIOSpecDefault {

def versionSpecificSuite: Spec[Any, Nothing] = Spec.labeled("Scala 2.13 specific tests", Spec.empty)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package zio.schema

trait VersionSpecificDeriveSchemaSpec {
import zio.test.*

trait VersionSpecificDeriveSchemaSpec extends ZIOSpecDefault {
case class ContainerFields(field1: Option[String])

object ContainerFields {
Expand All @@ -13,5 +15,7 @@ trait VersionSpecificDeriveSchemaSpec {
class FieldNameVerifier[F] {
inline def apply[S <: String & scala.Singleton](name: S): Boolean =
VerifyFieldNameMacro.verifyFieldName[F, S]
}
}

def versionSpecificSuite = Spec.labeled("Scala 3 specific tests", Spec.empty)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package zio.schema

import zio.*
import zio.test.*
import zio.test.Assertion.*
import scala.reflect.ClassTag

trait VersionSpecificDeriveSpec extends ZIOSpecDefault {
import VersionSpecificDeriveSpec.*

def versionSpecificSuite =
suite("Scala 3 specific tests")(
test("Opaque types") {
val deriver = new Deriver[TC] {
override def deriveRecord[A](record: Schema.Record[A], fields: => Chunk[Deriver.WrappedF[TC, _]], summoned: => Option[TC[A]]): TC[A] = ???

override def deriveEnum[A](`enum`: Schema.Enum[A], cases: => Chunk[Deriver.WrappedF[TC, _]], summoned: => Option[TC[A]]): TC[A] = ???

override def derivePrimitive[A](st: StandardType[A], summoned: => Option[TC[A]]): TC[A] = ???

override def derivePrimitiveAlias[A: ClassTag, U](st: StandardType[U], summoned: => Option[TC[A]]): TC[A] = {
if (st == StandardType.StringType) {
new TC[A] {
def name(a: A): String = a.asInstanceOf[String]
}
} else {
???
}
}

override def deriveOption[A](option: Schema.Optional[A], inner: => TC[A], summoned: => Option[TC[Option[A]]]): TC[Option[A]] = ???

override def deriveSequence[C[_], A](sequence: Schema.Sequence[C[A], A, _], inner: => TC[A], summoned: => Option[TC[C[A]]]): TC[C[A]] = ???

override def deriveMap[K, V](map: Schema.Map[K, V], key: => TC[K], value: => TC[V], summoned: => Option[TC[Map[K, V]]]): TC[Map[K, V]] = ???

override def deriveTransformedRecord[A, B](
record: Schema.Record[A],
transform: Schema.Transform[A, B, _],
fields: => Chunk[Deriver.WrappedF[TC, _]],
summoned: => Option[TC[B]]
): TC[B] = ???
}

given TC[AnotherObject.MyId] = deriver.derive

def show[A](a: A)(using ev: TC[A]): String =
ev.name(a)

assert(show(AnotherObject.MyId("abc")))(equalTo("abc"))
}
)
}

object VersionSpecificDeriveSpec {
object AnotherObject {
opaque type MyId = String

object MyId {
def apply(s: String): MyId = s

given(using ev: Schema[String]): Schema[MyId] = ev
}
}

trait TC[A] {
def name(a: A): String
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ object DeriveSchemaSpec extends ZIOSpecDefault with VersionSpecificDeriveSchemaS
}
assert(derived)(hasSameSchema(expected))
}
)
),
versionSpecificSuite
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import zio.schema.Schema.Field
import zio.test.{ Spec, TestEnvironment, ZIOSpecDefault, assertTrue }
import zio.{ Chunk, Scope }

object DeriveSpec extends ZIOSpecDefault {
object DeriveSpec extends ZIOSpecDefault with VersionSpecificDeriveSpec {
override def spec: Spec[TestEnvironment with Scope, Any] =
suite("Derive")(
suite("case object")(
Expand Down Expand Up @@ -160,7 +160,8 @@ object DeriveSpec extends ZIOSpecDefault {
val refEquals = tc.inner.get eq defaultOpenTraitTC
assertTrue(refEquals)
}
)
),
versionSpecificSuite
)

trait TC[A] {
Expand Down

0 comments on commit 7c06f4b

Please sign in to comment.