Skip to content

Commit

Permalink
Add scala 3 support (#177)
Browse files Browse the repository at this point in the history
* Add scala 3 support

* Add scala 3 support (add several readers for one field supporting)

* Add scala 3 support (isStrict supporting)

* Add scala 3 support (Add deprecated field styles)

* Add scala 3 support (deriving methods for reader/writer)

* Add scala 3 support (add deprecated field styles)

* Add scala 3 support (Add enum supporting)

* Add scala 3 support (cross-building)

* Add scala 3 support (make the branch up-to-date)

* Add scala 3 support (resolve lazy val issue)

* Add scala 3 support (refactoring after review)

---------

Co-authored-by: e.zhaygutov <[email protected]>
Co-authored-by: nikolaev-nikita <[email protected]>
  • Loading branch information
3 people authored Jul 3, 2023
1 parent 407a0fd commit ade5b16
Show file tree
Hide file tree
Showing 103 changed files with 4,854 additions and 195 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/scala.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
scala: [2.12.17, 2.13.10]
# FIXME Use stable scala version
scala: [2.13.10, 3.3.1-RC1-bin-20230318-7226ba6-NIGHTLY]

steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 2 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
version=3.7.1
runner.dialect=scala3
154 changes: 99 additions & 55 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
lazy val scala213 = "2.13.10"
/* FIXME
Return to use a stable version when 'scala.quoted.Quotes.reflectModuleSymbol.newClass'
and 'scala.quoted.Quotes.reflectModule.ClassDef.apply' are no longer experimental methods
*/
lazy val scala3 = "3.3.1-RC1-bin-20230318-7226ba6-NIGHTLY"

ThisBuild / scalaVersion := scala3

lazy val commonSettings = Seq(
version := "0.27.0",
version := "0.28.0",
organization := "com.tethys-json",
scalaVersion := "2.12.17",
crossScalaVersions := Seq("2.12.17", "2.13.10"),
Compile / unmanagedSourceDirectories ++= {
def extraDirs(suffix: String) = Seq(file(sourceDirectory.value.getPath + "/main/scala" + suffix))

CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, y)) if y <= 12 =>
extraDirs("-2.12-")
case Some((2, y)) if y >= 13 =>
extraDirs("-2.13+")
case _ => Nil
}
},
licenses := Seq("Apache-2.0" -> url("https://www.apache.org/licenses/LICENSE-2.0")),
homepage := Some(url("https://github.com/tethys-json/tethys")),
scmInfo := Some(
Expand All @@ -34,6 +30,12 @@ lazy val commonSettings = Seq(
name = "Boris Potepun",
email = "[email protected]",
url = url("https://github.com/REDNBLACK")
),
Developer(
id = "MrIrre",
name = "Erlan Zhaygutov",
email = "[email protected]",
url = url("https://github.com/MrIrre")
)
),
credentials ++= Option(Path.userHome / ".config" / "sbt" / ".tethys-credentials")
Expand All @@ -42,75 +44,100 @@ lazy val commonSettings = Seq(
publishMavenStyle := true,
publishTo := {
if (isSnapshot.value)
Some(Opts.resolver.sonatypeSnapshots)
Opts.resolver.sonatypeOssSnapshots.headOption
else
sonatypePublishToBundle.value
},
Test / publishArtifact := false
)

def crossScalaSettings = {
def addDirsByScalaVersion(path: String): Def.Initialize[Seq[sbt.File]] =
scalaVersion.zip(baseDirectory) { case (v, base) =>
def extraDirs(versionSpecificFolder: String): Seq[sbt.File] = Seq(base / path / versionSpecificFolder)

CrossVersion.partialVersion(v) match {
case Some((2, y)) if y >= 13 =>
extraDirs("scala-2.13+")
case Some((3, _)) =>
extraDirs("scala-3")
case _ => Seq.empty
}
}

Seq(
crossScalaVersions := Seq(scala213, scala3),
Compile / unmanagedSourceDirectories ++= addDirsByScalaVersion("src/main").value,
Test / unmanagedSourceDirectories ++= addDirsByScalaVersion("src/test").value
)
}

lazy val testSettings = Seq(
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest-flatspec" % "3.2.15" % Test,
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest-flatspec" % "3.2.15" % Test,
"org.scalatest" %% "scalatest-shouldmatchers" % "3.2.15" % Test
)
)

lazy val tethys = project.in(file("."))
.settings(
publishTo := None,
crossScalaVersions := Seq.empty,
commonSettings
)
.aggregate(core, `macro-derivation`, `jackson-211`, `jackson-212`, json4s, circe, enumeratum, refined)
.aggregate(core, `macro-derivation`, `jackson-211`, `jackson-212`, `jackson-213`, json4s, circe, refined, enumeratum)

lazy val modules = file("modules")

def addScalaCompiler(scalaVersion: String): Seq[ModuleID] =
CrossVersion.partialVersion(scalaVersion) match {
case Some((2, y)) if y >= 13 =>
Seq("org.scala-lang" % "scala-compiler" % scalaVersion % Provided)
case Some((3, _)) =>
Seq("org.scala-lang" %% "scala3-compiler" % scalaVersion % Provided)
case _ => Seq.empty
}

