Skip to content

Commit

Permalink
Move files around for scala3
Browse files Browse the repository at this point in the history
made scala2 specific suites for some features that won't go to Scala 3
immediately.
stubbed out some methods in auto to get compilation working
  • Loading branch information
zarthross committed May 13, 2023
1 parent 79fc8f5 commit a71fb90
Show file tree
Hide file tree
Showing 31 changed files with 248 additions and 105 deletions.
24 changes: 14 additions & 10 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@ import sbtcrossproject.{ CrossType, crossProject }

val Scala212V = "2.12.17"
val Scala213V = "2.13.7"
val Scala3V = "3.2.0"

val circeVersion = "0.14.3"
val paradiseVersion = "2.1.1"

val jawnVersion = "1.4.0"
val munitVersion = "0.7.29"
val disciplineMunitVersion = "1.0.9"
val munitVersion = "1.0.0-M6"
val disciplineMunitVersion = "2.0.0-M3"

ThisBuild / tlBaseVersion := "0.14"
ThisBuild / tlCiReleaseTags := false

ThisBuild / organization := "io.circe"
ThisBuild / crossScalaVersions := List(Scala212V, Scala213V)
ThisBuild / crossScalaVersions := List(Scala212V, Scala213V, Scala3V)
ThisBuild / scalaVersion := Scala213V

