From 0acf5af7469abadc8daf912dee4498d12ea50d8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Femen=C3=ADa?= <131800808+pablf@users.noreply.github.com> Date: Mon, 15 Jan 2024 09:32:48 +0100 Subject: [PATCH] Scala Native and Scala.js support (#638) * native and js support * native and js support * native and js support --- .github/workflows/ci.yml | 6 +- build.sbt | 247 +++++++++++---- project/BuildHelper.scala | 12 +- project/plugins.sbt | 2 +- .../test/scala/zio/schema/SchemaSpec.scala | 28 +- .../zio/schema/codec/AvroAnnotations.scala | 0 .../scala/zio/schema/codec/AvroCodec.scala | 0 .../zio/schema/codec/AvroPropMarker.scala | 0 .../zio/schema/codec/AvroSchemaCodec.scala | 0 .../zio/schema/codec/AvroCodecSpec.scala | 0 .../schema/codec/AvroSchemaCodecSpec.scala | 0 .../zio/schema/codec/BsonSchemaCodec.scala | 0 .../codec/BsonSchemaCodecGenericSpec.scala | 0 .../scala/zio/schema/codec/BsonConfig.scala | 0 .../schema/codec/BsonSchemaCodecSpec.scala | 0 .../scala/zio/schema/codec/MixedConfig.scala | 0 .../scala/zio/schema/codec/SchemaConfig.scala | 0 .../zio/schema/SchemaValidationSpec.scala | 2 +- .../scala/zio/schema/codec/JsonCodec.scala | 4 +- .../zio/schema/codec/JsonCodecSpec.scala | 4 +- .../zio/schema/codec/MessagePackCodec.scala | 0 .../zio/schema/codec/MessagePackDecoder.scala | 0 .../zio/schema/codec/MessagePackEncoder.scala | 0 .../schema/codec/MessagePackCodecSpec.scala | 0 .../zio/schema/codec/ProtobufCodecSpec.scala | 24 +- .../zio/schema/codec/ChunkTransport.scala | 0 .../scala/zio/schema/codec/ThriftCodec.scala | 0 .../src/test/resources/testing-data.thrift | 0 .../zio/schema/codec/ThriftCodecSpec.scala | 0 .../schema/codec/generated/BasicDouble.java | 0 .../zio/schema/codec/generated/BasicInt.java | 0 .../schema/codec/generated/BasicString.java | 0 .../zio/schema/codec/generated/BoolValue.java | 0 .../zio/schema/codec/generated/Color.java | 0 .../zio/schema/codec/generated/Embedded.java | 0 .../zio/schema/codec/generated/EnumValue.java | 0 .../schema/codec/generated/Enumeration.java | 0 .../zio/schema/codec/generated/HighArity.java | 0 .../zio/schema/codec/generated/IntList.java | 0 .../zio/schema/codec/generated/IntValue.java | 0 .../zio/schema/codec/generated/MapValue.java | 0 .../zio/schema/codec/generated/OneOf.java | 0 .../zio/schema/codec/generated/Record.java | 0 .../zio/schema/codec/generated/SetValue.java | 0 .../schema/codec/generated/StringList.java | 0 .../schema/codec/generated/StringValue.java | 0 .../zio/schema/SchemaPlatformSpecific.scala | 3 + .../main/scala/zio/schema/StandardType.scala | 293 ++++++++++++++++++ .../zio/schema/SchemaPlatformSpecific.scala | 14 + .../main/scala/zio/schema/StandardType.scala | 0 .../zio/schema/SchemaPlatformSpecific.scala | 3 + .../main/scala/zio/schema/StandardType.scala | 293 ++++++++++++++++++ .../src/main/scala/zio/schema/Differ.scala | 2 +- .../main/scala/zio/schema/DynamicValue.scala | 30 +- .../src/main/scala/zio/schema/Schema.scala | 11 +- .../schema/validation/ValidationSpec.scala | 14 +- 56 files changed, 862 insertions(+), 130 deletions(-) rename zio-schema-avro/{shared => }/src/main/scala/zio/schema/codec/AvroAnnotations.scala (100%) rename zio-schema-avro/{shared => }/src/main/scala/zio/schema/codec/AvroCodec.scala (100%) rename zio-schema-avro/{shared => }/src/main/scala/zio/schema/codec/AvroPropMarker.scala (100%) rename zio-schema-avro/{shared => }/src/main/scala/zio/schema/codec/AvroSchemaCodec.scala (100%) rename zio-schema-avro/{shared => }/src/test/scala-2/zio/schema/codec/AvroCodecSpec.scala (100%) rename zio-schema-avro/{shared => }/src/test/scala-2/zio/schema/codec/AvroSchemaCodecSpec.scala (100%) rename zio-schema-bson/{shared => }/src/main/scala/zio/schema/codec/BsonSchemaCodec.scala (100%) rename zio-schema-bson/{shared => }/src/test/scala-2.x/zio/schema/codec/BsonSchemaCodecGenericSpec.scala (100%) rename zio-schema-bson/{shared => }/src/test/scala/zio/schema/codec/BsonConfig.scala (100%) rename zio-schema-bson/{shared => }/src/test/scala/zio/schema/codec/BsonSchemaCodecSpec.scala (100%) rename zio-schema-bson/{shared => }/src/test/scala/zio/schema/codec/MixedConfig.scala (100%) rename zio-schema-bson/{shared => }/src/test/scala/zio/schema/codec/SchemaConfig.scala (100%) rename zio-schema-msg-pack/{shared => }/src/main/scala/zio/schema/codec/MessagePackCodec.scala (100%) rename zio-schema-msg-pack/{shared => }/src/main/scala/zio/schema/codec/MessagePackDecoder.scala (100%) rename zio-schema-msg-pack/{shared => }/src/main/scala/zio/schema/codec/MessagePackEncoder.scala (100%) rename zio-schema-msg-pack/{shared => }/src/test/scala-2/zio/schema/codec/MessagePackCodecSpec.scala (100%) rename zio-schema-thrift/{shared => }/src/main/scala/zio/schema/codec/ChunkTransport.scala (100%) rename zio-schema-thrift/{shared => }/src/main/scala/zio/schema/codec/ThriftCodec.scala (100%) rename zio-schema-thrift/{shared => }/src/test/resources/testing-data.thrift (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/BasicDouble.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/BasicInt.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/BasicString.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/BoolValue.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/Color.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/Embedded.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/EnumValue.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/Enumeration.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/HighArity.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/IntList.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/IntValue.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/MapValue.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/OneOf.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/Record.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/SetValue.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/StringList.java (100%) rename zio-schema-thrift/{shared => }/src/test/scala-2/zio/schema/codec/generated/StringValue.java (100%) create mode 100644 zio-schema/js/src/main/scala/zio/schema/SchemaPlatformSpecific.scala create mode 100644 zio-schema/js/src/main/scala/zio/schema/StandardType.scala create mode 100644 zio-schema/jvm/src/main/scala/zio/schema/SchemaPlatformSpecific.scala rename zio-schema/{shared => jvm}/src/main/scala/zio/schema/StandardType.scala (100%) create mode 100644 zio-schema/native/src/main/scala/zio/schema/SchemaPlatformSpecific.scala create mode 100644 zio-schema/native/src/main/scala/zio/schema/StandardType.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b494a6ac..68b2f8d96 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,7 @@ jobs: matrix: java: ['adopt@1.8', 'adopt@1.11'] scala: ['2.12.18', '2.13.12', '3.3.1'] + platform: ['JVM', 'Native', 'JS'] steps: - uses: actions/checkout@v3.0.0 with: @@ -48,8 +49,11 @@ jobs: java-version: ${{ matrix.java }} - name: Cache scala dependencies uses: coursier/cache-action@v6 + - name: Install libuv + if: matrix.platform == 'Native' + run: sudo apt-get update && sudo apt-get install -y libuv1-dev - name: Run tests - run: sbt ++${{ matrix.scala }}! test + run: sbt ++${{ matrix.scala }}! test${{ matrix.platform }} publish: runs-on: ubuntu-20.04 diff --git a/build.sbt b/build.sbt index fe773ab73..258e7076b 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,6 @@ -import sbtcrossproject.CrossPlugin.autoImport.crossProject +import sbtcrossproject.CrossPlugin.autoImport._ import BuildHelper.{ crossProjectSettings, _ } -import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport.scalaJSUseMainModuleInitializer +import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._ inThisBuild( List( @@ -35,6 +35,7 @@ inThisBuild( ) ThisBuild / publishTo := sonatypePublishToBundle.value +scalacOptions ++= Seq("-scalajs") addCommandAlias("prepare", "fix; fmt") addCommandAlias("fmt", "all scalafmtSbt scalafmtAll") @@ -42,6 +43,25 @@ addCommandAlias("fmtCheck", "all scalafmtSbtCheck scalafmtCheckAll") addCommandAlias("fix", "scalafixAll") addCommandAlias("fixCheck", "scalafixAll --check") +addCommandAlias( + "testJVM", + "testsJVM/test; zioSchemaMacrosJVM/test; zioSchemaJVM/test; zioSchemaDerivationJVM/test;" + + "zioSchemaOpticsJVM/test; zioSchemaJsonJVM/test; zioSchemaProtobufJVM/test; zioSchemaZioTestJVM/test;" + + "zioSchemaAvro/test; zioSchemaThrift/test; zioSchemaBson/test; zioSchemaMsgPack/test" +) + +addCommandAlias( + "testNative", + "zioSchemaMacrosNative/test; zioSchemaDerivationNative/test; zioSchemaJsonNative/test; zioSchemaOpticsNative/test;" + + "testsNative/test; zioSchemaNative/test; zioSchemaZioTestNative/test; zioSchemaProtobufNative/test;" +) + +addCommandAlias( + "testJS", + "zioSchemaMacrosJS/test; zioSchemaDerivationJS/test; zioSchemaJsonJS/test; zioSchemaOpticsJS/test; testsJS/test; zioSchemaJS/test; " + + "zioSchemaZioTestJS/test; zioSchemaProtobufJS/test;" +) + lazy val root = project .in(file(".")) .settings( @@ -52,68 +72,101 @@ lazy val root = project .aggregate( zioSchemaMacrosJVM, zioSchemaMacrosJS, + zioSchemaMacros.native, zioSchemaJVM, zioSchemaJS, + zioSchema.native, zioSchemaDerivationJVM, zioSchemaDerivationJS, + zioSchemaDerivation.native, zioSchemaJsonJVM, zioSchemaJsonJS, + zioSchemaJson.native, zioSchemaOpticsJS, zioSchemaOpticsJVM, + zioSchemaOptics.native, zioSchemaProtobufJS, zioSchemaProtobufJVM, + zioSchemaProtobuf.native, zioSchemaExamplesJS, zioSchemaExamplesJVM, + zioSchemaExamples.native, testsJVM, testsJS, + tests.native, zioSchemaZioTestJVM, zioSchemaZioTestJS, - zioSchemaThriftJS, - zioSchemaThriftJVM, - zioSchemaAvroJS, - zioSchemaAvroJVM, - zioSchemaBsonJVM, - zioSchemaMsgPackJS, - zioSchemaMsgPackJVM, + zioSchemaZioTest.native, + zioSchemaThrift, + zioSchemaAvro, + zioSchemaBson, + zioSchemaMsgPack, docs ) -lazy val tests = crossProject(JSPlatform, JVMPlatform) +lazy val tests = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("tests")) .dependsOn(zioSchemaDerivation % "compile->test", zioSchema % "test->test", zioSchemaZioTest % "compile->test") .settings(stdSettings("zio-schema-tests")) .settings(publish / skip := true) .settings(crossProjectSettings) .settings(buildInfoSettings("zio.schema")) + .settings(testDeps) lazy val testsJS = tests.js .settings(scalaJSUseMainModuleInitializer := true) lazy val testsJVM = tests.jvm -lazy val zioSchemaMacros = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchemaMacros = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("zio-schema-macros")) .settings(stdSettings("zio-schema-macros")) .settings(crossProjectSettings) .settings(buildInfoSettings("zio.schema")) .settings(macroDefinitionSettings) + .nativeSettings(Test / fork := false) + .nativeSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0" + ) + ) + .jsSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0", + "io.github.cquiroz" %%% "scala-java-time-tzdb" % "2.5.0" + ) + ) + .settings(testDeps) lazy val zioSchemaMacrosJS = zioSchemaMacros.js lazy val zioSchemaMacrosJVM = zioSchemaMacros.jvm -lazy val zioSchema = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchema = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("zio-schema")) .settings(stdSettings("zio-schema")) .settings(crossProjectSettings) .settings(buildInfoSettings("zio.schema")) .settings( libraryDependencies ++= Seq( - "dev.zio" %% "zio" % zioVersion, - "dev.zio" %% "zio-streams" % zioVersion, - "dev.zio" %% "zio-prelude" % zioPreludeVersion, - "dev.zio" %% "zio-constraintless" % zioConstraintlessVersion + "dev.zio" %%% "zio" % zioVersion, + "dev.zio" %%% "zio-streams" % zioVersion, + "dev.zio" %%% "zio-prelude" % zioPreludeVersion, + "dev.zio" %%% "zio-constraintless" % zioConstraintlessVersion + ) + ) + .nativeSettings(Test / fork := false) + .nativeSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0" ) ) + .jsSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0", + "io.github.cquiroz" %%% "scala-java-time-tzdb" % "2.5.0" + ) + ) + .settings(testDeps) .dependsOn(zioSchemaMacros) lazy val zioSchemaJS = zioSchema.js @@ -121,7 +174,7 @@ lazy val zioSchemaJS = zioSchema.js lazy val zioSchemaJVM = zioSchema.jvm -lazy val zioSchemaDerivation = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchemaDerivation = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("zio-schema-derivation")) .dependsOn(zioSchema, zioSchema % "test->test") .settings(stdSettings("zio-schema-derivation")) @@ -129,12 +182,23 @@ lazy val zioSchemaDerivation = crossProject(JSPlatform, JVMPlatform) .settings(buildInfoSettings("zio.schema")) .settings( libraryDependencies ++= Seq( - "dev.zio" %% "zio" % zioVersion, - "dev.zio" %% "zio-streams" % zioVersion, - "dev.zio" %% "zio-prelude" % zioPreludeVersion + "dev.zio" %%% "zio" % zioVersion, + "dev.zio" %%% "zio-streams" % zioVersion, + "dev.zio" %%% "zio-prelude" % zioPreludeVersion ) ) - .settings( + .jvmSettings( + libraryDependencies ++= { + CrossVersion.partialVersion(scalaVersion.value) match { + case Some((2, _)) => + Seq( + "org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided + ) + case _ => Seq() + } + } + ) + .jsSettings( libraryDependencies ++= { CrossVersion.partialVersion(scalaVersion.value) match { case Some((2, _)) => @@ -145,13 +209,25 @@ lazy val zioSchemaDerivation = crossProject(JSPlatform, JVMPlatform) } } ) + .nativeSettings(Test / fork := false) + .nativeSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0" + ) + ) + .jsSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0", + "io.github.cquiroz" %%% "scala-java-time-tzdb" % "2.5.0" + ) + ) + .settings(testDeps) lazy val zioSchemaDerivationJS = zioSchemaDerivation.js - .settings(scalaJSUseMainModuleInitializer := true) lazy val zioSchemaDerivationJVM = zioSchemaDerivation.jvm -lazy val zioSchemaJson = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchemaJson = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("zio-schema-json")) .dependsOn(zioSchema, zioSchemaDerivation, tests % "test->test") .settings(stdSettings("zio-schema-json")) @@ -159,34 +235,60 @@ lazy val zioSchemaJson = crossProject(JSPlatform, JVMPlatform) .settings(buildInfoSettings("zio.schema.json")) .settings( libraryDependencies ++= Seq( - "dev.zio" %% "zio-json" % zioJsonVersion + "dev.zio" %%% "zio-json" % zioJsonVersion + ) + ) + .nativeSettings(Test / fork := false) + .nativeSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0" + ) + ) + .jsSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0", + "io.github.cquiroz" %%% "scala-java-time-tzdb" % "2.5.0" ) ) + .jsSettings(scalaJSLinkerConfig ~= { _.withOptimizer(false) }) + .settings(testDeps) lazy val zioSchemaJsonJS = zioSchemaJson.js .settings(scalaJSUseMainModuleInitializer := true) lazy val zioSchemaJsonJVM = zioSchemaJson.jvm -lazy val zioSchemaProtobuf = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchemaProtobuf = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("zio-schema-protobuf")) .dependsOn(zioSchema, zioSchemaDerivation, tests % "test->test") .settings(stdSettings("zio-schema-protobuf")) .settings(dottySettings) .settings(crossProjectSettings) .settings(buildInfoSettings("zio.schema.protobuf")) + .nativeSettings(Test / fork := false) + .nativeSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0" + ) + ) + .jsSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0", + "io.github.cquiroz" %%% "scala-java-time-tzdb" % "2.5.0" + ) + ) + .settings(testDeps) lazy val zioSchemaProtobufJS = zioSchemaProtobuf.js .settings(scalaJSUseMainModuleInitializer := true) lazy val zioSchemaProtobufJVM = zioSchemaProtobuf.jvm -lazy val zioSchemaThrift = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchemaThrift = project .in(file("zio-schema-thrift")) - .dependsOn(zioSchema, zioSchemaDerivation, tests % "test->test") + .dependsOn(zioSchema.jvm, zioSchemaDerivation.jvm, tests.jvm % "test->test") .settings(stdSettings("zio-schema-thrift")) .settings(dottySettings) - .settings(crossProjectSettings) .settings(buildInfoSettings("zio.schema.thrift")) .settings( libraryDependencies ++= Seq( @@ -194,18 +296,13 @@ lazy val zioSchemaThrift = crossProject(JSPlatform, JVMPlatform) "javax.annotation" % "javax.annotation-api" % javaxAnnotationApiVersion ) ) + .settings(testDeps) -lazy val zioSchemaThriftJS = zioSchemaThrift.js - .settings(scalaJSUseMainModuleInitializer := true) - -lazy val zioSchemaThriftJVM = zioSchemaThrift.jvm - -lazy val zioSchemaMsgPack = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchemaMsgPack = project .in(file("zio-schema-msg-pack")) - .dependsOn(zioSchema, zioSchemaDerivation, tests % "test->test") + .dependsOn(zioSchema.jvm, zioSchemaDerivation.jvm, tests.jvm % "test->test") .settings(stdSettings("zio-schema-msg-pack")) .settings(dottySettings) - .settings(crossProjectSettings) .settings(buildInfoSettings("zio.schema.msgpack")) .settings( libraryDependencies ++= Seq( @@ -214,18 +311,13 @@ lazy val zioSchemaMsgPack = crossProject(JSPlatform, JVMPlatform) "com.fasterxml.jackson.module" %% "jackson-module-scala" % jacksonScalaVersion % Test ) ) + .settings(testDeps) -lazy val zioSchemaMsgPackJS = zioSchemaMsgPack.js - .settings(scalaJSUseMainModuleInitializer := true) - -lazy val zioSchemaMsgPackJVM = zioSchemaMsgPack.jvm - -lazy val zioSchemaAvro = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchemaAvro = project .in(file("zio-schema-avro")) - .dependsOn(zioSchema, zioSchemaDerivation, tests % "test->test") + .dependsOn(zioSchema.jvm, zioSchemaDerivation.jvm, tests.jvm % "test->test") .settings(stdSettings("zio-schema-avro")) .settings(dottySettings) - .settings(crossProjectSettings) .settings(buildInfoSettings("zio.schema.avro")) .settings( libraryDependencies ++= Seq( @@ -233,17 +325,12 @@ lazy val zioSchemaAvro = crossProject(JSPlatform, JVMPlatform) "org.apache.avro" % "avro" % avroVersion ) ) + .settings(testDeps) -lazy val zioSchemaAvroJS = zioSchemaAvro.js - .settings(scalaJSUseMainModuleInitializer := true) - -lazy val zioSchemaAvroJVM = zioSchemaAvro.jvm - -lazy val zioSchemaBson = crossProject(JVMPlatform) +lazy val zioSchemaBson = project .in(file("zio-schema-bson")) - .dependsOn(zioSchema, zioSchemaDerivation, zioSchemaZioTest % Test, tests % "test->test") + .dependsOn(zioSchema.jvm, zioSchemaDerivation.jvm, zioSchemaZioTest.jvm % Test, tests.jvm % "test->test") .settings(stdSettings("zio-schema-bson")) - .settings(crossProjectSettings) .settings(buildInfoSettings("zio.schema.bson")) .settings( libraryDependencies ++= Seq( @@ -255,10 +342,9 @@ lazy val zioSchemaBson = crossProject(JVMPlatform) ), scalacOptions -= "-Xfatal-warnings" // cross-version imports ) + .settings(testDeps) -lazy val zioSchemaBsonJVM = zioSchemaBson.jvm - -lazy val zioSchemaOptics = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchemaOptics = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("zio-schema-optics")) .dependsOn(zioSchema, zioSchemaDerivation, tests % "test->test") .settings(stdSettings("zio-schema-optics")) @@ -267,16 +353,29 @@ lazy val zioSchemaOptics = crossProject(JSPlatform, JVMPlatform) .settings(buildInfoSettings("zio.schema.optics")) .settings( libraryDependencies ++= Seq( - "dev.zio" %% "zio-optics" % zioOpticsVersion + "dev.zio" %%% "zio-optics" % zioOpticsVersion + ) + ) + .nativeSettings(Test / fork := false) + .nativeSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0" + ) + ) + .jsSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0", + "io.github.cquiroz" %%% "scala-java-time-tzdb" % "2.5.0" ) ) + .settings(testDeps) lazy val zioSchemaOpticsJS = zioSchemaOptics.js .settings(scalaJSUseMainModuleInitializer := true) lazy val zioSchemaOpticsJVM = zioSchemaOptics.jvm -lazy val zioSchemaExamples = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchemaExamples = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("zio-schema-examples")) .settings(stdSettings("zio-schema-examples")) .settings(crossScalaVersions -= Scala212) @@ -287,13 +386,26 @@ lazy val zioSchemaExamples = crossProject(JSPlatform, JVMPlatform) scalacOptions -= "-Yno-imports", scalacOptions -= "-Xfatal-warnings" ) + .nativeSettings(Test / fork := false) + .nativeSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0" + ) + ) + .jsSettings( + libraryDependencies ++= Seq( + "io.github.cquiroz" %%% "scala-java-time" % "2.5.0", + "io.github.cquiroz" %%% "scala-java-time-tzdb" % "2.5.0" + ) + ) + .settings(testDeps) lazy val zioSchemaExamplesJS = zioSchemaExamples.js .settings(scalaJSUseMainModuleInitializer := true) lazy val zioSchemaExamplesJVM = zioSchemaExamples.jvm -lazy val zioSchemaZioTest = crossProject(JSPlatform, JVMPlatform) +lazy val zioSchemaZioTest = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("zio-schema-zio-test")) .dependsOn(zioSchema, zioSchemaDerivation) .settings(stdSettings("zio-schema-zio-test")) @@ -301,9 +413,10 @@ lazy val zioSchemaZioTest = crossProject(JSPlatform, JVMPlatform) .settings(buildInfoSettings("zio.schema.test")) .settings( libraryDependencies ++= Seq( - "dev.zio" %% "zio-test" % zioVersion + "dev.zio" %%% "zio-test" % zioVersion ) ) + .settings(testDeps) lazy val zioSchemaZioTestJS = zioSchemaZioTest.js .settings(scalaJSUseMainModuleInitializer := true) @@ -342,14 +455,22 @@ lazy val docs = project |sbt test |```""".stripMargin ) + .settings(testDeps) .dependsOn( zioSchemaJVM, zioSchemaProtobufJVM, zioSchemaJsonJVM, zioSchemaOpticsJVM, - zioSchemaAvroJVM, - zioSchemaBsonJVM, - zioSchemaMsgPackJVM, - zioSchemaThriftJVM + zioSchemaAvro, + zioSchemaBson, + zioSchemaMsgPack, + zioSchemaThrift ) .enablePlugins(WebsitePlugin) + +lazy val testDeps = Seq( + libraryDependencies ++= Seq( + "dev.zio" %%% "zio-test" % zioVersion % Test, + "dev.zio" %%% "zio-test-sbt" % zioVersion % Test + ) +) diff --git a/project/BuildHelper.scala b/project/BuildHelper.scala index 9c7fbb9f7..6d7780c8b 100644 --- a/project/BuildHelper.scala +++ b/project/BuildHelper.scala @@ -1,10 +1,11 @@ import sbt._ import Keys._ -import sbtcrossproject.CrossPlugin.autoImport.crossProjectPlatform +import sbtcrossproject.CrossPlugin.autoImport._ import sbtbuildinfo._ import BuildInfoKeys._ import scalafix.sbt.ScalafixPlugin.autoImport._ +import scalanativecrossproject.NativePlatform object BuildHelper { @@ -40,11 +41,6 @@ object BuildHelper { val thriftVersion = "0.16.0" val javaxAnnotationApiVersion = "1.3.2" - private val testDeps = Seq( - "dev.zio" %% "zio-test" % zioVersion % Test, - "dev.zio" %% "zio-test-sbt" % zioVersion % Test - ) - def macroDefinitionSettings = Seq( scalacOptions += "-language:experimental.macros", libraryDependencies ++= { @@ -203,8 +199,8 @@ object BuildHelper { name := s"$prjName", crossScalaVersions := Seq(Scala213, Scala212, Scala3), ThisBuild / scalaVersion := Scala213, //crossScalaVersions.value.head, //Scala3, - scalacOptions := compilerOptions(scalaVersion.value, optimize = !isSnapshot.value), - libraryDependencies ++= compileOnlyDeps(scalaVersion.value) ++ testDeps, + scalacOptions ++= compilerOptions(scalaVersion.value, optimize = !isSnapshot.value), + libraryDependencies ++= compileOnlyDeps(scalaVersion.value), ThisBuild / semanticdbEnabled := scalaVersion.value != Scala3, // enable SemanticDB, ThisBuild / semanticdbOptions += "-P:semanticdb:synthetics:on", ThisBuild / semanticdbVersion := scalafixSemanticdb.revision, diff --git a/project/plugins.sbt b/project/plugins.sbt index 311555266..1b7f275b0 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,7 +1,7 @@ addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.5") addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.11.1") addSbtPlugin("com.github.cb372" % "sbt-explicit-dependencies" % "0.3.1") -addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.14.0") +addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.15.0") addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.2") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.11.0") addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.5.12") diff --git a/tests/shared/src/test/scala/zio/schema/SchemaSpec.scala b/tests/shared/src/test/scala/zio/schema/SchemaSpec.scala index 08cb29d35..7c1e29317 100644 --- a/tests/shared/src/test/scala/zio/schema/SchemaSpec.scala +++ b/tests/shared/src/test/scala/zio/schema/SchemaSpec.scala @@ -5,6 +5,7 @@ import scala.collection.immutable.ListMap import zio.Chunk import zio.schema.CaseSet._ +import zio.schema.SchemaAssertions.hasSameSchema import zio.test.Assertion._ import zio.test._ @@ -13,32 +14,31 @@ object SchemaSpec extends ZIOSpecDefault { def spec: Spec[Environment, Any] = suite("Schema Spec")( suite("Should have valid equals")( test("primitive") { - assert(schemaUnit)(equalTo(schemaUnit)) + assert(schemaUnit)(hasSameSchema(schemaUnit)) }, test("sequence") { - assert(Schema.chunk(schemaUnit))(equalTo(Schema.chunk(schemaUnit))) + assert(Schema.chunk(schemaUnit))(hasSameSchema(Schema.chunk(schemaUnit))) } @@ TestAspect.scala2Only, test("tuple") { - assert(Schema.Tuple2(schemaUnit, schemaUnit))(equalTo(Schema.Tuple2(schemaUnit, schemaUnit))) && + assert(Schema.Tuple2(schemaUnit, schemaUnit))(hasSameSchema(Schema.Tuple2(schemaUnit, schemaUnit))) && assert(Schema.Tuple2(schemaTransform, schemaTransform))( - equalTo(Schema.Tuple2(schemaTransform, schemaTransform)) + hasSameSchema(Schema.Tuple2(schemaTransform, schemaTransform)) ) }, - // TODO: disabled due to the fact that get operation is a different lambda instance -// test("record") { -// assert(schemaRecord("key"))(equalTo(schemaRecord("key"))) && -// assert(schemaRecord("key1"))(not(equalTo(schemaRecord("key2")))) -// }, + test("record") { + assert(schemaRecord("key"))(hasSameSchema(schemaRecord("key"))) && + assert(schemaRecord("key1"))(not(hasSameSchema(schemaRecord("key2")))) + }, test("transform") { - assert(schemaTransform)(equalTo(schemaTransform)) && - assert(schemaTransformMethod)(equalTo(schemaTransformMethod)) + assert(schemaTransform)(hasSameSchema(schemaTransform)) && + assert(schemaTransformMethod)(hasSameSchema(schemaTransformMethod)) } @@ TestAspect.scala2Only, test("optional") { - assert(Schema.Optional(schemaUnit))(equalTo(Schema.Optional(schemaUnit))) + assert(Schema.Optional(schemaUnit))(hasSameSchema(Schema.Optional(schemaUnit))) }, test("enumeration") { - assert(schemaEnum("key"))(equalTo(schemaEnum("key"))) && - assert(schemaEnum("key1"))(not(equalTo(schemaEnum("key2")))) + assert(schemaEnum("key"))(hasSameSchema(schemaEnum("key"))) && + assert(schemaEnum("key1"))(not(hasSameSchema(schemaEnum("key2")))) } @@ TestAspect.scala2Only ), diff --git a/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroAnnotations.scala b/zio-schema-avro/src/main/scala/zio/schema/codec/AvroAnnotations.scala similarity index 100% rename from zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroAnnotations.scala rename to zio-schema-avro/src/main/scala/zio/schema/codec/AvroAnnotations.scala diff --git a/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroCodec.scala b/zio-schema-avro/src/main/scala/zio/schema/codec/AvroCodec.scala similarity index 100% rename from zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroCodec.scala rename to zio-schema-avro/src/main/scala/zio/schema/codec/AvroCodec.scala diff --git a/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroPropMarker.scala b/zio-schema-avro/src/main/scala/zio/schema/codec/AvroPropMarker.scala similarity index 100% rename from zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroPropMarker.scala rename to zio-schema-avro/src/main/scala/zio/schema/codec/AvroPropMarker.scala diff --git a/zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroSchemaCodec.scala b/zio-schema-avro/src/main/scala/zio/schema/codec/AvroSchemaCodec.scala similarity index 100% rename from zio-schema-avro/shared/src/main/scala/zio/schema/codec/AvroSchemaCodec.scala rename to zio-schema-avro/src/main/scala/zio/schema/codec/AvroSchemaCodec.scala diff --git a/zio-schema-avro/shared/src/test/scala-2/zio/schema/codec/AvroCodecSpec.scala b/zio-schema-avro/src/test/scala-2/zio/schema/codec/AvroCodecSpec.scala similarity index 100% rename from zio-schema-avro/shared/src/test/scala-2/zio/schema/codec/AvroCodecSpec.scala rename to zio-schema-avro/src/test/scala-2/zio/schema/codec/AvroCodecSpec.scala diff --git a/zio-schema-avro/shared/src/test/scala-2/zio/schema/codec/AvroSchemaCodecSpec.scala b/zio-schema-avro/src/test/scala-2/zio/schema/codec/AvroSchemaCodecSpec.scala similarity index 100% rename from zio-schema-avro/shared/src/test/scala-2/zio/schema/codec/AvroSchemaCodecSpec.scala rename to zio-schema-avro/src/test/scala-2/zio/schema/codec/AvroSchemaCodecSpec.scala diff --git a/zio-schema-bson/shared/src/main/scala/zio/schema/codec/BsonSchemaCodec.scala b/zio-schema-bson/src/main/scala/zio/schema/codec/BsonSchemaCodec.scala similarity index 100% rename from zio-schema-bson/shared/src/main/scala/zio/schema/codec/BsonSchemaCodec.scala rename to zio-schema-bson/src/main/scala/zio/schema/codec/BsonSchemaCodec.scala diff --git a/zio-schema-bson/shared/src/test/scala-2.x/zio/schema/codec/BsonSchemaCodecGenericSpec.scala b/zio-schema-bson/src/test/scala-2.x/zio/schema/codec/BsonSchemaCodecGenericSpec.scala similarity index 100% rename from zio-schema-bson/shared/src/test/scala-2.x/zio/schema/codec/BsonSchemaCodecGenericSpec.scala rename to zio-schema-bson/src/test/scala-2.x/zio/schema/codec/BsonSchemaCodecGenericSpec.scala diff --git a/zio-schema-bson/shared/src/test/scala/zio/schema/codec/BsonConfig.scala b/zio-schema-bson/src/test/scala/zio/schema/codec/BsonConfig.scala similarity index 100% rename from zio-schema-bson/shared/src/test/scala/zio/schema/codec/BsonConfig.scala rename to zio-schema-bson/src/test/scala/zio/schema/codec/BsonConfig.scala diff --git a/zio-schema-bson/shared/src/test/scala/zio/schema/codec/BsonSchemaCodecSpec.scala b/zio-schema-bson/src/test/scala/zio/schema/codec/BsonSchemaCodecSpec.scala similarity index 100% rename from zio-schema-bson/shared/src/test/scala/zio/schema/codec/BsonSchemaCodecSpec.scala rename to zio-schema-bson/src/test/scala/zio/schema/codec/BsonSchemaCodecSpec.scala diff --git a/zio-schema-bson/shared/src/test/scala/zio/schema/codec/MixedConfig.scala b/zio-schema-bson/src/test/scala/zio/schema/codec/MixedConfig.scala similarity index 100% rename from zio-schema-bson/shared/src/test/scala/zio/schema/codec/MixedConfig.scala rename to zio-schema-bson/src/test/scala/zio/schema/codec/MixedConfig.scala diff --git a/zio-schema-bson/shared/src/test/scala/zio/schema/codec/SchemaConfig.scala b/zio-schema-bson/src/test/scala/zio/schema/codec/SchemaConfig.scala similarity index 100% rename from zio-schema-bson/shared/src/test/scala/zio/schema/codec/SchemaConfig.scala rename to zio-schema-bson/src/test/scala/zio/schema/codec/SchemaConfig.scala diff --git a/zio-schema-derivation/shared/src/test/scala/zio/schema/SchemaValidationSpec.scala b/zio-schema-derivation/shared/src/test/scala/zio/schema/SchemaValidationSpec.scala index 4173f3de2..bc073feaf 100644 --- a/zio-schema-derivation/shared/src/test/scala/zio/schema/SchemaValidationSpec.scala +++ b/zio-schema-derivation/shared/src/test/scala/zio/schema/SchemaValidationSpec.scala @@ -6,7 +6,7 @@ import zio.schema.annotation.validate import zio.schema.validation.{ Validation, ValidationError } import zio.test._ -object SchemaValidationSpec extends ZIOSpecDefault { +object SchemaValidationSpecJVM extends ZIOSpecDefault { import Assertion._ final case class ExampleData( diff --git a/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala b/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala index af8d3b99f..813aec6b4 100644 --- a/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala +++ b/zio-schema-json/shared/src/main/scala/zio/schema/codec/JsonCodec.scala @@ -326,7 +326,7 @@ object JsonCodec { } } - private def dynamicEncoder(schema: Schema.Dynamic, cfg: Config): ZJsonEncoder[DynamicValue] = { + private[codec] def dynamicEncoder(schema: Schema.Dynamic, cfg: JsonCodec.Config): ZJsonEncoder[DynamicValue] = { val directMapping = schema.annotations.exists { case directDynamicMapping() => true case _ => false @@ -877,7 +877,7 @@ object JsonCodec { //scalafmt: { maxColumn = 400, optIn.configStyleArguments = false } private[codec] object ProductDecoder { - import zio.schema.codec.JsonCodec.JsonDecoder.schemaDecoder + import JsonCodec.JsonDecoder.schemaDecoder private[codec] def caseClass0Decoder[Z](discriminator: Int, schema: Schema.CaseClass0[Z]): ZJsonDecoder[Z] = { (trace: List[JsonError], in: RetractReader) => if (discriminator == -1) Codecs.unitDecoder.unsafeDecode(trace, in) diff --git a/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala b/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala index 5fb306e63..c228c49c7 100644 --- a/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala +++ b/zio-schema-json/shared/src/test/scala-2/zio/schema/codec/JsonCodecSpec.scala @@ -29,7 +29,7 @@ object JsonCodecSpec extends ZIOSpecDefault { encoderSuite, decoderSuite, encoderDecoderSuite - ) @@ timeout(90.seconds) + ) @@ timeout(180.seconds) // TODO: Add tests for the pipeline contract. @@ -1226,7 +1226,7 @@ object JsonCodecSpec extends ZIOSpecDefault { ) } } - } @@ TestAspect.size(1000) @@ TestAspect.samples(1000), + } @@ TestAspect.size(1000) @@ TestAspect.samples(1000) @@ TestAspect.exceptNative, suite("meta schema")( test("primitive string meta schema") { assertEncodesThenDecodes(MetaSchema.schema, Schema[String].ast) diff --git a/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackCodec.scala b/zio-schema-msg-pack/src/main/scala/zio/schema/codec/MessagePackCodec.scala similarity index 100% rename from zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackCodec.scala rename to zio-schema-msg-pack/src/main/scala/zio/schema/codec/MessagePackCodec.scala diff --git a/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackDecoder.scala b/zio-schema-msg-pack/src/main/scala/zio/schema/codec/MessagePackDecoder.scala similarity index 100% rename from zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackDecoder.scala rename to zio-schema-msg-pack/src/main/scala/zio/schema/codec/MessagePackDecoder.scala diff --git a/zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackEncoder.scala b/zio-schema-msg-pack/src/main/scala/zio/schema/codec/MessagePackEncoder.scala similarity index 100% rename from zio-schema-msg-pack/shared/src/main/scala/zio/schema/codec/MessagePackEncoder.scala rename to zio-schema-msg-pack/src/main/scala/zio/schema/codec/MessagePackEncoder.scala diff --git a/zio-schema-msg-pack/shared/src/test/scala-2/zio/schema/codec/MessagePackCodecSpec.scala b/zio-schema-msg-pack/src/test/scala-2/zio/schema/codec/MessagePackCodecSpec.scala similarity index 100% rename from zio-schema-msg-pack/shared/src/test/scala-2/zio/schema/codec/MessagePackCodecSpec.scala rename to zio-schema-msg-pack/src/test/scala-2/zio/schema/codec/MessagePackCodecSpec.scala diff --git a/zio-schema-protobuf/shared/src/test/scala-2/zio/schema/codec/ProtobufCodecSpec.scala b/zio-schema-protobuf/shared/src/test/scala-2/zio/schema/codec/ProtobufCodecSpec.scala index b15dc82ad..b3130742a 100644 --- a/zio-schema-protobuf/shared/src/test/scala-2/zio/schema/codec/ProtobufCodecSpec.scala +++ b/zio-schema-protobuf/shared/src/test/scala-2/zio/schema/codec/ProtobufCodecSpec.scala @@ -692,6 +692,7 @@ object ProtobufCodecSpec extends ZIOSpecDefault { d <- decode(schemaFail, "0F").exit d2 <- decodeNS(schemaFail, "0F").exit } yield assert(d)(failsWithA[DecodeError]) && assert(d2)(failsWithA[DecodeError]) + } ), suite("dynamic")( @@ -1010,12 +1011,27 @@ object ProtobufCodecSpec extends ZIOSpecDefault { lazy val schemaChunkOfBytes: Schema[ChunkOfBytes] = DeriveSchema.gen[ChunkOfBytes] + // "%02X".format doesn't work the same in ScalaJS def toHex(chunk: Chunk[Byte]): String = - chunk.toArray.map("%02X".format(_)).mkString + chunk.toArray.map { byte => + val intToHex: (Int => Char) = { int => + ('A' - 0xA + int + (((int - 10) >> 31) & ('0' - 55))).toChar + } + val left = (byte >> 4) & 0xF + val right = byte & 0xF + s"${intToHex(left)}${intToHex(right)}" + }.mkString + + private def split(str: String): List[String] = + if (str.isEmpty) { + List.empty + } else { + str.take(2) :: split(str.drop(2)) + } def fromHex(hex: String): Chunk[Byte] = - Try(hex.split("(?<=\\G.{2})").map(Integer.parseInt(_, 16).toByte)) - .map(Chunk.fromArray) + Try(split(hex).map(Integer.parseInt(_, 16).toByte)) + .map(Chunk.fromIterable) .getOrElse(Chunk.empty) def encode[A](schema: Schema[A], input: A): ZIO[Any, Nothing, Chunk[Byte]] = @@ -1040,7 +1056,7 @@ object ProtobufCodecSpec extends ZIOSpecDefault { ZStream .fromChunk(fromHex(hex)) ) - .run(ZSink.collectAll) + .runCollect //NS == non streaming variant of decode def decodeNS[A](schema: Schema[A], hex: String): ZIO[Any, DecodeError, A] = diff --git a/zio-schema-thrift/shared/src/main/scala/zio/schema/codec/ChunkTransport.scala b/zio-schema-thrift/src/main/scala/zio/schema/codec/ChunkTransport.scala similarity index 100% rename from zio-schema-thrift/shared/src/main/scala/zio/schema/codec/ChunkTransport.scala rename to zio-schema-thrift/src/main/scala/zio/schema/codec/ChunkTransport.scala diff --git a/zio-schema-thrift/shared/src/main/scala/zio/schema/codec/ThriftCodec.scala b/zio-schema-thrift/src/main/scala/zio/schema/codec/ThriftCodec.scala similarity index 100% rename from zio-schema-thrift/shared/src/main/scala/zio/schema/codec/ThriftCodec.scala rename to zio-schema-thrift/src/main/scala/zio/schema/codec/ThriftCodec.scala diff --git a/zio-schema-thrift/shared/src/test/resources/testing-data.thrift b/zio-schema-thrift/src/test/resources/testing-data.thrift similarity index 100% rename from zio-schema-thrift/shared/src/test/resources/testing-data.thrift rename to zio-schema-thrift/src/test/resources/testing-data.thrift diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/ThriftCodecSpec.scala diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/BasicDouble.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/BasicDouble.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/BasicDouble.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/BasicDouble.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/BasicInt.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/BasicInt.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/BasicInt.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/BasicInt.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/BasicString.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/BasicString.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/BasicString.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/BasicString.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/BoolValue.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/BoolValue.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/BoolValue.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/BoolValue.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/Color.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/Color.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/Color.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/Color.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/Embedded.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/Embedded.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/Embedded.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/Embedded.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/EnumValue.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/EnumValue.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/EnumValue.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/EnumValue.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/Enumeration.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/Enumeration.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/Enumeration.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/Enumeration.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/HighArity.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/HighArity.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/HighArity.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/HighArity.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/IntList.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/IntList.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/IntList.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/IntList.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/IntValue.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/IntValue.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/IntValue.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/IntValue.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/MapValue.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/MapValue.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/MapValue.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/MapValue.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/OneOf.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/OneOf.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/OneOf.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/OneOf.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/Record.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/Record.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/Record.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/Record.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/SetValue.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/SetValue.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/SetValue.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/SetValue.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/StringList.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/StringList.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/StringList.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/StringList.java diff --git a/zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/StringValue.java b/zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/StringValue.java similarity index 100% rename from zio-schema-thrift/shared/src/test/scala-2/zio/schema/codec/generated/StringValue.java rename to zio-schema-thrift/src/test/scala-2/zio/schema/codec/generated/StringValue.java diff --git a/zio-schema/js/src/main/scala/zio/schema/SchemaPlatformSpecific.scala b/zio-schema/js/src/main/scala/zio/schema/SchemaPlatformSpecific.scala new file mode 100644 index 000000000..afc49c148 --- /dev/null +++ b/zio-schema/js/src/main/scala/zio/schema/SchemaPlatformSpecific.scala @@ -0,0 +1,3 @@ +package zio.schema + +trait SchemaPlatformSpecific {} diff --git a/zio-schema/js/src/main/scala/zio/schema/StandardType.scala b/zio-schema/js/src/main/scala/zio/schema/StandardType.scala new file mode 100644 index 000000000..e561bef75 --- /dev/null +++ b/zio-schema/js/src/main/scala/zio/schema/StandardType.scala @@ -0,0 +1,293 @@ +package zio.schema + +import java.math.BigInteger +import java.time +import java.time._ + +import zio.Chunk + +sealed trait StandardType[A] extends Ordering[A] { self => + def tag: String + def defaultValue: Either[String, A] + override def toString: String = tag + + /** + * Converts a DynamicValue into a primitive type. + */ + def toTypedPrimitive(value: DynamicValue): Either[String, A] = + value.toTypedValue(Schema.primitive[A](self)) +} + +object StandardType { + + private[schema] object Tags { + final val UNIT = "unit" + final val STRING = "string" + final val BOOL = "boolean" + final val BYTE = "byte" + final val SHORT = "short" + final val INT = "int" + final val LONG = "long" + final val FLOAT = "float" + final val DOUBLE = "double" + final val BINARY = "binary" + final val CHAR = "char" + final val BIG_DECIMAL = "bigDecimal" + final val BIG_INTEGER = "bigInteger" + final val DAY_OF_WEEK = "dayOfWeek" + final val MONTH = "month" + final val MONTH_DAY = "monthDay" + final val PERIOD = "period" + final val YEAR = "year" + final val YEAR_MONTH = "yearMonth" + final val ZONE_ID = "zoneId" + final val ZONE_OFFSET = "zoneOffset" + final val DURATION = "duration" + final val INSTANT = "instant" + final val LOCAL_DATE = "localDate" + final val LOCAL_TIME = "localTime" + final val LOCAL_DATE_TIME = "localDateTime" + final val OFFSET_TIME = "offsetTime" + final val OFFSET_DATE_TIME = "offsetDateTime" + final val ZONED_DATE_TIME = "zonedDateTime" + final val UUID = "uuid" + } + + def fromString(tag: String): Option[StandardType[_]] = + tag match { + case Tags.UNIT => Some(UnitType) + case Tags.STRING => Some(StringType) + case Tags.BOOL => Some(BoolType) + case Tags.BYTE => Some(ByteType) + case Tags.SHORT => Some(ShortType) + case Tags.INT => Some(IntType) + case Tags.LONG => Some(LongType) + case Tags.FLOAT => Some(FloatType) + case Tags.DOUBLE => Some(DoubleType) + case Tags.BINARY => Some(BinaryType) + case Tags.CHAR => Some(CharType) + case Tags.BIG_DECIMAL => Some(BigDecimalType) + case Tags.BIG_INTEGER => Some(BigIntegerType) + case Tags.MONTH => Some(MonthType) + case Tags.MONTH_DAY => Some(MonthDayType) + case Tags.PERIOD => Some(PeriodType) + case Tags.DAY_OF_WEEK => Some(DayOfWeekType) + case Tags.YEAR => Some(YearType) + case Tags.YEAR_MONTH => Some(YearMonthType) + case Tags.ZONE_ID => Some(ZoneIdType) + case Tags.ZONE_OFFSET => Some(ZoneOffsetType) + case Tags.DURATION => Some(DurationType) + case Tags.INSTANT => Some(InstantType) + case Tags.LOCAL_DATE => Some(LocalDateType) + case Tags.LOCAL_TIME => Some(LocalTimeType) + case Tags.LOCAL_DATE_TIME => Some(LocalDateTimeType) + case Tags.OFFSET_TIME => Some(OffsetTimeType) + case Tags.OFFSET_DATE_TIME => Some(OffsetDateTimeType) + case Tags.ZONED_DATE_TIME => Some(ZonedDateTimeType) + case Tags.UUID => Some(UUIDType) + } + + def apply[A](implicit standardType: StandardType[A]): StandardType[A] = standardType + + implicit object UnitType extends StandardType[Unit] { + override def tag: String = Tags.UNIT + override def compare(x: Unit, y: Unit): Int = 0 + override def defaultValue: Either[String, Unit] = Right(()) + } + + implicit object StringType extends StandardType[String] { + override def tag: String = Tags.STRING + override def compare(x: String, y: String): Int = x.compareTo(y) + override def defaultValue: Either[String, String] = Right("") + } + + implicit object BoolType extends StandardType[Boolean] { + override def tag: String = Tags.BOOL + override def compare(x: Boolean, y: Boolean): Int = x.compareTo(y) + override def defaultValue: Either[String, Boolean] = Right(false) + } + + implicit object ByteType extends StandardType[Byte] { + override def tag: String = Tags.BYTE + override def compare(x: Byte, y: Byte): Int = x.compareTo(y) + override def defaultValue: Either[String, Byte] = Right(0.toByte) + } + + implicit object ShortType extends StandardType[Short] { + override def tag: String = Tags.SHORT + override def compare(x: Short, y: Short): Int = x.compareTo(y) + override def defaultValue: Either[String, Short] = Right(0.asInstanceOf[Short]) + } + + implicit object IntType extends StandardType[Int] { + override def tag: String = Tags.INT + override def compare(x: Int, y: Int): Int = x.compareTo(y) + override def defaultValue: Either[String, Int] = Right(0) + } + + implicit object LongType extends StandardType[Long] { + override def tag: String = Tags.LONG + override def compare(x: Long, y: Long): Int = x.compareTo(y) + override def defaultValue: Either[String, Long] = Right(0.asInstanceOf[Long]) + } + + implicit object FloatType extends StandardType[Float] { + override def tag: String = Tags.FLOAT + override def compare(x: Float, y: Float): Int = x.compareTo(y) + override def defaultValue: Either[String, Float] = Right(0.0.asInstanceOf[Float]) + } + + implicit object DoubleType extends StandardType[Double] { + override def tag: String = Tags.DOUBLE + override def compare(x: Double, y: Double): Int = x.compareTo(y) + override def defaultValue: Either[String, Double] = Right(0.0) + } + + implicit object BinaryType extends StandardType[Chunk[Byte]] { + override def tag: String = Tags.BINARY + override def compare(x: Chunk[Byte], y: Chunk[Byte]): Int = x.sum.compare(y.sum) + override def defaultValue: Either[String, Chunk[Byte]] = Right(Chunk.empty) + } + + implicit object CharType extends StandardType[Char] { + override def tag: String = Tags.CHAR + override def compare(x: Char, y: Char): Int = x.compareTo(y) + // The NUL Unicode character is used as the default value for + // `StandardType[Char]` because the empty Char '' does not compile + override def defaultValue: Either[String, Char] = Right('\u0000') + } + + implicit object UUIDType extends StandardType[java.util.UUID] { + override def tag: String = Tags.UUID + override def compare(x: java.util.UUID, y: java.util.UUID): Int = x.compareTo(y) + override def defaultValue: Either[String, java.util.UUID] = Left("UUID generation not available in ScalaJS") + } + + implicit object BigDecimalType extends StandardType[java.math.BigDecimal] { + override def tag: String = Tags.BIG_DECIMAL + override def compare(x: java.math.BigDecimal, y: java.math.BigDecimal): Int = x.compareTo(y) + override def defaultValue: Either[String, java.math.BigDecimal] = Right(java.math.BigDecimal.ZERO) + } + + implicit object BigIntegerType extends StandardType[java.math.BigInteger] { + override def tag: String = Tags.BIG_INTEGER + override def compare(x: BigInteger, y: BigInteger): Int = x.compareTo(y) + override def defaultValue: Either[String, java.math.BigInteger] = Right(java.math.BigInteger.ZERO) + } + + //java.time specific types + implicit object DayOfWeekType extends StandardType[DayOfWeek] { + override def tag: String = Tags.DAY_OF_WEEK + override def compare(x: DayOfWeek, y: DayOfWeek): Int = x.getValue.compareTo(y.getValue) + override def defaultValue: Either[String, DayOfWeek] = + Right(java.time.temporal.WeekFields.of(java.util.Locale.getDefault).getFirstDayOfWeek) + } + + implicit object MonthType extends StandardType[java.time.Month] { + override def tag: String = Tags.MONTH + override def compare(x: Month, y: Month): Int = x.getValue.compareTo(y.getValue) + override def defaultValue: Either[String, java.time.Month] = Right(java.time.Month.JANUARY) + } + + implicit object MonthDayType extends StandardType[java.time.MonthDay] { + override def tag: String = Tags.MONTH_DAY + override def compare(x: MonthDay, y: MonthDay): Int = x.compareTo(y) + override def defaultValue: Either[String, java.time.MonthDay] = + Right(java.time.MonthDay.of(java.time.Month.JANUARY, 1)) + } + + implicit object PeriodType extends StandardType[java.time.Period] { + override def tag: String = Tags.PERIOD + override def compare(x: Period, y: Period): Int = { + val startDate = time.LocalDate.of(0, 1, 1) + startDate.plus(x).compareTo(startDate.plus(y)) + } + override def defaultValue: Either[String, java.time.Period] = Right(java.time.Period.ZERO) + } + + implicit object YearType extends StandardType[java.time.Year] { + override def tag: String = Tags.YEAR + override def compare(x: Year, y: Year): Int = x.getValue.compareTo(y.getValue) + override def defaultValue: Either[String, java.time.Year] = Right(java.time.Year.now) + } + + implicit object YearMonthType extends StandardType[java.time.YearMonth] { + override def tag: String = Tags.YEAR_MONTH + override def compare(x: YearMonth, y: YearMonth): Int = x.compareTo(y) + override def defaultValue: Either[String, java.time.YearMonth] = Right(java.time.YearMonth.now) + } + + implicit object ZoneIdType extends StandardType[java.time.ZoneId] { + override def tag: String = Tags.ZONE_ID + override def compare(x: ZoneId, y: ZoneId): Int = x.getId.compareTo(y.getId) // TODO is there a better comparison + override def defaultValue: Either[String, java.time.ZoneId] = Right(java.time.ZoneId.systemDefault) + } + + implicit object ZoneOffsetType extends StandardType[java.time.ZoneOffset] { + override def tag: String = Tags.ZONE_OFFSET + override def compare(x: ZoneOffset, y: ZoneOffset): Int = x.compareTo(y) + override def defaultValue: Either[String, java.time.ZoneOffset] = Right(java.time.ZoneOffset.UTC) + } + + implicit object DurationType extends StandardType[java.time.Duration] { + override def tag: String = Tags.DURATION + override def compare(x: time.Duration, y: time.Duration): Int = x.compareTo(y) + override def defaultValue: Either[String, java.time.Duration] = Right(java.time.Duration.ZERO) + } + + implicit object InstantType extends StandardType[java.time.Instant] { + override def tag: String = Tags.INSTANT + + override def defaultValue: Either[String, Instant] = Right(java.time.Instant.EPOCH) + + override def compare(x: Instant, y: Instant): Int = x.compareTo(y) + } + + implicit object LocalDateType extends StandardType[java.time.LocalDate] { + override def tag: String = Tags.LOCAL_DATE + + override def defaultValue: Either[String, LocalDate] = Right(java.time.LocalDate.now) + + override def compare(x: LocalDate, y: LocalDate): Int = x.compareTo(y) + } + + implicit object LocalTimeType extends StandardType[java.time.LocalTime] { + override def tag: String = Tags.LOCAL_TIME + + override def defaultValue: Either[String, LocalTime] = Right(java.time.LocalTime.MIDNIGHT) + + override def compare(x: LocalTime, y: LocalTime): Int = x.compareTo(y) + } + + implicit object LocalDateTimeType extends StandardType[java.time.LocalDateTime] { + override def tag: String = Tags.LOCAL_DATE_TIME + + override def defaultValue: Either[String, LocalDateTime] = Right(java.time.LocalDateTime.now) + + override def compare(x: LocalDateTime, y: LocalDateTime): Int = x.compareTo(y) + } + + implicit object OffsetTimeType extends StandardType[java.time.OffsetTime] { + override def tag: String = Tags.OFFSET_TIME + + override def defaultValue: Either[String, OffsetTime] = Right(java.time.OffsetTime.now) + + override def compare(x: OffsetTime, y: OffsetTime): Int = x.compareTo(y) + } + + implicit object OffsetDateTimeType extends StandardType[java.time.OffsetDateTime] { + override def tag: String = Tags.OFFSET_DATE_TIME + + override def defaultValue: Either[String, OffsetDateTime] = Right(java.time.OffsetDateTime.now) + + override def compare(x: OffsetDateTime, y: OffsetDateTime): Int = x.compareTo(y) + } + + implicit object ZonedDateTimeType extends StandardType[java.time.ZonedDateTime] { + override def tag: String = Tags.ZONED_DATE_TIME + + override def defaultValue: Either[String, ZonedDateTime] = Right(java.time.ZonedDateTime.now) + + override def compare(x: ZonedDateTime, y: ZonedDateTime): Int = x.compareTo(y) + } +} diff --git a/zio-schema/jvm/src/main/scala/zio/schema/SchemaPlatformSpecific.scala b/zio-schema/jvm/src/main/scala/zio/schema/SchemaPlatformSpecific.scala new file mode 100644 index 000000000..f256da2da --- /dev/null +++ b/zio-schema/jvm/src/main/scala/zio/schema/SchemaPlatformSpecific.scala @@ -0,0 +1,14 @@ +package zio.schema + +trait SchemaPlatformSpecific { + + implicit val url: Schema[java.net.URL] = + Schema[String].transformOrFail( + string => + try { + Right(new java.net.URL(string)) + } catch { case _: Exception => Left(s"Invalid URL: $string") }, + url => Right(url.toString) + ) + +} diff --git a/zio-schema/shared/src/main/scala/zio/schema/StandardType.scala b/zio-schema/jvm/src/main/scala/zio/schema/StandardType.scala similarity index 100% rename from zio-schema/shared/src/main/scala/zio/schema/StandardType.scala rename to zio-schema/jvm/src/main/scala/zio/schema/StandardType.scala diff --git a/zio-schema/native/src/main/scala/zio/schema/SchemaPlatformSpecific.scala b/zio-schema/native/src/main/scala/zio/schema/SchemaPlatformSpecific.scala new file mode 100644 index 000000000..afc49c148 --- /dev/null +++ b/zio-schema/native/src/main/scala/zio/schema/SchemaPlatformSpecific.scala @@ -0,0 +1,3 @@ +package zio.schema + +trait SchemaPlatformSpecific {} diff --git a/zio-schema/native/src/main/scala/zio/schema/StandardType.scala b/zio-schema/native/src/main/scala/zio/schema/StandardType.scala new file mode 100644 index 000000000..b65a46ee5 --- /dev/null +++ b/zio-schema/native/src/main/scala/zio/schema/StandardType.scala @@ -0,0 +1,293 @@ +package zio.schema + +import java.math.BigInteger +import java.time +import java.time._ + +import zio.Chunk + +sealed trait StandardType[A] extends Ordering[A] { self => + def tag: String + def defaultValue: Either[String, A] + override def toString: String = tag + + /** + * Converts a DynamicValue into a primitive type. + */ + def toTypedPrimitive(value: DynamicValue): Either[String, A] = + value.toTypedValue(Schema.primitive[A](self)) +} + +object StandardType { + + private[schema] object Tags { + final val UNIT = "unit" + final val STRING = "string" + final val BOOL = "boolean" + final val BYTE = "byte" + final val SHORT = "short" + final val INT = "int" + final val LONG = "long" + final val FLOAT = "float" + final val DOUBLE = "double" + final val BINARY = "binary" + final val CHAR = "char" + final val BIG_DECIMAL = "bigDecimal" + final val BIG_INTEGER = "bigInteger" + final val DAY_OF_WEEK = "dayOfWeek" + final val MONTH = "month" + final val MONTH_DAY = "monthDay" + final val PERIOD = "period" + final val YEAR = "year" + final val YEAR_MONTH = "yearMonth" + final val ZONE_ID = "zoneId" + final val ZONE_OFFSET = "zoneOffset" + final val DURATION = "duration" + final val INSTANT = "instant" + final val LOCAL_DATE = "localDate" + final val LOCAL_TIME = "localTime" + final val LOCAL_DATE_TIME = "localDateTime" + final val OFFSET_TIME = "offsetTime" + final val OFFSET_DATE_TIME = "offsetDateTime" + final val ZONED_DATE_TIME = "zonedDateTime" + final val UUID = "uuid" + } + + def fromString(tag: String): Option[StandardType[_]] = + tag match { + case Tags.UNIT => Some(UnitType) + case Tags.STRING => Some(StringType) + case Tags.BOOL => Some(BoolType) + case Tags.BYTE => Some(ByteType) + case Tags.SHORT => Some(ShortType) + case Tags.INT => Some(IntType) + case Tags.LONG => Some(LongType) + case Tags.FLOAT => Some(FloatType) + case Tags.DOUBLE => Some(DoubleType) + case Tags.BINARY => Some(BinaryType) + case Tags.CHAR => Some(CharType) + case Tags.BIG_DECIMAL => Some(BigDecimalType) + case Tags.BIG_INTEGER => Some(BigIntegerType) + case Tags.MONTH => Some(MonthType) + case Tags.MONTH_DAY => Some(MonthDayType) + case Tags.PERIOD => Some(PeriodType) + case Tags.DAY_OF_WEEK => Some(DayOfWeekType) + case Tags.YEAR => Some(YearType) + case Tags.YEAR_MONTH => Some(YearMonthType) + case Tags.ZONE_ID => Some(ZoneIdType) + case Tags.ZONE_OFFSET => Some(ZoneOffsetType) + case Tags.DURATION => Some(DurationType) + case Tags.INSTANT => Some(InstantType) + case Tags.LOCAL_DATE => Some(LocalDateType) + case Tags.LOCAL_TIME => Some(LocalTimeType) + case Tags.LOCAL_DATE_TIME => Some(LocalDateTimeType) + case Tags.OFFSET_TIME => Some(OffsetTimeType) + case Tags.OFFSET_DATE_TIME => Some(OffsetDateTimeType) + case Tags.ZONED_DATE_TIME => Some(ZonedDateTimeType) + case Tags.UUID => Some(UUIDType) + } + + def apply[A](implicit standardType: StandardType[A]): StandardType[A] = standardType + + implicit object UnitType extends StandardType[Unit] { + override def tag: String = Tags.UNIT + override def compare(x: Unit, y: Unit): Int = 0 + override def defaultValue: Either[String, Unit] = Right(()) + } + + implicit object StringType extends StandardType[String] { + override def tag: String = Tags.STRING + override def compare(x: String, y: String): Int = x.compareTo(y) + override def defaultValue: Either[String, String] = Right("") + } + + implicit object BoolType extends StandardType[Boolean] { + override def tag: String = Tags.BOOL + override def compare(x: Boolean, y: Boolean): Int = x.compareTo(y) + override def defaultValue: Either[String, Boolean] = Right(false) + } + + implicit object ByteType extends StandardType[Byte] { + override def tag: String = Tags.BYTE + override def compare(x: Byte, y: Byte): Int = x.compareTo(y) + override def defaultValue: Either[String, Byte] = Right(0.toByte) + } + + implicit object ShortType extends StandardType[Short] { + override def tag: String = Tags.SHORT + override def compare(x: Short, y: Short): Int = x.compareTo(y) + override def defaultValue: Either[String, Short] = Right(0.asInstanceOf[Short]) + } + + implicit object IntType extends StandardType[Int] { + override def tag: String = Tags.INT + override def compare(x: Int, y: Int): Int = x.compareTo(y) + override def defaultValue: Either[String, Int] = Right(0) + } + + implicit object LongType extends StandardType[Long] { + override def tag: String = Tags.LONG + override def compare(x: Long, y: Long): Int = x.compareTo(y) + override def defaultValue: Either[String, Long] = Right(0.asInstanceOf[Long]) + } + + implicit object FloatType extends StandardType[Float] { + override def tag: String = Tags.FLOAT + override def compare(x: Float, y: Float): Int = x.compareTo(y) + override def defaultValue: Either[String, Float] = Right(0.0.asInstanceOf[Float]) + } + + implicit object DoubleType extends StandardType[Double] { + override def tag: String = Tags.DOUBLE + override def compare(x: Double, y: Double): Int = x.compareTo(y) + override def defaultValue: Either[String, Double] = Right(0.0) + } + + implicit object BinaryType extends StandardType[Chunk[Byte]] { + override def tag: String = Tags.BINARY + override def compare(x: Chunk[Byte], y: Chunk[Byte]): Int = x.sum.compare(y.sum) + override def defaultValue: Either[String, Chunk[Byte]] = Right(Chunk.empty) + } + + implicit object CharType extends StandardType[Char] { + override def tag: String = Tags.CHAR + override def compare(x: Char, y: Char): Int = x.compareTo(y) + // The NUL Unicode character is used as the default value for + // `StandardType[Char]` because the empty Char '' does not compile + override def defaultValue: Either[String, Char] = Right('\u0000') + } + + implicit object UUIDType extends StandardType[java.util.UUID] { + override def tag: String = Tags.UUID + override def compare(x: java.util.UUID, y: java.util.UUID): Int = x.compareTo(y) + override def defaultValue: Either[String, java.util.UUID] = Right(java.util.UUID.randomUUID()) + } + + implicit object BigDecimalType extends StandardType[java.math.BigDecimal] { + override def tag: String = Tags.BIG_DECIMAL + override def compare(x: java.math.BigDecimal, y: java.math.BigDecimal): Int = x.compareTo(y) + override def defaultValue: Either[String, java.math.BigDecimal] = Right(java.math.BigDecimal.ZERO) + } + + implicit object BigIntegerType extends StandardType[java.math.BigInteger] { + override def tag: String = Tags.BIG_INTEGER + override def compare(x: BigInteger, y: BigInteger): Int = x.compareTo(y) + override def defaultValue: Either[String, java.math.BigInteger] = Right(java.math.BigInteger.ZERO) + } + + //java.time specific types + implicit object DayOfWeekType extends StandardType[DayOfWeek] { + override def tag: String = Tags.DAY_OF_WEEK + override def compare(x: DayOfWeek, y: DayOfWeek): Int = x.getValue.compareTo(y.getValue) + override def defaultValue: Either[String, DayOfWeek] = + Right(java.time.temporal.WeekFields.of(java.util.Locale.getDefault).getFirstDayOfWeek) + } + + implicit object MonthType extends StandardType[java.time.Month] { + override def tag: String = Tags.MONTH + override def compare(x: Month, y: Month): Int = x.getValue.compareTo(y.getValue) + override def defaultValue: Either[String, java.time.Month] = Right(java.time.Month.JANUARY) + } + + implicit object MonthDayType extends StandardType[java.time.MonthDay] { + override def tag: String = Tags.MONTH_DAY + override def compare(x: MonthDay, y: MonthDay): Int = x.compareTo(y) + override def defaultValue: Either[String, java.time.MonthDay] = + Right(java.time.MonthDay.of(java.time.Month.JANUARY, 1)) + } + + implicit object PeriodType extends StandardType[java.time.Period] { + override def tag: String = Tags.PERIOD + override def compare(x: Period, y: Period): Int = { + val startDate = time.LocalDate.of(0, 1, 1) + startDate.plus(x).compareTo(startDate.plus(y)) + } + override def defaultValue: Either[String, java.time.Period] = Right(java.time.Period.ZERO) + } + + implicit object YearType extends StandardType[java.time.Year] { + override def tag: String = Tags.YEAR + override def compare(x: Year, y: Year): Int = x.getValue.compareTo(y.getValue) + override def defaultValue: Either[String, java.time.Year] = Right(java.time.Year.now) + } + + implicit object YearMonthType extends StandardType[java.time.YearMonth] { + override def tag: String = Tags.YEAR_MONTH + override def compare(x: YearMonth, y: YearMonth): Int = x.compareTo(y) + override def defaultValue: Either[String, java.time.YearMonth] = Right(java.time.YearMonth.now) + } + + implicit object ZoneIdType extends StandardType[java.time.ZoneId] { + override def tag: String = Tags.ZONE_ID + override def compare(x: ZoneId, y: ZoneId): Int = x.getId.compareTo(y.getId) // TODO is there a better comparison + override def defaultValue: Either[String, java.time.ZoneId] = Right(java.time.ZoneId.systemDefault) + } + + implicit object ZoneOffsetType extends StandardType[java.time.ZoneOffset] { + override def tag: String = Tags.ZONE_OFFSET + override def compare(x: ZoneOffset, y: ZoneOffset): Int = x.compareTo(y) + override def defaultValue: Either[String, java.time.ZoneOffset] = Right(java.time.ZoneOffset.UTC) + } + + implicit object DurationType extends StandardType[java.time.Duration] { + override def tag: String = Tags.DURATION + override def compare(x: time.Duration, y: time.Duration): Int = x.compareTo(y) + override def defaultValue: Either[String, java.time.Duration] = Right(java.time.Duration.ZERO) + } + + implicit object InstantType extends StandardType[java.time.Instant] { + override def tag: String = Tags.INSTANT + + override def defaultValue: Either[String, Instant] = Right(java.time.Instant.EPOCH) + + override def compare(x: Instant, y: Instant): Int = x.compareTo(y) + } + + implicit object LocalDateType extends StandardType[java.time.LocalDate] { + override def tag: String = Tags.LOCAL_DATE + + override def defaultValue: Either[String, LocalDate] = Right(java.time.LocalDate.now) + + override def compare(x: LocalDate, y: LocalDate): Int = x.compareTo(y) + } + + implicit object LocalTimeType extends StandardType[java.time.LocalTime] { + override def tag: String = Tags.LOCAL_TIME + + override def defaultValue: Either[String, LocalTime] = Right(java.time.LocalTime.MIDNIGHT) + + override def compare(x: LocalTime, y: LocalTime): Int = x.compareTo(y) + } + + implicit object LocalDateTimeType extends StandardType[java.time.LocalDateTime] { + override def tag: String = Tags.LOCAL_DATE_TIME + + override def defaultValue: Either[String, LocalDateTime] = Right(java.time.LocalDateTime.now) + + override def compare(x: LocalDateTime, y: LocalDateTime): Int = x.compareTo(y) + } + + implicit object OffsetTimeType extends StandardType[java.time.OffsetTime] { + override def tag: String = Tags.OFFSET_TIME + + override def defaultValue: Either[String, OffsetTime] = Right(java.time.OffsetTime.now) + + override def compare(x: OffsetTime, y: OffsetTime): Int = x.compareTo(y) + } + + implicit object OffsetDateTimeType extends StandardType[java.time.OffsetDateTime] { + override def tag: String = Tags.OFFSET_DATE_TIME + + override def defaultValue: Either[String, OffsetDateTime] = Right(java.time.OffsetDateTime.now) + + override def compare(x: OffsetDateTime, y: OffsetDateTime): Int = x.compareTo(y) + } + + implicit object ZonedDateTimeType extends StandardType[java.time.ZonedDateTime] { + override def tag: String = Tags.ZONED_DATE_TIME + + override def defaultValue: Either[String, ZonedDateTime] = Right(java.time.ZonedDateTime.now) + + override def compare(x: ZonedDateTime, y: ZonedDateTime): Int = x.compareTo(y) + } +} diff --git a/zio-schema/shared/src/main/scala/zio/schema/Differ.scala b/zio-schema/shared/src/main/scala/zio/schema/Differ.scala index 4f4dee67f..437a567d4 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/Differ.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/Differ.scala @@ -189,7 +189,7 @@ object Differ { } val string: Differ[String] = apply[Int].transform( - (s: String) => Chunk.fromArray(s.chars().toArray), + (s: String) => Chunk.fromIterable(s.toList.map(_.toInt)), (as: Chunk[Int]) => new String(as.map(_.toChar).toArray) ) diff --git a/zio-schema/shared/src/main/scala/zio/schema/DynamicValue.scala b/zio-schema/shared/src/main/scala/zio/schema/DynamicValue.scala index eae9bb983..a16993281 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/DynamicValue.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/DynamicValue.scala @@ -528,6 +528,12 @@ object DynamicValue { (d: DynamicValue) => d.isInstanceOf[DynamicValue.Singleton[_]] ) + private def hasStandardType(value: DynamicValue, standardType: StandardType[_]): Boolean = + value match { + case DynamicValue.Primitive(_, tpe) => tpe == standardType + case _ => false + } + private val primitiveUnitCase: Schema.Case[DynamicValue, DynamicValue.Primitive[Unit]] = Schema.Case( "Unit", @@ -587,10 +593,8 @@ object DynamicValue { case dv @ DynamicValue.Primitive(_: Int, _) => dv.asInstanceOf[DynamicValue.Primitive[Int]] case _ => throw new IllegalArgumentException }, - (dv: DynamicValue.Primitive[Int]) => dv.asInstanceOf[DynamicValue], { - case DynamicValue.Primitive(_: Int, _) => true - case _ => false - } + (dv: DynamicValue.Primitive[Int]) => dv.asInstanceOf[DynamicValue], + hasStandardType(_, StandardType.IntType) ) private val primitiveLongCase: Schema.Case[DynamicValue, DynamicValue.Primitive[Long]] = @@ -600,10 +604,8 @@ object DynamicValue { case dv @ DynamicValue.Primitive(_: Long, _) => dv.asInstanceOf[DynamicValue.Primitive[Long]] case _ => throw new IllegalArgumentException }, - (dv: DynamicValue.Primitive[Long]) => dv.asInstanceOf[DynamicValue], { - case DynamicValue.Primitive(_: Long, _) => true - case _ => false - } + (dv: DynamicValue.Primitive[Long]) => dv.asInstanceOf[DynamicValue], + hasStandardType(_, StandardType.LongType) ) private val primitiveFloatCase: Schema.Case[DynamicValue, DynamicValue.Primitive[Float]] = @@ -613,10 +615,8 @@ object DynamicValue { case dv @ DynamicValue.Primitive(_: Float, _) => dv.asInstanceOf[DynamicValue.Primitive[Float]] case _ => throw new IllegalArgumentException }, - (dv: DynamicValue.Primitive[Float]) => dv.asInstanceOf[DynamicValue], { - case DynamicValue.Primitive(_: Float, _) => true - case _ => false - } + (dv: DynamicValue.Primitive[Float]) => dv.asInstanceOf[DynamicValue], + hasStandardType(_, StandardType.FloatType) ) private val primitiveDoubleCase: Schema.Case[DynamicValue, DynamicValue.Primitive[Double]] = @@ -626,10 +626,8 @@ object DynamicValue { case dv @ DynamicValue.Primitive(_: Double, _) => dv.asInstanceOf[DynamicValue.Primitive[Double]] case _ => throw new IllegalArgumentException }, - (dv: DynamicValue.Primitive[Double]) => dv.asInstanceOf[DynamicValue], { - case DynamicValue.Primitive(_: Double, _) => true - case _ => false - } + (dv: DynamicValue.Primitive[Double]) => dv.asInstanceOf[DynamicValue], + hasStandardType(_, StandardType.DoubleType) ) private val primitiveBinaryCase: Schema.Case[DynamicValue, DynamicValue.Primitive[Chunk[Byte]]] = diff --git a/zio-schema/shared/src/main/scala/zio/schema/Schema.scala b/zio-schema/shared/src/main/scala/zio/schema/Schema.scala index 7fe459798..3bdab6378 100644 --- a/zio-schema/shared/src/main/scala/zio/schema/Schema.scala +++ b/zio-schema/shared/src/main/scala/zio/schema/Schema.scala @@ -157,7 +157,7 @@ sealed trait Schema[A] { def zip[B](that: Schema[B]): Schema[(A, B)] = Schema.Tuple2(self, that) } -object Schema extends SchemaEquality { +object Schema extends SchemaPlatformSpecific with SchemaEquality { def apply[A](implicit schema: Schema[A]): Schema[A] = schema def defer[A](schema: => Schema[A]): Schema[A] = Lazy(() => schema) @@ -319,15 +319,6 @@ object Schema extends SchemaEquality { implicit def vector[A](implicit element: Schema[A]): Schema[Vector[A]] = Schema.Sequence[Vector[A], A, String](element, _.toVector, Chunk.fromIterable(_), Chunk.empty, "Vector") - implicit val url: Schema[java.net.URL] = - Schema[String].transformOrFail( - string => - try { - Right(new URI(string).toURL) - } catch { case _: Exception => Left(s"Invalid URL: $string") }, - url => Right(url.toString) - ) - implicit def schemaSchema[A]: Schema[Schema[A]] = Schema[MetaSchema].transform( _.toSchema.asInstanceOf[Schema[A]], _.ast diff --git a/zio-schema/shared/src/test/scala/zio/schema/validation/ValidationSpec.scala b/zio-schema/shared/src/test/scala/zio/schema/validation/ValidationSpec.scala index 371c3b3b4..7cc65fdd3 100644 --- a/zio-schema/shared/src/test/scala/zio/schema/validation/ValidationSpec.scala +++ b/zio-schema/shared/src/test/scala/zio/schema/validation/ValidationSpec.scala @@ -288,12 +288,12 @@ object ValidationSpec extends ZIOSpecDefault { val parsedTimes = parseTimes(CreateTimesConfig(NoHour, "", HasMinute, "", NoSecond, "", NoFraction, "", NoAmPm), "mm") assertParsedTimes(parsedTimes) - }, + } @@ TestAspect.jvmOnly, test("Time Validation m") { val parsedTimes = parseTimes(CreateTimesConfig(NoHour, "", HasMinute, "", NoSecond, "", NoFraction, "", NoAmPm), "m") assertParsedTimes(parsedTimes) - }, + } @@ TestAspect.jvmOnly, test("Time Validation HHmm") { val parsedTimes = parseTimes(CreateTimesConfig(HasHour, "", HasMinute, "", NoSecond, "", NoFraction, "", NoAmPm), "HHmm") @@ -315,7 +315,7 @@ object ValidationSpec extends ZIOSpecDefault { "HH:mm:ss a" ) assertParsedTimes(parsedTimes) - }, + } @@ TestAspect.jvmOnly, test("Time Validation H:m:s") { val parsedTimes = parseTimes(CreateTimesConfig(HasHour, ":", HasMinute, ":", HasSecond, "", NoFraction, "", NoAmPm), "H:m:s") @@ -325,7 +325,7 @@ object ValidationSpec extends ZIOSpecDefault { val parsedTimes = parseTimes(CreateTimesConfig(HasHour, ":", HasMinute, ":", HasSecond, "", NoFraction, " ", HasAmPm), "H:m:s a") assertParsedTimes(parsedTimes) - }, + } @@ TestAspect.jvmOnly, test("Time Validation hh:mm:ss") { val parsedTimes = parseTimes(CreateTimesConfig(HasHour, ":", HasMinute, ":", HasSecond, "", NoFraction, "", NoAmPm), "hh:mm:ss") @@ -337,7 +337,7 @@ object ValidationSpec extends ZIOSpecDefault { "hh:mm:ss a" ) assertParsedTimes(parsedTimes) - }, + } @@ TestAspect.jvmOnly, test("Time Validation h:m:s") { val parsedTimes = parseTimes(CreateTimesConfig(HasHour, ":", HasMinute, ":", HasSecond, "", NoFraction, "", NoAmPm), "h:m:s") @@ -347,7 +347,7 @@ object ValidationSpec extends ZIOSpecDefault { val parsedTimes = parseTimes(CreateTimesConfig(HasHour, ":", HasMinute, ":", HasSecond, "", NoFraction, " ", HasAmPm), "h:m:s a") assertParsedTimes(parsedTimes) - }, + } @@ TestAspect.jvmOnly, test("Time Validation HH:mm:ss S") { val parsedTimes = parseTimes( CreateTimesConfig(HasHour, ":", HasMinute, ":", HasSecond, " ", HasFraction, "", NoAmPm), @@ -368,7 +368,7 @@ object ValidationSpec extends ZIOSpecDefault { "HH:mm:ss SSSSSSSSS a" ) assertParsedTimes(parsedTimes) - }, + } @@ TestAspect.jvmOnly, test("Regex duration Validation") { check(Gen.finiteDuration) { duration => assertTrue(Validation.duration.validate(duration.toString).isRight)