lazy val core = project.in(modules / "core")
.settings(crossScalaSettings)
.settings(commonSettings)
.settings(testSettings)
.settings(
name := "tethys-core",
libraryDependencies ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, y)) if y >= 13 =>
Seq(
"org.scala-lang" % "scala-compiler" % scalaVersion.value % Provided
)
case _ => Nil
}
}
libraryDependencies ++= addScalaCompiler(scalaVersion.value)
)

lazy val `macro-derivation` = project.in(modules / "macro-derivation")
.settings(crossScalaSettings)
.settings(commonSettings)
.settings(testSettings)
.settings(
name := "tethys-derivation",
libraryDependencies ++= Seq(
"org.scala-lang" % "scala-compiler" % scalaVersion.value % Provided
)
libraryDependencies ++= addScalaCompiler(scalaVersion.value)
)
.dependsOn(core)

lazy val jacksonSettings = Seq(
Compile / unmanagedSourceDirectories += modules / "jackson-backend" / "src" / "main",
Test / unmanagedSourceDirectories += modules / "jackson-backend" / "src" / "test",
Test / unmanagedResourceDirectories += modules / "jackson-backend" / "src" / "test" / "resources"
Test / unmanagedSourceDirectories += modules / "jackson-backend" / "src" / "test",
Test / unmanagedResourceDirectories += modules / "jackson-backend" / "src" / "test" / "resources"
)

lazy val `jackson-211` = project.in(modules / "jackson-211")
.settings(crossScalaSettings)
.settings(commonSettings)
.settings(jacksonSettings)
.settings(testSettings)
.settings(
name := "tethys-jackson",
name := "tethys-jackson211",
libraryDependencies ++= Seq(
"com.fasterxml.jackson.core" % "jackson-core" % "2.11.4"
)
)
.dependsOn(core)

lazy val `jackson-212` = project.in(modules / "jackson-212")
.settings(crossScalaSettings)
.settings(commonSettings)
.settings(jacksonSettings)
.settings(testSettings)
Expand All @@ -122,75 +149,92 @@ lazy val `jackson-212` = project.in(modules / "jackson-212")
)
.dependsOn(core)

lazy val `jackson-213` = project.in(modules / "jackson-213")
.settings(crossScalaSettings)
.settings(commonSettings)
.settings(jacksonSettings)
.settings(testSettings)
.settings(
name := "tethys-jackson213",
libraryDependencies ++= Seq(
"com.fasterxml.jackson.core" % "jackson-core" % "2.13.5"
)
)
.dependsOn(core)

lazy val circe = project.in(modules / "circe")
.settings(crossScalaSettings)
.settings(commonSettings)
.settings(testSettings)
.settings(
name := "tethys-circe",
libraryDependencies ++= Seq(
"io.circe" %% "circe-core" % "0.14.4"
"io.circe" %% "circe-core" % "0.14.5"
)
)
.dependsOn(core, `jackson-212` % Test)

lazy val json4s = project.in(modules / "json4s")
.settings(crossScalaSettings)
.settings(commonSettings)
.settings(testSettings)
.settings(
name := "tethys-json4s",
libraryDependencies ++= Seq(
"org.json4s" %% "json4s-core" % "4.0.6"
"org.json4s" %% "json4s-ast" % "4.0.6"
)
)
.dependsOn(core)

lazy val enumeratum = project.in(modules / "enumeratum")
.settings(crossScalaSettings)
.settings(commonSettings)
.settings(testSettings)
.settings(crossScalaVersions := Seq(scala213))
.settings(
name := "tethys-enumeratum",
libraryDependencies ++= Seq(
"com.beachape" %% "enumeratum" % "1.7.2"
)
libraryDependencies ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, y)) if y >= 13 =>
Seq("com.beachape" %% "enumeratum" % "1.7.2")
case _ => Seq.empty
}
}
)
.dependsOn(core)

lazy val refined = project.in(modules / "refined")
.settings(crossScalaSettings)
.settings(commonSettings)
.settings(testSettings)
.settings(
name := "tethys-refined",
libraryDependencies ++= Seq(
"eu.timepit" %% "refined" % "0.10.1"
"eu.timepit" %% "refined" % "0.10.2"
)
)
.dependsOn(core)

