From 756721a23abf76c857f2af0c4e9f7023fa8216de Mon Sep 17 00:00:00 2001 From: Eli Kasik Date: Wed, 16 Feb 2022 17:21:21 -0500 Subject: [PATCH] #794: Derivation tools for external newtypes --- .../zio/prelude/newtypes/DerivationSpec.scala | 45 +++++++++++++++++++ .../zio/prelude/newtypes/derivation.scala | 14 ++++++ 2 files changed, 59 insertions(+) create mode 100644 core-tests/shared/src/test/scala/zio/prelude/newtypes/DerivationSpec.scala create mode 100644 core/shared/src/main/scala/zio/prelude/newtypes/derivation.scala diff --git a/core-tests/shared/src/test/scala/zio/prelude/newtypes/DerivationSpec.scala b/core-tests/shared/src/test/scala/zio/prelude/newtypes/DerivationSpec.scala new file mode 100644 index 000000000..94b0b4bb3 --- /dev/null +++ b/core-tests/shared/src/test/scala/zio/prelude/newtypes/DerivationSpec.scala @@ -0,0 +1,45 @@ +package zio.prelude.newtypes + +import zio.prelude.{Newtype, Subtype} +import zio.test._ +import zio.prelude.newtypes.derivation.derive + +object DerivationSpec extends DefaultRunnableSpec { + trait Show[A]{ + def show(a: A): String + } + + implicit val showString: Show[String] = (a: String) => a + + // these are imported from an external library - we have no control over them + object External{ + object Secret extends Newtype[String] + type Secret = Secret.Type + + object Password extends Subtype[String] + type Password = Password.Type + } + + import External._ + + override def spec = suite("external derivation for newtypes")( + test("works for Newtype"){ + val showSecret: Show[Secret] = derive + assertTrue(showSecret.show(Secret("foo")) == "foo") + }, + test("works for Subtype"){ + val showPassword: Show[Password] = derive + assertTrue(showPassword.show(Password("foo")) == "foo") + }, + testM("works with auto derivation"){ + typeCheck( + """ + |import zio.prelude.newtypes.derivation.auto._ + |implicitly[Show[Secret]] + |implicitly[Show[Password]] + |""".stripMargin) + .absolve + .as(assertCompletes) + } + ) +} diff --git a/core/shared/src/main/scala/zio/prelude/newtypes/derivation.scala b/core/shared/src/main/scala/zio/prelude/newtypes/derivation.scala new file mode 100644 index 000000000..10631bbcf --- /dev/null +++ b/core/shared/src/main/scala/zio/prelude/newtypes/derivation.scala @@ -0,0 +1,14 @@ +package zio.prelude.newtypes + +import zio.prelude.Newtype + +object derivation { + def derive[A, STA <: Newtype[A], F[_]](implicit ev: STA <:< Newtype[A], typeClass: F[A]): F[STA#Type] = + typeClass.asInstanceOf[F[STA#Type]] + + trait Auto { + implicit def auto[A, STA <: Newtype[A], F[_]](implicit ev: STA <:< Newtype[A], typeClass: F[A]): F[STA#Type] = + derive + } + object auto extends Auto +}