diff --git a/core/src/main/scala/zio/schema/Schema.scala b/core/src/main/scala/zio/schema/Schema.scala index c0b19de22..513af9951 100644 --- a/core/src/main/scala/zio/schema/Schema.scala +++ b/core/src/main/scala/zio/schema/Schema.scala @@ -746,59 +746,6 @@ object Schema { implicit def rightSchema[A, B](implicit schemaB: Schema[B]): Schema[Right[Nothing, B]] = schemaB.transform(Right(_), _.value) - def caseClassN[A, Z](t1: (String, Schema[A]))(f: A => Z, g: Z => Option[A]): Schema[Z] = - Schema - .record(Map(t1)) - .transformOrFail( - { map => - val v1 = map(t1._1).asInstanceOf[A] - - Right(f(v1)) - }, { (z: Z) => - g(z).map { a => - Map(t1._1 -> a) - }.toRight("Cannot deconstruct case class") - } - ) - - def caseClassN[A, B, Z]( - t1: (String, Schema[A]), - t2: (String, Schema[B]) - )(f: (A, B) => Z, g: Z => Option[(A, B)]): Schema[Z] = - Schema - .record(Map[String, Schema[_]](t1, t2)) - .transformOrFail( - { map => - val v1 = map(t1._1).asInstanceOf[A] - val v2 = map(t2._1).asInstanceOf[B] - - Right(f(v1, v2)) - }, { (z: Z) => - g(z).map { case (a, b) => Map(t1._1 -> a, t2._1 -> b) } - .toRight("Cannot deconstruct case class") - } - ) - - def caseClassN[A, B, C, Z]( - t1: (String, Schema[A]), - t2: (String, Schema[B]), - t3: (String, Schema[C]) - )(f: (A, B, C) => Z, g: Z => Option[(A, B, C)]): Schema[Z] = - Schema - .record(Map[String, Schema[_]](t1, t2, t3)) - .transformOrFail( - { map => - val v1 = map(t1._1).asInstanceOf[A] - val v2 = map(t2._1).asInstanceOf[B] - val v3 = map(t3._1).asInstanceOf[C] - - Right(f(v1, v2, v3)) - }, { (z: Z) => - g(z).map { case (a, b, c) => Map(t1._1 -> a, t2._1 -> b, t3._1 -> c) } - .toRight("Cannot deconstruct case class") - } - ) - def either[A, B](left: Schema[A], right: Schema[B]): Schema[Either[A, B]] = EitherSchema(left, right) diff --git a/core/src/main/scala/zio/schema/codec/ProtobufCodec.scala b/core/src/main/scala/zio/schema/codec/ProtobufCodec.scala index 32d92ea30..61b89eafa 100644 --- a/core/src/main/scala/zio/schema/codec/ProtobufCodec.scala +++ b/core/src/main/scala/zio/schema/codec/ProtobufCodec.scala @@ -4,6 +4,8 @@ import java.nio.charset.StandardCharsets import java.nio.{ ByteBuffer, ByteOrder } import java.time._ +import scala.annotation.tailrec + import zio.schema._ import zio.schema.codec.ProtobufCodec.Protobuf.WireType.LengthDelimited import zio.stream.ZTransducer @@ -154,9 +156,854 @@ object ProtobufCodec extends Codec { case (Schema.Tuple(left, right), v @ (_, _)) => encodeTuple(fieldNumber, left, right, v) case (Schema.Optional(codec), v: Option[_]) => encodeOptional(fieldNumber, codec, v) case (Schema.EitherSchema(left, right), v: Either[_, _]) => encodeEither(fieldNumber, left, right, v) - case (_, _) => Chunk.empty + case (Schema.CaseClass1(f, _, ext), v) => encodeCaseClass(fieldNumber, v, f -> ext) + case (Schema.CaseClass2(f1, f2, _, ext1, ext2), v) => encodeCaseClass(fieldNumber, v, f1 -> ext1, f2 -> ext2) + case (Schema.CaseClass3(f1, f2, f3, _, ext1, ext2, ext3), v) => + encodeCaseClass(fieldNumber, v, f1 -> ext1, f2 -> ext2, f3 -> ext3) + case (Schema.CaseClass4(f1, f2, f3, f4, _, ext1, ext2, ext3, ext4), v) => + encodeCaseClass(fieldNumber, v, f1 -> ext1, f2 -> ext2, f3 -> ext3, f4 -> ext4) + case (Schema.CaseClass5(f1, f2, f3, f4, f5, _, ext1, ext2, ext3, ext4, ext5), v) => + encodeCaseClass(fieldNumber, v, f1 -> ext1, f2 -> ext2, f3 -> ext3, f4 -> ext4, f5 -> ext5) + case (Schema.CaseClass6(f1, f2, f3, f4, f5, f6, _, ext1, ext2, ext3, ext4, ext5, ext6), v) => + encodeCaseClass(fieldNumber, v, f1 -> ext1, f2 -> ext2, f3 -> ext3, f4 -> ext4, f5 -> ext5, f6 -> ext6) + case (Schema.CaseClass7(f1, f2, f3, f4, f5, f6, f7, _, ext1, ext2, ext3, ext4, ext5, ext6, ext7), v) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7 + ) + case ( + Schema.CaseClass8(f1, f2, f3, f4, f5, f6, f7, f8, _, ext1, ext2, ext3, ext4, ext5, ext6, ext7, ext8), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8 + ) + case ( + Schema.CaseClass9( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9 + ) + case ( + Schema.CaseClass10( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10 + ) + case ( + Schema.CaseClass11( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11 + ) + case ( + Schema.CaseClass12( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12 + ) + case ( + Schema.CaseClass13( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12, + ext13 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12, + f13 -> ext13 + ) + case ( + Schema.CaseClass14( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12, + ext13, + ext14 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12, + f13 -> ext13, + f14 -> ext14 + ) + case ( + Schema.CaseClass15( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12, + ext13, + ext14, + ext15 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12, + f13 -> ext13, + f14 -> ext14, + f15 -> ext15 + ) + case ( + Schema.CaseClass16( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12, + ext13, + ext14, + ext15, + ext16 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12, + f13 -> ext13, + f14 -> ext14, + f15 -> ext15, + f16 -> ext16 + ) + case ( + Schema.CaseClass17( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12, + ext13, + ext14, + ext15, + ext16, + ext17 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12, + f13 -> ext13, + f14 -> ext14, + f15 -> ext15, + f16 -> ext16, + f17 -> ext17 + ) + case ( + Schema.CaseClass18( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12, + ext13, + ext14, + ext15, + ext16, + ext17, + ext18 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12, + f13 -> ext13, + f14 -> ext14, + f15 -> ext15, + f16 -> ext16, + f17 -> ext17, + f18 -> ext18 + ) + case ( + Schema.CaseClass19( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12, + ext13, + ext14, + ext15, + ext16, + ext17, + ext18, + ext19 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12, + f13 -> ext13, + f14 -> ext14, + f15 -> ext15, + f16 -> ext16, + f17 -> ext17, + f18 -> ext18, + f19 -> ext19 + ) + case ( + Schema.CaseClass20( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12, + ext13, + ext14, + ext15, + ext16, + ext17, + ext18, + ext19, + ext20 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12, + f13 -> ext13, + f14 -> ext14, + f15 -> ext15, + f16 -> ext16, + f17 -> ext17, + f18 -> ext18, + f19 -> ext19, + f20 -> ext20 + ) + case ( + Schema.CaseClass21( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + f21, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12, + ext13, + ext14, + ext15, + ext16, + ext17, + ext18, + ext19, + ext20, + ext21 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12, + f13 -> ext13, + f14 -> ext14, + f15 -> ext15, + f16 -> ext16, + f17 -> ext17, + f18 -> ext18, + f19 -> ext19, + f20 -> ext20, + f21 -> ext21 + ) + case ( + Schema.CaseClass22( + f1, + f2, + f3, + f4, + f5, + f6, + f7, + f8, + f9, + f10, + f11, + f12, + f13, + f14, + f15, + f16, + f17, + f18, + f19, + f20, + f21, + f22, + _, + ext1, + ext2, + ext3, + ext4, + ext5, + ext6, + ext7, + ext8, + ext9, + ext10, + ext11, + ext12, + ext13, + ext14, + ext15, + ext16, + ext17, + ext18, + ext19, + ext20, + ext21, + ext22 + ), + v + ) => + encodeCaseClass( + fieldNumber, + v, + f1 -> ext1, + f2 -> ext2, + f3 -> ext3, + f4 -> ext4, + f5 -> ext5, + f6 -> ext6, + f7 -> ext7, + f8 -> ext8, + f9 -> ext9, + f10 -> ext10, + f11 -> ext11, + f12 -> ext12, + f13 -> ext13, + f14 -> ext14, + f15 -> ext15, + f16 -> ext16, + f17 -> ext17, + f18 -> ext18, + f19 -> ext19, + f20 -> ext20, + f21 -> ext21, + f22 -> ext22 + ) + case (_, _) => Chunk.empty } + private def encodeCaseClass[Z]( + fieldNumber: Option[Int], + value: Z, + fields: ((String, Schema[_]), Z => Any)* + ): Chunk[Byte] = { + val encoded = Chunk + .fromIterable( + fields.zipWithIndex.map { + case (((_, schema), ext), fieldNumber) => + encode(Some(fieldNumber + 1), schema.asInstanceOf[Schema[Any]], ext(value)) + } + ) + .flatten + encodeKey(WireType.LengthDelimited(encoded.size), fieldNumber) ++ encoded + } + private def encodeRecord( fieldNumber: Option[Int], structure: Map[String, Schema[_]], @@ -424,16 +1271,972 @@ object ProtobufCodec extends Codec { case Schema.Record(structure) => recordDecoder(flatFields(structure)) case Schema.Sequence(element) => if (canBePacked(element)) packedSequenceDecoder(element) else nonPackedSequenceDecoder(element) - case Schema.Enumeration(structure) => enumDecoder(flatFields(structure)) - case Schema.Transform(codec, f, _) => transformDecoder(codec, f) - case Schema.Primitive(standardType) => primitiveDecoder(standardType) - case Schema.Tuple(left, right) => tupleDecoder(left, right) - case Schema.Optional(codec) => optionalDecoder(codec) - case Schema.Fail(message) => fail(message) - case Schema.EitherSchema(left, right) => eitherDecoder(left, right) - case Schema.ListSchema(codec) => listDecoder(codec) - case _: Schema.CaseClass[A] => ??? + case Schema.Enumeration(structure) => enumDecoder(flatFields(structure)) + case Schema.Transform(codec, f, _) => transformDecoder(codec, f) + case Schema.Primitive(standardType) => primitiveDecoder(standardType) + case Schema.Tuple(left, right) => tupleDecoder(left, right) + case Schema.Optional(codec) => optionalDecoder(codec) + case Schema.Fail(message) => fail(message) + case Schema.EitherSchema(left, right) => eitherDecoder(left, right) + case Schema.ListSchema(codec) => listDecoder(codec) + case s: Schema.CaseClass1[_, A] => caseClass1Decoder(s) + case s: Schema.CaseClass2[_, _, A] => caseClass2Decoder(s) + case s: Schema.CaseClass3[_, _, _, A] => caseClass3Decoder(s) + case s: Schema.CaseClass4[_, _, _, _, A] => caseClass4Decoder(s) + case s: Schema.CaseClass5[_, _, _, _, _, A] => caseClass5Decoder(s) + case s: Schema.CaseClass6[_, _, _, _, _, _, A] => caseClass6Decoder(s) + case s: Schema.CaseClass7[_, _, _, _, _, _, _, A] => caseClass7Decoder(s) + case s: Schema.CaseClass8[_, _, _, _, _, _, _, _, A] => caseClass8Decoder(s) + case s: Schema.CaseClass9[_, _, _, _, _, _, _, _, _, A] => caseClass9Decoder(s) + case s: Schema.CaseClass10[_, _, _, _, _, _, _, _, _, _, A] => caseClass10Decoder(s) + case s: Schema.CaseClass11[_, _, _, _, _, _, _, _, _, _, _, A] => caseClass11Decoder(s) + case s: Schema.CaseClass12[_, _, _, _, _, _, _, _, _, _, _, _, A] => caseClass12Decoder(s) + case s: Schema.CaseClass13[_, _, _, _, _, _, _, _, _, _, _, _, _, A] => caseClass13Decoder(s) + case s: Schema.CaseClass14[_, _, _, _, _, _, _, _, _, _, _, _, _, _, A] => caseClass14Decoder(s) + case s: Schema.CaseClass15[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, A] => caseClass15Decoder(s) + case s: Schema.CaseClass16[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, A] => caseClass16Decoder(s) + case s: Schema.CaseClass17[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, A] => caseClass17Decoder(s) + case s: Schema.CaseClass18[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, A] => caseClass18Decoder(s) + case s: Schema.CaseClass19[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, A] => caseClass19Decoder(s) + case s: Schema.CaseClass20[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, A] => + caseClass20Decoder(s) + case s: Schema.CaseClass21[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, A] => + caseClass21Decoder(s) + case s: Schema.CaseClass22[_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, A] => + caseClass22Decoder(s) + } + + private def caseClass1Decoder[A, Z](schema: Schema.CaseClass1[A, Z]): Decoder[Z] = + unsafeDecodeFields(Array.ofDim[Any](1), schema.field).flatMap { buffer => + if (buffer(0) == null) + fail("Missing field 1.") + else + succeed(schema.construct(buffer(0).asInstanceOf[A])) + } + + private def caseClass2Decoder[A1, A2, Z](schema: Schema.CaseClass2[A1, A2, Z]): Decoder[Z] = + for { + buffer <- unsafeDecodeFields(Array.ofDim[Any](2), schema.field1, schema.field2) + _ <- validateBuffer(0, buffer) + } yield schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2]) + + private def caseClass3Decoder[A1, A2, A3, Z](schema: Schema.CaseClass3[A1, A2, A3, Z]): Decoder[Z] = + for { + buffer <- unsafeDecodeFields(Array.ofDim[Any](3), schema.field1, schema.field2, schema.field3) + _ <- validateBuffer(0, buffer) + } yield schema.construct(buffer(0).asInstanceOf[A1], buffer(1).asInstanceOf[A2], buffer(2).asInstanceOf[A3]) + + private def caseClass4Decoder[A1, A2, A3, A4, Z](schema: Schema.CaseClass4[A1, A2, A3, A4, Z]): Decoder[Z] = + for { + buffer <- unsafeDecodeFields(Array.ofDim[Any](4), schema.field1, schema.field2, schema.field3, schema.field4) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4] + ) + private def caseClass5Decoder[A1, A2, A3, A4, A5, Z](schema: Schema.CaseClass5[A1, A2, A3, A4, A5, Z]): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](5), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5] + ) + + private def caseClass6Decoder[A1, A2, A3, A4, A5, A6, Z]( + schema: Schema.CaseClass6[A1, A2, A3, A4, A5, A6, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](6), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6] + ) + + private def caseClass7Decoder[A1, A2, A3, A4, A5, A6, A7, Z]( + schema: Schema.CaseClass7[A1, A2, A3, A4, A5, A6, A7, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](7), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7] + ) + + private def caseClass8Decoder[A1, A2, A3, A4, A5, A6, A7, A8, Z]( + schema: Schema.CaseClass8[A1, A2, A3, A4, A5, A6, A7, A8, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](8), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field8 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8] + ) + + private def caseClass9Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, Z]( + schema: Schema.CaseClass9[A1, A2, A3, A4, A5, A6, A7, A8, A9, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](9), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9] + ) + + private def caseClass10Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Z]( + schema: Schema.CaseClass10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](10), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10] + ) + + private def caseClass11Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, Z]( + schema: Schema.CaseClass11[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](11), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11] + ) + + private def caseClass12Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, Z]( + schema: Schema.CaseClass12[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](12), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12] + ) + + private def caseClass13Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, Z]( + schema: Schema.CaseClass13[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](13), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12, + schema.field13 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12], + buffer(12).asInstanceOf[A13] + ) + + private def caseClass14Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, Z]( + schema: Schema.CaseClass14[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](14), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12, + schema.field13, + schema.field14 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12], + buffer(12).asInstanceOf[A13], + buffer(13).asInstanceOf[A14] + ) + + private def caseClass15Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, Z]( + schema: Schema.CaseClass15[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](15), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12, + schema.field13, + schema.field14, + schema.field15 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12], + buffer(12).asInstanceOf[A13], + buffer(13).asInstanceOf[A14], + buffer(14).asInstanceOf[A15] + ) + + private def caseClass16Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, Z]( + schema: Schema.CaseClass16[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](16), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12, + schema.field13, + schema.field14, + schema.field15, + schema.field16 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12], + buffer(12).asInstanceOf[A13], + buffer(13).asInstanceOf[A14], + buffer(14).asInstanceOf[A15], + buffer(15).asInstanceOf[A16] + ) + + private def caseClass17Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, Z]( + schema: Schema.CaseClass17[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](17), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12, + schema.field13, + schema.field14, + schema.field15, + schema.field16, + schema.field17 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12], + buffer(12).asInstanceOf[A13], + buffer(13).asInstanceOf[A14], + buffer(14).asInstanceOf[A15], + buffer(15).asInstanceOf[A16], + buffer(16).asInstanceOf[A17] + ) + + private def caseClass18Decoder[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, Z]( + schema: Schema.CaseClass18[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, Z] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](18), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12, + schema.field13, + schema.field14, + schema.field15, + schema.field16, + schema.field17, + schema.field18 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12], + buffer(12).asInstanceOf[A13], + buffer(13).asInstanceOf[A14], + buffer(14).asInstanceOf[A15], + buffer(15).asInstanceOf[A16], + buffer(16).asInstanceOf[A17], + buffer(17).asInstanceOf[A18] + ) + + private def caseClass19Decoder[ + A1, + A2, + A3, + A4, + A5, + A6, + A7, + A8, + A9, + A10, + A11, + A12, + A13, + A14, + A15, + A16, + A17, + A18, + A19, + Z + ]( + schema: Schema.CaseClass19[ + A1, + A2, + A3, + A4, + A5, + A6, + A7, + A8, + A9, + A10, + A11, + A12, + A13, + A14, + A15, + A16, + A17, + A18, + A19, + Z + ] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](19), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12, + schema.field13, + schema.field14, + schema.field15, + schema.field16, + schema.field17, + schema.field18, + schema.field19 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12], + buffer(12).asInstanceOf[A13], + buffer(13).asInstanceOf[A14], + buffer(14).asInstanceOf[A15], + buffer(15).asInstanceOf[A16], + buffer(16).asInstanceOf[A17], + buffer(17).asInstanceOf[A18], + buffer(18).asInstanceOf[A19] + ) + + private def caseClass20Decoder[ + A1, + A2, + A3, + A4, + A5, + A6, + A7, + A8, + A9, + A10, + A11, + A12, + A13, + A14, + A15, + A16, + A17, + A18, + A19, + A20, + Z + ]( + schema: Schema.CaseClass20[ + A1, + A2, + A3, + A4, + A5, + A6, + A7, + A8, + A9, + A10, + A11, + A12, + A13, + A14, + A15, + A16, + A17, + A18, + A19, + A20, + Z + ] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](20), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12, + schema.field13, + schema.field14, + schema.field15, + schema.field16, + schema.field17, + schema.field18, + schema.field19, + schema.field20 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12], + buffer(12).asInstanceOf[A13], + buffer(13).asInstanceOf[A14], + buffer(14).asInstanceOf[A15], + buffer(15).asInstanceOf[A16], + buffer(16).asInstanceOf[A17], + buffer(17).asInstanceOf[A18], + buffer(18).asInstanceOf[A19], + buffer(19).asInstanceOf[A20] + ) + + private def caseClass21Decoder[ + A1, + A2, + A3, + A4, + A5, + A6, + A7, + A8, + A9, + A10, + A11, + A12, + A13, + A14, + A15, + A16, + A17, + A18, + A19, + A20, + A21, + Z + ]( + schema: Schema.CaseClass21[ + A1, + A2, + A3, + A4, + A5, + A6, + A7, + A8, + A9, + A10, + A11, + A12, + A13, + A14, + A15, + A16, + A17, + A18, + A19, + A20, + A21, + Z + ] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](21), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12, + schema.field13, + schema.field14, + schema.field15, + schema.field16, + schema.field17, + schema.field18, + schema.field19, + schema.field20, + schema.field21 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12], + buffer(12).asInstanceOf[A13], + buffer(13).asInstanceOf[A14], + buffer(14).asInstanceOf[A15], + buffer(15).asInstanceOf[A16], + buffer(16).asInstanceOf[A17], + buffer(17).asInstanceOf[A18], + buffer(18).asInstanceOf[A19], + buffer(19).asInstanceOf[A20], + buffer(20).asInstanceOf[A21] + ) + + private def caseClass22Decoder[ + A1, + A2, + A3, + A4, + A5, + A6, + A7, + A8, + A9, + A10, + A11, + A12, + A13, + A14, + A15, + A16, + A17, + A18, + A19, + A20, + A21, + A22, + Z + ]( + schema: Schema.CaseClass22[ + A1, + A2, + A3, + A4, + A5, + A6, + A7, + A8, + A9, + A10, + A11, + A12, + A13, + A14, + A15, + A16, + A17, + A18, + A19, + A20, + A21, + A22, + Z + ] + ): Decoder[Z] = + for { + buffer <- unsafeDecodeFields( + Array.ofDim[Any](22), + schema.field1, + schema.field2, + schema.field3, + schema.field4, + schema.field5, + schema.field6, + schema.field7, + schema.field9, + schema.field9, + schema.field10, + schema.field11, + schema.field12, + schema.field13, + schema.field14, + schema.field15, + schema.field16, + schema.field17, + schema.field18, + schema.field19, + schema.field20, + schema.field21, + schema.field22 + ) + _ <- validateBuffer(0, buffer) + } yield schema.construct( + buffer(0).asInstanceOf[A1], + buffer(1).asInstanceOf[A2], + buffer(2).asInstanceOf[A3], + buffer(3).asInstanceOf[A4], + buffer(4).asInstanceOf[A5], + buffer(5).asInstanceOf[A6], + buffer(6).asInstanceOf[A7], + buffer(7).asInstanceOf[A8], + buffer(8).asInstanceOf[A9], + buffer(9).asInstanceOf[A10], + buffer(10).asInstanceOf[A11], + buffer(11).asInstanceOf[A12], + buffer(12).asInstanceOf[A13], + buffer(13).asInstanceOf[A14], + buffer(14).asInstanceOf[A15], + buffer(15).asInstanceOf[A16], + buffer(16).asInstanceOf[A17], + buffer(17).asInstanceOf[A18], + buffer(18).asInstanceOf[A19], + buffer(19).asInstanceOf[A20], + buffer(20).asInstanceOf[A21], + buffer(21).asInstanceOf[A22] + ) + + @tailrec + private def validateBuffer(index: Int, buffer: Array[Any]): Decoder[Array[Any]] = + if (index == buffer.length - 1 && buffer(index) != null) + succeed(buffer) + else if (buffer(index) == null) + fail(s"Missing field number $index.") + else + validateBuffer(index + 1, buffer) + + private def unsafeDecodeFields(buffer: Array[Any], fields: (String, Schema[_])*): Decoder[Array[Any]] = + keyDecoder.flatMap { + case (wt, fieldNumber) if fieldNumber == fields.length => + wt match { + case LengthDelimited(width) => + decoder(fields(fieldNumber - 1)._2) + .take(width) + .map(fieldValue => buffer.updated(fieldNumber - 1, fieldValue)) + case _ => + decoder(fields(fieldNumber - 1)._2) + .map(fieldValue => buffer.updated(fieldNumber - 1, fieldValue)) + } + case (wt, fieldNumber) => + if (fieldNumber <= fields.length) { + wt match { + case LengthDelimited(width) => + for { + fieldValue <- decoder(fields(fieldNumber - 1)._2).take(width) + remainder <- unsafeDecodeFields(buffer, fields: _*) + } yield remainder.updated(fieldNumber - 1, fieldValue) + case _ => + for { + fieldValue <- decoder(fields(fieldNumber - 1)._2) + remainder <- unsafeDecodeFields(buffer, fields: _*) + } yield remainder.updated(fieldNumber - 1, fieldValue) + } + } else { + fail(s"Schema doesn't contain field number $fieldNumber.") + } } private def enumDecoder(fields: Map[Int, (String, Schema[_])]): Decoder[Map[String, _]] = diff --git a/core/src/main/scala/zio/schema/macros.scala b/core/src/main/scala/zio/schema/macros.scala index 9e7295da7..04d154c52 100644 --- a/core/src/main/scala/zio/schema/macros.scala +++ b/core/src/main/scala/zio/schema/macros.scala @@ -1215,7 +1215,6 @@ object DeriveSchema { ) } - private def caseClass22[Z](ctx: CaseClass[Typeclass, Z]): Typeclass[Z] = { val param1 = ctx.parameters.head val param2 = ctx.parameters(1) diff --git a/core/src/test/scala/zio/schema/DeriveSchemaSpec.scala b/core/src/test/scala/zio/schema/DeriveSchemaSpec.scala index 9e465b473..08fd7d9a4 100644 --- a/core/src/test/scala/zio/schema/DeriveSchemaSpec.scala +++ b/core/src/test/scala/zio/schema/DeriveSchemaSpec.scala @@ -15,6 +15,11 @@ object DeriveSchemaSpec extends DefaultRunnableSpec { extends Status case object Pending extends Status + sealed trait OneOf + case class StringValue(value: String) extends OneOf + case class IntValue(value: Int) extends OneOf + case class BooleanValue(value: Boolean) extends OneOf + override def spec: ZSpec[Environment, Failure] = suite("DeriveSchemaSpec")( test("DeriveSchema correctly derives schema for UserId case class") { diff --git a/core/src/test/scala/zio/schema/codec/JsonCodecSpec.scala b/core/src/test/scala/zio/schema/codec/JsonCodecSpec.scala index a6e8973cc..35d3709d3 100644 --- a/core/src/test/scala/zio/schema/codec/JsonCodecSpec.scala +++ b/core/src/test/scala/zio/schema/codec/JsonCodecSpec.scala @@ -109,7 +109,7 @@ object JsonCodecSpec extends DefaultRunnableSpec { assertEncodes( adtSchema, Enumeration(StringValue("foo")), - JsonCodec.Encoder.charSequenceToByteChunk("""{"value":{"string":"foo"}}""") + JsonCodec.Encoder.charSequenceToByteChunk("""{"oneOf":{"StringValue":{"value":"foo"}}}""") ) } ) @@ -492,7 +492,6 @@ object JsonCodecSpec extends DefaultRunnableSpec { case class Enumeration(oneOf: OneOf) - val adtSchema: Schema[Enumeration] = - Schema.caseClassN("value" -> schemaOneOf)(Enumeration, Enumeration.unapply) + val adtSchema: Schema[Enumeration] = DeriveSchema.gen[Enumeration] } diff --git a/core/src/test/scala/zio/schema/codec/ProtobufCodecSpec.scala b/core/src/test/scala/zio/schema/codec/ProtobufCodecSpec.scala index f5da1bbd2..e8242f09e 100644 --- a/core/src/test/scala/zio/schema/codec/ProtobufCodecSpec.scala +++ b/core/src/test/scala/zio/schema/codec/ProtobufCodecSpec.scala @@ -6,8 +6,7 @@ import java.time.temporal.ChronoUnit import scala.util.Try -import zio.schema.Schema.Primitive -import zio.schema.{ Schema, StandardType } +import zio.schema.{ DeriveSchema, Schema, StandardType } import zio.stream.{ ZSink, ZStream } import zio.test.Assertion._ import zio.test._ @@ -15,6 +14,7 @@ import zio.{ Chunk, ZIO } // TODO: use generators instead of manual encode/decode object ProtobufCodecSpec extends DefaultRunnableSpec { + import Schema._ def spec = suite("ProtobufCodec Spec")( suite("Should correctly encode")( @@ -64,21 +64,21 @@ object ProtobufCodecSpec extends DefaultRunnableSpec { }, testM("records") { for { - e <- encode(schemaRecord, Record("Foo", 123)).map(toHex) - e2 <- encodeNS(schemaRecord, Record("Foo", 123)).map(toHex) + e <- encode(Record.schemaRecord, Record("Foo", 123)).map(toHex) + e2 <- encodeNS(Record.schemaRecord, Record("Foo", 123)).map(toHex) } yield assert(e)(equalTo("0A03466F6F107B")) && assert(e2)(equalTo("0A03466F6F107B")) }, testM("enumerations") { for { e <- encode(schemaEnumeration, Enumeration(IntValue(482))).map(toHex) e2 <- encodeNS(schemaEnumeration, Enumeration(IntValue(482))).map(toHex) - } yield assert(e)(equalTo("0A0310E203")) && assert(e2)(equalTo("0A0310E203")) + } yield assert(e)(equalTo("0A05120308E203")) && assert(e2)(equalTo("0A05120308E203")) }, testM("enums unwrapped") { for { e <- encode(schemaOneOf, IntValue(482)).map(toHex) e2 <- encodeNS(schemaOneOf, IntValue(482)).map(toHex) - } yield assert(e)(equalTo("10E203")) && assert(e2)(equalTo("10E203")) + } yield assert(e)(equalTo("120308E203")) && assert(e2)(equalTo("120308E203")) }, testM("failure") { for { @@ -90,7 +90,7 @@ object ProtobufCodecSpec extends DefaultRunnableSpec { suite("Should successfully encode and decode")( testM("records") { for { - ed2 <- encodeAndDecodeNS(schemaRecord, Record("hello", 150)) + ed2 <- encodeAndDecodeNS(Record.schemaRecord, Record("hello", 150)) } yield assert(ed2)(equalTo(Record("hello", 150))) }, testM("integer") { @@ -120,7 +120,7 @@ object ProtobufCodecSpec extends DefaultRunnableSpec { }, testM("complex product and string and integer") { for { - ed2 <- encodeAndDecodeNS(schema, message) + ed2 <- encodeAndDecodeNS(SearchRequest.schema, message) } yield assert(ed2)(equalTo(message)) }, testM("booleans") { @@ -320,8 +320,8 @@ object ProtobufCodecSpec extends DefaultRunnableSpec { val oneOf = RichSum.AnotherSum(BooleanValue(false)) val wrapper = RichSum.LongWrapper(150L) for { - ed <- encodeAndDecode(richSumSchema, wrapper) - ed2 <- encodeAndDecodeNS(richSumSchema, oneOf) + ed <- encodeAndDecode(RichSum.richSumSchema, wrapper) + ed2 <- encodeAndDecodeNS(RichSum.richSumSchema, oneOf) } yield assert(ed)(equalTo(Chunk(wrapper))) && assert(ed2)(equalTo(oneOf)) }, testM("tuples") { @@ -391,15 +391,15 @@ object ProtobufCodecSpec extends DefaultRunnableSpec { testM("complex sum type with nested product") { val richSum = RichSum.Person("hello", 10) for { - ed <- encodeAndDecode(richSumSchema, richSum) - ed2 <- encodeAndDecodeNS(richSumSchema, richSum) + ed <- encodeAndDecode(RichSum.richSumSchema, richSum) + ed2 <- encodeAndDecodeNS(RichSum.richSumSchema, richSum) } yield assert(ed)(equalTo(Chunk(richSum))) && assert(ed2)(equalTo(richSum)) }, testM("complex sum type with nested long primitive") { val long = RichSum.LongWrapper(100L) for { - ed <- encodeAndDecode(richSumSchema, long) - ed2 <- encodeAndDecodeNS(richSumSchema, long) + ed <- encodeAndDecode(RichSum.richSumSchema, long) + ed2 <- encodeAndDecodeNS(RichSum.richSumSchema, long) } yield assert(ed)(equalTo(Chunk(long))) && assert(ed2)(equalTo(long)) }, testM("complex either with product type") { @@ -419,15 +419,15 @@ object ProtobufCodecSpec extends DefaultRunnableSpec { testM("complex optionals with product type") { val value = Some(Record("hello earth", 21)) for { - ed <- encodeAndDecode(Schema.Optional(schemaRecord), value) - ed2 <- encodeAndDecodeNS(Schema.Optional(schemaRecord), value) + ed <- encodeAndDecode(Schema.Optional(Record.schemaRecord), value) + ed2 <- encodeAndDecodeNS(Schema.Optional(Record.schemaRecord), value) } yield assert(ed)(equalTo(Chunk(value))) && assert(ed2)(equalTo(value)) }, testM("optional of product type within optional") { val value = Some(Some(Record("hello", 10))) for { - ed <- encodeAndDecode(Schema.Optional(Schema.Optional(schemaRecord)), value) - ed2 <- encodeAndDecodeNS(Schema.Optional(Schema.Optional(schemaRecord)), value) + ed <- encodeAndDecode(Schema.Optional(Schema.Optional(Record.schemaRecord)), value) + ed2 <- encodeAndDecodeNS(Schema.Optional(Schema.Optional(Record.schemaRecord)), value) } yield assert(ed)(equalTo(Chunk(value))) && assert(ed2)(equalTo(value)) }, testM("optional of sum type within optional") { @@ -479,29 +479,29 @@ object ProtobufCodecSpec extends DefaultRunnableSpec { suite("Should fail to decode")( testM("unknown wire types") { for { - d <- decode(schemaRecord, "0F").run - d2 <- decodeNS(schemaRecord, "0F").run + d <- decode(Record.schemaRecord, "0F").run + d2 <- decodeNS(Record.schemaRecord, "0F").run } yield assert(d)(fails(equalTo("Failed decoding key: unknown wire type"))) && assert(d2)(fails(equalTo("Failed decoding key: unknown wire type"))) }, testM("invalid field numbers") { for { - d <- decode(schemaRecord, "00").run - d2 <- decodeNS(schemaRecord, "00").run + d <- decode(Record.schemaRecord, "00").run + d2 <- decodeNS(Record.schemaRecord, "00").run } yield assert(d)(fails(equalTo("Failed decoding key: invalid field number"))) && assert(d2)(fails(equalTo("Failed decoding key: invalid field number"))) }, testM("incomplete length delimited values") { for { - d <- decode(schemaRecord, "0A0346").run - d2 <- decodeNS(schemaRecord, "0A0346").run + d <- decode(Record.schemaRecord, "0A0346").run + d2 <- decodeNS(Record.schemaRecord, "0A0346").run } yield assert(d)(fails(equalTo("Unexpected end of bytes"))) && assert(d2)(fails(equalTo("Unexpected end of bytes"))) }, testM("incomplete var ints") { for { - d <- decode(schemaRecord, "10FF").run - d2 <- decodeNS(schemaRecord, "10FF").run + d <- decode(Record.schemaRecord, "10FF").run + d2 <- decodeNS(Record.schemaRecord, "10FF").run } yield assert(d)(fails(equalTo("Unexpected end of chunk"))) && assert(d2)(fails(equalTo("Unexpected end of chunk"))) }, @@ -515,79 +515,53 @@ object ProtobufCodecSpec extends DefaultRunnableSpec { ) // some tests are based on https://developers.google.com/protocol-buffers/docs/encoding - case class BasicInt(value: Int) case class BasicTwoInts(value1: Int, value2: Int) - val schemaBasicTwoInts: Schema[BasicTwoInts] = Schema.caseClassN( - "value1" -> Schema[Int], - "value2" -> Schema[Int] - )(BasicTwoInts, BasicTwoInts.unapply) + lazy val schemaBasicTwoInts: Schema[BasicTwoInts] = DeriveSchema.gen[BasicTwoInts] - val schemaBasicInt: Schema[BasicInt] = Schema.caseClassN( - "value" -> Schema[Int] - )(BasicInt, BasicInt.unapply) + lazy val schemaBasicInt: Schema[BasicInt] = DeriveSchema.gen[BasicInt] case class BasicTwoIntWrapper(basic: BasicTwoInts) case class BasicIntWrapper(basic: BasicInt) case class SeparateWrapper(basic1: BasicInt, basic2: BasicInt) - val basicIntWrapperSchema: Schema[BasicIntWrapper] = Schema.caseClassN( - "basic" -> schemaBasicInt - )(BasicIntWrapper, BasicIntWrapper.unapply) + lazy val basicIntWrapperSchema: Schema[BasicIntWrapper] = DeriveSchema.gen[BasicIntWrapper] - val basicTwoIntWrapperSchema: Schema[BasicTwoIntWrapper] = Schema.caseClassN( - "basic" -> schemaBasicTwoInts - )(BasicTwoIntWrapper, BasicTwoIntWrapper.unapply) + lazy val basicTwoIntWrapperSchema: Schema[BasicTwoIntWrapper] = DeriveSchema.gen[BasicTwoIntWrapper] case class BasicString(value: String) - val schemaBasicString: Schema[BasicString] = Schema.caseClassN( - "value" -> Schema[String] - )(BasicString, BasicString.unapply) + lazy val schemaBasicString: Schema[BasicString] = DeriveSchema.gen[BasicString] - val separateWrapper: Schema[SeparateWrapper] = Schema.caseClassN( - "basic1" -> schemaBasicInt, - "basic2" -> schemaBasicInt - )(SeparateWrapper, SeparateWrapper.unapply) + lazy val separateWrapper: Schema[SeparateWrapper] = DeriveSchema.gen[SeparateWrapper] case class BasicFloat(value: Float) - val schemaBasicFloat: Schema[BasicFloat] = Schema.caseClassN( - "value" -> Schema[Float] - )(BasicFloat, BasicFloat.unapply) + lazy val schemaBasicFloat: Schema[BasicFloat] = DeriveSchema.gen[BasicFloat] case class BasicDouble(value: Double) - val schemaBasicDouble: Schema[BasicDouble] = Schema.caseClassN( - "value" -> Schema[Double] - )(BasicDouble, BasicDouble.unapply) + lazy val schemaBasicDouble: Schema[BasicDouble] = DeriveSchema.gen[BasicDouble] case class Embedded(embedded: BasicInt) - val schemaEmbedded: Schema[Embedded] = Schema.caseClassN( - "embedded" -> schemaBasicInt - )(Embedded, Embedded.unapply) + lazy val schemaEmbedded: Schema[Embedded] = DeriveSchema.gen[Embedded] case class PackedList(packed: List[Int]) - val schemaPackedList: Schema[PackedList] = Schema.caseClassN( - "packed" -> Schema.list(Schema[Int]) - )(PackedList, PackedList.unapply) + lazy val schemaPackedList: Schema[PackedList] = DeriveSchema.gen[PackedList] case class UnpackedList(items: List[String]) - val schemaUnpackedList: Schema[UnpackedList] = Schema.caseClassN( - "unpacked" -> Schema.list(Schema[String]) - )(UnpackedList, UnpackedList.unapply) + lazy val schemaUnpackedList: Schema[UnpackedList] = DeriveSchema.gen[UnpackedList] case class Record(name: String, value: Int) - val schemaRecord: Schema[Record] = Schema.caseClassN( - "name" -> Schema[String], - "value" -> Schema[Int] - )(Record, Record.unapply) + object Record { + implicit val schemaRecord: Schema[Record] = DeriveSchema.gen[Record] + } val schemaTuple: Schema.Tuple[Int, String] = Schema.Tuple(Schema[Int], Schema[String]) @@ -596,51 +570,25 @@ object ProtobufCodecSpec extends DefaultRunnableSpec { case class IntValue(value: Int) extends OneOf case class BooleanValue(value: Boolean) extends OneOf - val schemaOneOf: Schema[OneOf] = Schema.Transform( - Schema.enumeration( - Map( - "string" -> Schema[String], - "int" -> Schema[Int], - "boolean" -> Schema[Boolean] - ) - ), - (value: Map[String, _]) => { - value - .get("string") - .map(v => Right(StringValue(v.asInstanceOf[String]))) - .orElse(value.get("int").map(v => Right(IntValue(v.asInstanceOf[Int])))) - .orElse(value.get("boolean").map(v => Right(BooleanValue(v.asInstanceOf[Boolean])))) - .getOrElse(Left("No value found")) - }, { - case StringValue(v) => Right(Map("string" -> v)) - case IntValue(v) => Right(Map("int" -> v)) - case BooleanValue(v) => Right(Map("boolean" -> v)) - } - ) + lazy val schemaOneOf: Schema[OneOf] = DeriveSchema.gen[OneOf] case class MyRecord(age: Int) - val myRecord: Schema[MyRecord] = Schema.caseClassN( - "age" -> Schema[Int] - )(MyRecord, MyRecord.unapply) + lazy val myRecord: Schema[MyRecord] = DeriveSchema.gen[MyRecord] - val complexTupleSchema: Schema.Tuple[Record, OneOf] = Schema.Tuple(schemaRecord, schemaOneOf) + val complexTupleSchema: Schema.Tuple[Record, OneOf] = Schema.Tuple(Record.schemaRecord, schemaOneOf) val eitherSchema: Schema.EitherSchema[Int, String] = Schema.EitherSchema(Schema[Int], Schema[String]) val complexEitherSchema: Schema.EitherSchema[Record, OneOf] = - Schema.EitherSchema(schemaRecord, schemaOneOf) + Schema.EitherSchema(Record.schemaRecord, schemaOneOf) val complexEitherSchema2: Schema.EitherSchema[MyRecord, MyRecord] = Schema.EitherSchema(myRecord, myRecord) case class RichProduct(stringOneOf: OneOf, basicString: BasicString, record: Record) - val richProductSchema: Schema[RichProduct] = Schema.caseClassN( - "stringOneOf" -> schemaOneOf, - "basicString" -> schemaBasicString, - "record" -> schemaRecord - )(RichProduct, RichProduct.unapply) + lazy val richProductSchema: Schema[RichProduct] = DeriveSchema.gen[RichProduct] sealed trait RichSum @@ -648,72 +596,34 @@ object ProtobufCodecSpec extends DefaultRunnableSpec { case class Person(name: String, age: Int) extends RichSum case class AnotherSum(oneOf: OneOf) extends RichSum case class LongWrapper(long: Long) extends RichSum - } - val personSchema: Schema[RichSum.Person] = Schema.caseClassN( - ("name" -> Schema[String]), - ("age" -> Schema[Int]) - )(RichSum.Person, RichSum.Person.unapply) - - val richSumSchema: Schema[RichSum] = Schema.Transform( - Schema.enumeration( - Map( - "person" -> personSchema, - "oneOf" -> schemaOneOf, - "long" -> Schema[Long] - ) - ), - (value: Map[String, _]) => { - value - .get("person") - .map(v => Right(v.asInstanceOf[RichSum.Person])) - .orElse(value.get("oneOf").map(v => Right(RichSum.AnotherSum(v.asInstanceOf[OneOf])))) - .orElse(value.get("long").map(v => Right(RichSum.LongWrapper(v.asInstanceOf[Long])))) - .getOrElse(Left("No value found")) - }, { - case p: RichSum.Person => Right(Map("person" -> p)) - case RichSum.AnotherSum(oneOf) => Right(Map("oneOf" -> oneOf)) - case RichSum.LongWrapper(long) => Right(Map("long" -> long)) - } - ) + implicit val richSumSchema: Schema[RichSum] = DeriveSchema.gen[RichSum] + } case class Enumeration(oneOf: OneOf) - val schemaEnumeration: Schema[Enumeration] = - Schema.caseClassN("value" -> schemaOneOf)(Enumeration, Enumeration.unapply) + lazy val schemaEnumeration: Schema[Enumeration] = DeriveSchema.gen[Enumeration] val schemaFail: Schema[StringValue] = Schema.fail("failing schema") case class RequestVars(someString: String, second: Int) - val rvSchema: Schema[RequestVars] = Schema.caseClassN( - "someString" -> Schema[String], - "second" -> Schema[Int] - )(RequestVars, RequestVars.unapply) + lazy val rvSchema: Schema[RequestVars] = DeriveSchema.gen[RequestVars] case class SearchRequest(query: String, pageNumber: RequestVars, resultPerPage: Int) - val schema: Schema[SearchRequest] = Schema.caseClassN( - "query" -> Schema[String], - "pageNumber" -> rvSchema, - "resultPerPage" -> Schema[Int] - )(SearchRequest, SearchRequest.unapply) + object SearchRequest { + implicit val schema: Schema[SearchRequest] = DeriveSchema.gen[SearchRequest] + } val message: SearchRequest = SearchRequest("bitcoins", RequestVars("varValue", 1), 100) case class SequenceOfProduct(name: String, records: List[Record], richSum: RichSum) case class SequenceOfSum(value: String, enums: List[RichSum]) - val sequenceOfProductSchema: Schema[SequenceOfProduct] = Schema.caseClassN( - "name" -> Schema[String], - "records" -> Schema.list(schemaRecord), - "richSum" -> richSumSchema - )(SequenceOfProduct, SequenceOfProduct.unapply) + lazy val sequenceOfProductSchema: Schema[SequenceOfProduct] = DeriveSchema.gen[SequenceOfProduct] - val sequenceOfSumSchema: Schema[SequenceOfSum] = Schema.caseClassN( - "value" -> Schema[String], - "enums" -> Schema.list(richSumSchema) - )(SequenceOfSum, SequenceOfSum.unapply) + lazy val sequenceOfSumSchema: Schema[SequenceOfSum] = DeriveSchema.gen[SequenceOfSum] def toHex(chunk: Chunk[Byte]): String = chunk.toArray.map("%02X".format(_)).mkString