ThisBuild / githubWorkflowJavaVersions := Seq("8", "17").map(JavaSpec.temurin)
Expand Down Expand Up @@ -54,19 +55,22 @@ lazy val genericExtras = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("generic-extras"))
.settings(
moduleName := "circe-generic-extras",
libraryDependencies ++= Seq(
libraryDependencies ++= List(
"io.circe" %%% "circe-generic" % circeVersion,
"io.circe" %%% "circe-literal" % circeVersion % Test,
"io.circe" %%% "circe-testing" % circeVersion % Test,
"org.scalameta" %%% "munit" % munitVersion % Test,
"org.scalameta" %%% "munit-scalacheck" % munitVersion % Test,
"org.typelevel" %%% "discipline-munit" % disciplineMunitVersion % Test,
"org.typelevel" %% "jawn-parser" % jawnVersion % Test,
scalaOrganization.value % "scala-compiler" % scalaVersion.value % Provided,
scalaOrganization.value % "scala-reflect" % scalaVersion.value % Provided
) ++ (
"org.typelevel" %% "jawn-parser" % jawnVersion % Test
) ++ (if (scalaBinaryVersion.value.startsWith("2"))
List(
scalaOrganization.value % "scala-compiler" % scalaVersion.value % Provided,
scalaOrganization.value % "scala-reflect" % scalaVersion.value % Provided
)
else Nil) ++ (
if (scalaBinaryVersion.value == "2.12") {
Seq(
List(
compilerPlugin(("org.scalamacros" % "paradise" % paradiseVersion).cross(CrossVersion.patch))
)
} else Nil
Expand All @@ -88,7 +92,7 @@ lazy val genericExtras = crossProject(JSPlatform, JVMPlatform, NativePlatform)
)
.jsSettings()
.nativeSettings(
tlVersionIntroduced := List("2.12", "2.13").map(_ -> "0.14.3").toMap
tlVersionIntroduced := List("2.12", "2.13", "3").map(_ -> "0.14.3").toMap
)

lazy val benchmarks = project
Expand Down
29 changes: 6 additions & 23 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions generic-extras/src/main/scala-3/io/circe/generic/extras/auto.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.circe.generic.extras

import io.circe.{ Decoder, Encoder }
import io.circe.`export`.Exported
import scala.deriving.Mirror

/**
* Fully automatic codec derivation.
*
* Extending this trait provides [[io.circe.Decoder]] and [[io.circe.Encoder]]
* instances for case classes (if all members have instances), sealed
* trait hierarchies, etc.
*/
trait AutoDerivation {
implicit inline final def deriveDecoder[A](using inline A: Mirror.Of[A]): Exported[Decoder[A]] =
Exported(Decoder.derived[A])
implicit inline final def deriveEncoder[A](using inline A: Mirror.Of[A]): Exported[Encoder.AsObject[A]] =
Exported(Encoder.AsObject.derived[A])
}

object auto extends AutoDerivation
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package io.circe.generic.extras

import io.circe.{ Codec, Decoder, Encoder }
import scala.deriving.Mirror

/**
* Semi-automatic codec derivation.
*
* This object provides helpers for creating [[io.circe.Decoder]] and [[io.circe.ObjectEncoder]]
* instances for case classes, "incomplete" case classes, sealed trait hierarchies, etc.
*
* Typical usage will look like the following:
*
* {{{
* import io.circe._, io.circe.generic.semiauto._
*
* case class Foo(i: Int, p: (String, Double))
*
* object Foo {
* implicit val decodeFoo: Decoder[Foo] = deriveDecoder[Foo]
* implicit val encodeFoo: Encoder.AsObject[Foo] = deriveEncoder[Foo]
* }
* }}}
*/
object semiauto {
inline final def deriveConfiguredDecoder[A](using inline A: Mirror.Of[A], configuration: Configuration): Decoder[A] = ???
inline final def deriveConfiguredEncoder[A](using inline A: Mirror.Of[A], configuration: Configuration): Encoder.AsObject[A] = ???
inline final def deriveConfiguredCodec[A](using inline A: Mirror.Of[A], configuration: Configuration): Codec.AsObject[A] = ???

inline final def deriveExtrasDecoder[A](using inline A: Mirror.Of[A], configuration: Configuration): ExtrasDecoder[A] = ???
inline final def deriveExtrasEncoder[A](using inline A: Mirror.Of[A], configuration: Configuration): Encoder.AsObject[A] = ???
inline final def deriveExtrasCodec[A](using inline A: Mirror.Of[A], configuration: Configuration): ExtrasAsObjectCodec[A] = ???

/**
* Derive a decoder for a sealed trait hierarchy made up of case objects.
*
* Note that this differs from the usual derived decoder in that the leaves of the ADT are represented as JSON
* strings.
*/
def deriveEnumerationDecoder[A](): Decoder[A] = ???

/**
* Derive an encoder for a sealed trait hierarchy made up of case objects.
*
* Note that this differs from the usual derived encoder in that the leaves of the ADT are represented as JSON
* strings.
*/
def deriveEnumerationEncoder[A](): Encoder[A] = ???

/**
* Derive a codec for a sealed trait hierarchy made up of case objects.
*
* Note that this differs from the usual derived encoder in that the leaves of the ADT are represented as JSON
* strings.
*/
def deriveEnumerationCodec[A](): Codec[A] = ???

/**
* Derive a decoder for a value class.
*/
def deriveUnwrappedDecoder[A](): Decoder[A] = ???

/**
* Derive an encoder for a value class.
*/
def deriveUnwrappedEncoder[A](): Encoder[A] = ???

/**
* Derive a codec for a value class.
*/
def deriveUnwrappedCodec[A](): Codec[A] = ???

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package io.circe.generic.extras

import cats.data.Validated
import cats.kernel.Eq
import io.circe.{ Decoder, DecodingFailure, Encoder, Json }
import io.circe.CursorOp.DownField
import io.circe.generic.extras.auto._
import io.circe.literal._
import io.circe.testing.CodecTests
import org.scalacheck.{ Arbitrary, Gen }
import org.scalacheck.Arbitrary.arbitrary
import org.scalacheck.Prop.forAll
import examples._

class ConfiguredAutoDerivedScala2Suite extends CirceSuite {

import defaults._

property("Decoder[Int => Qux[String]] should decode partial JSON representations") {
forAll { (i: Int, s: String, j: Int) =>
val result = Json
.obj(
"a" -> Json.fromString(s),
"j" -> Json.fromInt(j)
)
.as[Int => Qux[String]]
.map(_(i))

assert(result === Right(Qux(i, s, j)))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package io.circe.generic.extras

import cats.kernel.Eq
import io.circe.{ Codec, Decoder, DecodingFailure, Encoder, Json }
import io.circe.generic.extras.semiauto._
import io.circe.literal._
import io.circe.testing.CodecTests
import org.scalacheck.{ Arbitrary, Gen }
import org.scalacheck.Arbitrary.arbitrary
import shapeless.Witness
import shapeless.labelled.{ FieldType, field }
import org.scalacheck.Prop.forAll

import examples._
import cats.laws.discipline.ScalaVersionSpecific

object ConfiguredSemiautoDerivedScala2Suite {
implicit val customConfig: Configuration =
Configuration.default.withSnakeCaseMemberNames.withDefaults.withDiscriminator("type").withSnakeCaseConstructorNames

implicit val decodeJlessQux: Decoder[FieldType[Witness.`'j`.T, Int] => Qux[String]] =
deriveConfiguredFor[FieldType[Witness.`'j`.T, Int] => Qux[String]].incomplete

implicit val decodeIntlessQux: Decoder[Int => Qux[String]] =
deriveConfiguredFor[Int => Qux[String]].incomplete

implicit val decodeQuxPatch: Decoder[Qux[String] => Qux[String]] = deriveConfiguredFor[Qux[String]].patch
}

class ConfiguredSemiautoDerivedScala2Suite extends CirceSuite {
import ConfiguredSemiautoDerivedScala2Suite._

property("Decoder[FieldType[Witness.`'j`.T, Int] => Qux[String]] should decode partial JSON representations") {
forAll { (i: Int, s: String, j: Int) =>
val result = Json
.obj(
"i" -> Json.fromInt(i),
"a" -> Json.fromString(s)
)
.as[FieldType[Witness.`'j`.T, Int] => Qux[String]]
.map(
_(field(j))
)

assert(result === Right(Qux(i, s, j)))
}
}

property("Decoder[Int => Qux[String]] should decode partial JSON representations") {
forAll { (i: Int, s: String, j: Int) =>
val result = Json
.obj(
"a" -> Json.fromString(s),
"j" -> Json.fromInt(j)
)
.as[Int => Qux[String]]
.map(_(i))

assert(result === Right(Qux(i, s, j)))
}
}

property("Decoder[Qux[String] => Qux[String]] should decode patch JSON representations") {
forAll { (q: Qux[String], i: Option[Int], a: Option[String], j: Option[Int]) =>
val json = Json.obj(
"i" -> Encoder[Option[Int]].apply(i),
"a" -> Encoder[Option[String]].apply(a),
"j" -> Encoder[Option[Int]].apply(j)
)

val expected = Qux[String](i.getOrElse(q.i), a.getOrElse(q.a), j.getOrElse(q.j))

assert(json.as[Qux[String] => Qux[String]].map(_(q)) === Right(expected))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -279,19 +279,5 @@ class ConfiguredAutoDerivedSuite extends CirceSuite {
checkAll("Codec[(Int, Int, Foo)]", CodecTests[(Int, Int, Foo)].codec)
checkAll("Codec[Qux[Int]]", CodecTests[Qux[Int]].codec)
checkAll("Codec[Foo]", CodecTests[Foo].codec)

property("Decoder[Int => Qux[String]] should decode partial JSON representations") {
forAll { (i: Int, s: String, j: Int) =>
val result = Json
.obj(
"a" -> Json.fromString(s),
"j" -> Json.fromInt(j)
)
.as[Int => Qux[String]]
.map(_(i))

assert(result === Right(Qux(i, s, j)))
}
}
}
}
Loading

0 comments on commit a71fb90

Please sign in to comment.