lazy val benchmarks = project.in(modules / "benchmarks")
.settings(crossScalaSettings)
.settings(commonSettings)
.settings(
publishTo := None,
libraryDependencies ++= Seq(
"io.spray" %% "spray-json" % "1.3.6",
"org.json4s" %% "json4s-native" % "3.6.10",
"org.json4s" %% "json4s-jackson" % "3.6.10",
"io.circe" %% "circe-core" % "0.14.4",
"io.circe" %% "circe-generic" % "0.13.0",
"io.circe" %% "circe-jawn" % "0.13.0",
"io.circe" %% "circe-jackson210" % "0.13.0",
"com.typesafe.play" %% "play-json" % "2.9.2",
"org.knowm.xchart" % "xchart" % "3.8.0" exclude("de.erichseifert.vectorgraphics2d", "VectorGraphics2D") withSources()
"io.spray" %% "spray-json" % "1.3.6",
"org.json4s" %% "json4s-native" % "4.0.6",
"org.json4s" %% "json4s-jackson" % "4.0.6",
"io.circe" %% "circe-core" % "0.14.3",
"io.circe" %% "circe-generic" % "0.14.3",
"io.circe" %% "circe-jawn" % "0.14.3",
"io.circe" %% "circe-jackson210" % "0.14.0",
"com.typesafe.play" %% "play-json" % "2.10.0-RC7",
"org.knowm.xchart" % "xchart" % "3.8.2" exclude("de.erichseifert.vectorgraphics2d", "VectorGraphics2D") withSources()
),
libraryDependencies ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 13)) => Nil
case _ => Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full))
}
},
scalacOptions ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 13)) => Seq("-Ymacro-annotations")
case _ => Nil
case _ => Seq.empty
}
}
)
Expand Down
Binary file modified modules/benchmarks/images/ParsingPerformance.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified modules/benchmarks/images/WritingPerformance.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ object CirceBench {
}

object CirceJawnDataReader extends DataReader {
override def read(json: String): Seq[Data] = jawn.decode[Seq[Data]](json).right.get
override def read(json: String): Seq[Data] = jawn.decode[Seq[Data]](json).toOption.get
}

object CirceJacksonDataReader extends DataReader {
override def read(json: String): Seq[Data] = jackson.decode[Seq[Data]](json).right.get
override def read(json: String): Seq[Data] = jackson.decode[Seq[Data]](json).toOption.get
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import json.bench.{DataReader, DataWriter}
import org.json4s._

object Json4sBench {
implicit val format = DefaultFormats
implicit val format: DefaultFormats.type = DefaultFormats

object Json4sNativeDataProcessor extends DataWriter with DataReader {
override def write(seq: Seq[Data]): String = org.json4s.native.Serialization.write(seq)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ object TethysBench {

override def write(seq: Seq[Data]): String = seq.asJson

override def read(json: String): Seq[Data] = json.jsonAs[Seq[Data]].right.get
override def read(json: String): Seq[Data] = json.jsonAs[Seq[Data]].toOption.get
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package tethys.compat

import scala.collection.{IterableFactory, MapFactory, mutable}
import scala.quoted.*

trait CollectionBuilder[A, C] {
def newBuilder: mutable.Builder[A, C]
}

object CollectionBuilder {
final class IterableFactoryCollectionBuilder[A, C[_]](factory: IterableFactory[C]) extends CollectionBuilder[A, C[A]] {
def newBuilder: mutable.Builder[A, C[A]] = factory.newBuilder[A]
}

final class MapFactoryCollectionBuilder[K, V, M[_, _]](factory: MapFactory[M]) extends CollectionBuilder[(K, V), M[K, V]] {
def newBuilder: mutable.Builder[(K, V), M[K, V]] = factory.newBuilder[K, V]
}

inline given iterableFactoryCollectionBuilder[A, C[X] <: Iterable[X]]: CollectionBuilder[A, C[A]] =
${CollectionBuilderMacroImpl.fromIterableFactory[A, C]}

inline given mapFactoryCollectionBuilder[K, V, M[X, Y] <: Map[X, Y]]: MapFactoryCollectionBuilder[K, V, M] =
${CollectionBuilderMacroImpl.fromMapFactory[K, V, M]}

object CollectionBuilderMacroImpl {
def fromIterableFactory[A: Type, C[X] <: Iterable[X]: Type](using Quotes): Expr[IterableFactoryCollectionBuilder[A, C]] = {
import quotes.reflect.*

val factory = Ref(TypeRepr.of[C].typeSymbol.companionModule).asExprOf[IterableFactory[C]]
'{new tethys.compat.CollectionBuilder.IterableFactoryCollectionBuilder[A, C]($factory)}
}

def fromMapFactory[K: Type, V: Type, M[X, Y] <: Map[X, Y]: Type](using Quotes): Expr[MapFactoryCollectionBuilder[K, V, M]] = {
import quotes.reflect.*

val factory = Ref(TypeRepr.of[M].typeSymbol.companionModule).asExprOf[MapFactory[M]]
'{new tethys.compat.CollectionBuilder.MapFactoryCollectionBuilder[K, V, M]($factory)}
}
}
}
3 changes: 2 additions & 1 deletion modules/core/src/main/scala/tethys/commons/TokenNode.scala
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,8 @@ object TokenNode {
}
}

implicit class TokenListOps(val tokens: Seq[TokenNode]) extends AnyVal {
implicit class TokenListOps(private val tokens: Seq[TokenNode]) extends AnyVal {
import tethys.TokenIteratorOps
def tokensAs[A: JsonReader]: A = QueueIterator(tokens).readJson[A].fold(throw _, identity)
}
}
Loading

0 comments on commit ade5b16

Please sign in to comment.