diff --git a/modules/generic/src/main/scala/io/protoless/generic/decoding/AutoDecoderInstances.scala b/modules/generic/src/main/scala/io/protoless/generic/AutoEncoderDecoderInstances.scala similarity index 50% rename from modules/generic/src/main/scala/io/protoless/generic/decoding/AutoDecoderInstances.scala rename to modules/generic/src/main/scala/io/protoless/generic/AutoEncoderDecoderInstances.scala index 74537ba..0c32bd6 100644 --- a/modules/generic/src/main/scala/io/protoless/generic/decoding/AutoDecoderInstances.scala +++ b/modules/generic/src/main/scala/io/protoless/generic/AutoEncoderDecoderInstances.scala @@ -1,12 +1,13 @@ -package io.protoless.generic.decoding +package io.protoless.generic -import com.google.protobuf.CodedInputStream +import com.google.protobuf.{CodedInputStream, CodedOutputStream} import shapeless.{Generic, HList, Nat} import io.protoless.messages.Decoder.Result import io.protoless.messages.decoders.{AutoDecoder, IncrementalDecoder} +import io.protoless.messages.encoders.{AutoEncoder, IncrementalEncoder} -trait AutoDecoderInstances extends IncrementalDecoderInstances { +trait AutoEncoderDecoderInstances extends IncrementalEncoderDecoderInstances { implicit def decodeAuto[A, R <: HList](implicit gen: Generic.Aux[A, R], @@ -20,4 +21,14 @@ trait AutoDecoderInstances extends IncrementalDecoderInstances { } } + implicit def encodeAuto[A, R <: HList](implicit + gen: Generic.Aux[A, R], + encoder: IncrementalEncoder[R, Nat._1] + ): AutoEncoder[A] = new AutoEncoder[A] { + override def encode(a: A, output: CodedOutputStream): Unit = { + encoder.encode(gen.to(a), output) + output.flush() + } + } + } diff --git a/modules/generic/src/main/scala/io/protoless/generic/decoding/CustomMappingDecoderInstances.scala b/modules/generic/src/main/scala/io/protoless/generic/CustomMappingEncoderDecoderInstances.scala similarity index 50% rename from modules/generic/src/main/scala/io/protoless/generic/decoding/CustomMappingDecoderInstances.scala rename to modules/generic/src/main/scala/io/protoless/generic/CustomMappingEncoderDecoderInstances.scala index 5e18d75..878b4f0 100644 --- a/modules/generic/src/main/scala/io/protoless/generic/decoding/CustomMappingDecoderInstances.scala +++ b/modules/generic/src/main/scala/io/protoless/generic/CustomMappingEncoderDecoderInstances.scala @@ -1,15 +1,16 @@ -package io.protoless.generic.decoding +package io.protoless.generic -import com.google.protobuf.CodedInputStream +import com.google.protobuf.{CodedInputStream, CodedOutputStream} -import shapeless.ops.nat.ToInt import shapeless.{::, Generic, HList, HNil, Nat} +import shapeless.ops.nat.ToInt import io.protoless.messages.decoders.CustomMappingDecoder -import io.protoless.fields.FieldDecoder +import io.protoless.messages.encoders.CustomMappingEncoder +import io.protoless.fields.{FieldEncoder, FieldDecoder} import io.protoless.messages.Decoder.Result -trait CustomMappingDecoderInstances { +trait CustomMappingEncoderDecoderInstances extends IncrementalDecoderInstances { implicit val decodeCustomMappingHNil: CustomMappingDecoder[HNil, HNil] = new CustomMappingDecoder[HNil, HNil] { override def decode(input: CodedInputStream): Result[HNil] = Right(HNil) @@ -54,4 +55,45 @@ trait CustomMappingDecoderInstances { } } } + + implicit val encodeCustomMappingHNil: CustomMappingEncoder[HNil, HNil] = new CustomMappingEncoder[HNil, HNil] { + override def encode(a: HNil, output: CodedOutputStream): Unit = {} + } + + // Encode mapping specified with Nat (Nat._1 :: Nat._3 :: HNil) + implicit def encodeCustomMappingHList[H, T <: HList, L <: Nat, TN <: HList](implicit + hEncoder: FieldEncoder[H], + index: ToInt[L], + tEncoder: CustomMappingEncoder[T, TN] + ): CustomMappingEncoder[H :: T, L :: TN] = new CustomMappingEncoder[H :: T, L :: TN] { + override def encode(a: H :: T, output: CodedOutputStream): Unit = { + val (h :: t) = a + hEncoder.write(index(), h, output) + tEncoder.encode(t, output) + } + } + + // Encode mapping specified with Literal (1 :: 3 :: HNil) + implicit def encodeCustomMappingHListLiteral[H, T <: HList, L <: Int, TN <: HList](implicit + hEncoder: FieldEncoder[H], + index: ValueOf[L], + tEncoder: CustomMappingEncoder[T, TN] + ): CustomMappingEncoder[H :: T, L :: TN] = new CustomMappingEncoder[H :: T, L :: TN] { + override def encode(a: H :: T, output: CodedOutputStream): Unit = { + val (h :: t) = a + hEncoder.write(valueOf[L], h, output) + tEncoder.encode(t, output) + } + } + + implicit def encodeCustomMapping[A, L <: HList, R <: HList](implicit + gen: Generic.Aux[A, R], + encoder: CustomMappingEncoder[R, L] + ): CustomMappingEncoder[A, L] = new CustomMappingEncoder[A, L] { + override def encode(a: A, output: CodedOutputStream): Unit = { + encoder.encode(gen.to(a), output) + output.flush() + } + } + } diff --git a/modules/generic/src/main/scala/io/protoless/generic/IncrementalDecoderInstances.scala b/modules/generic/src/main/scala/io/protoless/generic/IncrementalDecoderInstances.scala new file mode 100644 index 0000000..474a3d3 --- /dev/null +++ b/modules/generic/src/main/scala/io/protoless/generic/IncrementalDecoderInstances.scala @@ -0,0 +1,5 @@ +package io.protoless.generic + +trait IncrementalDecoderInstances { + +} diff --git a/modules/generic/src/main/scala/io/protoless/generic/decoding/IncrementalDecoderInstances.scala b/modules/generic/src/main/scala/io/protoless/generic/IncrementalEncoderInstances.scala similarity index 51% rename from modules/generic/src/main/scala/io/protoless/generic/decoding/IncrementalDecoderInstances.scala rename to modules/generic/src/main/scala/io/protoless/generic/IncrementalEncoderInstances.scala index 6e3bfa8..bda6e9d 100644 --- a/modules/generic/src/main/scala/io/protoless/generic/decoding/IncrementalDecoderInstances.scala +++ b/modules/generic/src/main/scala/io/protoless/generic/IncrementalEncoderInstances.scala @@ -1,13 +1,43 @@ -package io.protoless.generic.decoding +package io.protoless.generic +import com.google.protobuf.CodedOutputStream import com.google.protobuf.CodedInputStream import shapeless.{::, Generic, HList, HNil, Nat, Succ} +import shapeless.ops.nat.ToInt +import io.protoless.messages.encoders.IncrementalEncoder +import io.protoless.fields.FieldEncoder import io.protoless.messages.Decoder.Result import io.protoless.messages.decoders.IncrementalDecoder import io.protoless.fields.FieldDecoder -trait IncrementalDecoderInstances { +trait IncrementalEncoderDecoderInstances extends CustomMappingEncoderDecoderInstances { + + implicit def encodeIncrementalHNil[N <: Nat]: IncrementalEncoder[HNil, N] = new IncrementalEncoder[HNil, N] { + override def encode(a: HNil, output: CodedOutputStream): Unit = {} + } + + implicit def encodeIncrementalHList[H, T <: HList, N <: Nat](implicit + hEncoder: FieldEncoder[H], + index: ToInt[N], + tEncoder: IncrementalEncoder[T, Succ[N]] + ): IncrementalEncoder[H :: T, N] = new IncrementalEncoder[H :: T, N] { + override def encode(a: H :: T, output: CodedOutputStream): Unit = { + val (h :: t) = a + hEncoder.write(index(), h, output) + tEncoder.encode(t, output) + } + } + + implicit def encodeIncremental[A, N <: Nat, R <: HList](implicit + gen: Generic.Aux[A, R], + encoder: IncrementalEncoder[R, N] + ): IncrementalEncoder[A, N] = new IncrementalEncoder[A, N] { + override def encode(a: A, output: CodedOutputStream): Unit = { + encoder.encode(gen.to(a), output) + output.flush() + } + } implicit def decodeIncrementalHNil[N <: Nat]: IncrementalDecoder[HNil, N] = new IncrementalDecoder[HNil, N] { override def decode(input: CodedInputStream): Result[HNil] = Right(HNil) @@ -37,4 +67,5 @@ trait IncrementalDecoderInstances { } } } + } diff --git a/modules/generic/src/main/scala/io/protoless/generic/encoding/internal/SemiAutoEncoderInstances.scala b/modules/generic/src/main/scala/io/protoless/generic/SemiAutoEncoderDecoderInstances.scala similarity index 51% rename from modules/generic/src/main/scala/io/protoless/generic/encoding/internal/SemiAutoEncoderInstances.scala rename to modules/generic/src/main/scala/io/protoless/generic/SemiAutoEncoderDecoderInstances.scala index 7f0e190..f1bef07 100644 --- a/modules/generic/src/main/scala/io/protoless/generic/encoding/internal/SemiAutoEncoderInstances.scala +++ b/modules/generic/src/main/scala/io/protoless/generic/SemiAutoEncoderDecoderInstances.scala @@ -1,10 +1,10 @@ -package io.protoless.generic.encoding.internal +package io.protoless.generic import shapeless.Nat -import io.protoless.generic.encoding.IncrementalEncoderInstances -import io.protoless.messages.Encoder +import io.protoless.messages.{Encoder, Decoder} import io.protoless.messages.encoders.IncrementalEncoder +import io.protoless.messages.decoders.IncrementalDecoder /** * Internal class allowing to restrict automatic derivation of type `A`. @@ -12,10 +12,15 @@ import io.protoless.messages.encoders.IncrementalEncoder * [[SemiAutoEncoder]] can only be retrieved with `io.protoless.generic.semiauto.deriveEncoder`. */ private[protoless] class SemiAutoEncoder[A](val underlying: Encoder[A]) +private[protoless] class SemiAutoDecoder[A](val underlying: Decoder[A]) -private[protoless] class SemiAutoEncoderInstances extends IncrementalEncoderInstances { +private[protoless] trait SemiAutoEncoderDecoderInstances extends IncrementalEncoderDecoderInstances { implicit def encodeSemiAutoInstance[A](implicit encoder: IncrementalEncoder[A, Nat._1]): SemiAutoEncoder[A] = { new SemiAutoEncoder[A](encoder) } + + implicit def decodeSemiAutoInstance[A](implicit decoder: IncrementalDecoder[A, Nat._1]): SemiAutoDecoder[A] = { + new SemiAutoDecoder[A](decoder) + } } diff --git a/modules/generic/src/main/scala/io/protoless/generic/decoding/internal/SemiAutoDecoderInstances.scala b/modules/generic/src/main/scala/io/protoless/generic/decoding/internal/SemiAutoDecoderInstances.scala deleted file mode 100644 index 494611b..0000000 --- a/modules/generic/src/main/scala/io/protoless/generic/decoding/internal/SemiAutoDecoderInstances.scala +++ /dev/null @@ -1,22 +0,0 @@ -package io.protoless.generic.decoding.internal - -import shapeless.Nat - -import io.protoless.generic.decoding.IncrementalDecoderInstances -import io.protoless.messages.Decoder -import io.protoless.messages.decoders.IncrementalDecoder - -/** - * Internal class allowing to restrict automatic derivation of type `A`. - * - * [[SemiAutoDecoder]] can only be retrieved with `io.protoless.generic.semiauto.deriveDecoder`. - */ -private[protoless] class SemiAutoDecoder[A](val underlying: Decoder[A]) - -private[protoless] trait SemiAutoDecoderInstances extends IncrementalDecoderInstances { - - implicit def decodeSemiAutoInstance[A](implicit decoder: IncrementalDecoder[A, Nat._1]): SemiAutoDecoder[A] = { - new SemiAutoDecoder[A](decoder) - } - -} diff --git a/modules/generic/src/main/scala/io/protoless/generic/encoding/AutoEncoderInstances.scala b/modules/generic/src/main/scala/io/protoless/generic/encoding/AutoEncoderInstances.scala deleted file mode 100644 index f5ce3d8..0000000 --- a/modules/generic/src/main/scala/io/protoless/generic/encoding/AutoEncoderInstances.scala +++ /dev/null @@ -1,20 +0,0 @@ -package io.protoless.generic.encoding - -import com.google.protobuf.CodedOutputStream -import shapeless.{Generic, HList, Nat} - -import io.protoless.messages.encoders.{AutoEncoder, IncrementalEncoder} - -trait AutoEncoderInstances extends IncrementalEncoderInstances { - - implicit def encodeAuto[A, R <: HList](implicit - gen: Generic.Aux[A, R], - encoder: IncrementalEncoder[R, Nat._1] - ): AutoEncoder[A] = new AutoEncoder[A] { - override def encode(a: A, output: CodedOutputStream): Unit = { - encoder.encode(gen.to(a), output) - output.flush() - } - } - -} diff --git a/modules/generic/src/main/scala/io/protoless/generic/encoding/CustomMappingEncoderInstances.scala b/modules/generic/src/main/scala/io/protoless/generic/encoding/CustomMappingEncoderInstances.scala deleted file mode 100644 index ed05f5c..0000000 --- a/modules/generic/src/main/scala/io/protoless/generic/encoding/CustomMappingEncoderInstances.scala +++ /dev/null @@ -1,53 +0,0 @@ -package io.protoless.generic.encoding - -import com.google.protobuf.CodedOutputStream - -import shapeless.{::, Generic, HList, HNil, Nat} -import shapeless.ops.nat.ToInt - -import io.protoless.messages.encoders.CustomMappingEncoder -import io.protoless.fields.FieldEncoder - -trait CustomMappingEncoderInstances { - - implicit val encodeCustomMappingHNil: CustomMappingEncoder[HNil, HNil] = new CustomMappingEncoder[HNil, HNil] { - override def encode(a: HNil, output: CodedOutputStream): Unit = {} - } - - // Encode mapping specified with Nat (Nat._1 :: Nat._3 :: HNil) - implicit def encodeCustomMappingHList[H, T <: HList, L <: Nat, TN <: HList](implicit - hEncoder: FieldEncoder[H], - index: ToInt[L], - tEncoder: CustomMappingEncoder[T, TN] - ): CustomMappingEncoder[H :: T, L :: TN] = new CustomMappingEncoder[H :: T, L :: TN] { - override def encode(a: H :: T, output: CodedOutputStream): Unit = { - val (h :: t) = a - hEncoder.write(index(), h, output) - tEncoder.encode(t, output) - } - } - - // Encode mapping specified with Literal (1 :: 3 :: HNil) - implicit def encodeCustomMappingHListLiteral[H, T <: HList, L <: Int, TN <: HList](implicit - hEncoder: FieldEncoder[H], - index: ValueOf[L], - tEncoder: CustomMappingEncoder[T, TN] - ): CustomMappingEncoder[H :: T, L :: TN] = new CustomMappingEncoder[H :: T, L :: TN] { - override def encode(a: H :: T, output: CodedOutputStream): Unit = { - val (h :: t) = a - hEncoder.write(valueOf[L], h, output) - tEncoder.encode(t, output) - } - } - - implicit def encodeCustomMapping[A, L <: HList, R <: HList](implicit - gen: Generic.Aux[A, R], - encoder: CustomMappingEncoder[R, L] - ): CustomMappingEncoder[A, L] = new CustomMappingEncoder[A, L] { - override def encode(a: A, output: CodedOutputStream): Unit = { - encoder.encode(gen.to(a), output) - output.flush() - } - } - -} diff --git a/modules/generic/src/main/scala/io/protoless/generic/encoding/IncrementalEncoderInstances.scala b/modules/generic/src/main/scala/io/protoless/generic/encoding/IncrementalEncoderInstances.scala deleted file mode 100644 index e945ddf..0000000 --- a/modules/generic/src/main/scala/io/protoless/generic/encoding/IncrementalEncoderInstances.scala +++ /dev/null @@ -1,38 +0,0 @@ -package io.protoless.generic.encoding - -import com.google.protobuf.CodedOutputStream -import shapeless.{::, Generic, HList, HNil, Nat, Succ} -import shapeless.ops.nat.ToInt - -import io.protoless.messages.encoders.IncrementalEncoder -import io.protoless.fields.FieldEncoder - -trait IncrementalEncoderInstances { - - implicit def encodeIncrementalHNil[N <: Nat]: IncrementalEncoder[HNil, N] = new IncrementalEncoder[HNil, N] { - override def encode(a: HNil, output: CodedOutputStream): Unit = {} - } - - implicit def encodeIncrementalHList[H, T <: HList, N <: Nat](implicit - hEncoder: FieldEncoder[H], - index: ToInt[N], - tEncoder: IncrementalEncoder[T, Succ[N]] - ): IncrementalEncoder[H :: T, N] = new IncrementalEncoder[H :: T, N] { - override def encode(a: H :: T, output: CodedOutputStream): Unit = { - val (h :: t) = a - hEncoder.write(index(), h, output) - tEncoder.encode(t, output) - } - } - - implicit def encodeIncremental[A, N <: Nat, R <: HList](implicit - gen: Generic.Aux[A, R], - encoder: IncrementalEncoder[R, N] - ): IncrementalEncoder[A, N] = new IncrementalEncoder[A, N] { - override def encode(a: A, output: CodedOutputStream): Unit = { - encoder.encode(gen.to(a), output) - output.flush() - } - } - -} diff --git a/modules/generic/src/main/scala/io/protoless/generic/package.scala b/modules/generic/src/main/scala/io/protoless/generic/package.scala index 9e55ccd..971eac6 100644 --- a/modules/generic/src/main/scala/io/protoless/generic/package.scala +++ b/modules/generic/src/main/scala/io/protoless/generic/package.scala @@ -4,10 +4,6 @@ import shapeless.HList import io.protoless.messages.decoders.CustomMappingDecoder import io.protoless.messages.encoders.CustomMappingEncoder -import io.protoless.generic.decoding.{AutoDecoderInstances, CustomMappingDecoderInstances} -import io.protoless.generic.decoding.internal.{SemiAutoDecoder, SemiAutoDecoderInstances} -import io.protoless.generic.encoding.{AutoEncoderInstances, CustomMappingEncoderInstances} -import io.protoless.generic.encoding.internal.{SemiAutoEncoder, SemiAutoEncoderInstances} import io.protoless.messages.{Decoder, Encoder} package object generic { @@ -20,13 +16,13 @@ package object generic { * You can still derive [[messages.decoders.CustomMappingDecoder]] and [[messages.encoders.CustomMappingEncoder]] * with `semiauto.deriveDecoder[A, L]` or by summoning a decoder with `CustomMappingDecoder[A, HList]` (idem for Encoders). */ - object auto extends AutoDecoderInstances with CustomMappingDecoderInstances with AutoEncoderInstances with CustomMappingEncoderInstances + object auto extends AutoEncoderDecoderInstances /** * Allows to manually derive [[Decoder]] and [[Encoder]], * either with `Automatic` strategy or `Custom Mapping` strategy. */ - object semiauto extends SemiAutoEncoderInstances with SemiAutoDecoderInstances with CustomMappingDecoderInstances with CustomMappingEncoderInstances { + object semiauto extends SemiAutoEncoderDecoderInstances { /** * Derive an [[Decoder]] to decode a type `A` from a protobuf message, for which diff --git a/modules/generic/src/test/scala/io/protoless/generic/messages/CustomMappingEncoderDecoderSuite.scala b/modules/generic/src/test/scala/io/protoless/generic/messages/CustomMappingEncoderDecoderSuite.scala index 7de593a..9e96c6c 100644 --- a/modules/generic/src/test/scala/io/protoless/generic/messages/CustomMappingEncoderDecoderSuite.scala +++ b/modules/generic/src/test/scala/io/protoless/generic/messages/CustomMappingEncoderDecoderSuite.scala @@ -9,10 +9,11 @@ import io.protoless.tests.ProtolessSuite import io.protoless.tests.instances.EqualityInstances import io.protoless.tests.samples._ import io.protoless.tests.samples.TestCaseNestedCustomMapping.InnerNestedCustomMapping +import io.protoless.generic.SemiAutoEncoderDecoderInstances -class CustomMappingEncoderDecoderSuite extends ProtolessSuite with EqualityInstances with EncoderDecoderAssertions { +trait CustomMappingEncoderDecoderSuite extends ProtolessSuite with EqualityInstances with EncoderDecoderAssertions with SemiAutoEncoderDecoderInstances { - import io.protoless.generic.semiauto._ + import io.protoless.generic.semiauto.{deriveEncoder, deriveDecoder} // Fields number specified with Nat type IndexSimple = Nat._2 :: Nat._5 :: Nat._13 :: Nat._16 :: HNil diff --git a/modules/generic/src/test/scala/io/protoless/generic/messages/SemiAutoEncoderDecoderSuite.scala b/modules/generic/src/test/scala/io/protoless/generic/messages/SemiAutoEncoderDecoderSuite.scala index df46d9e..61051d6 100644 --- a/modules/generic/src/test/scala/io/protoless/generic/messages/SemiAutoEncoderDecoderSuite.scala +++ b/modules/generic/src/test/scala/io/protoless/generic/messages/SemiAutoEncoderDecoderSuite.scala @@ -6,10 +6,11 @@ import io.protoless.messages.{Decoder, Encoder} import io.protoless.tests.ProtolessSuite import io.protoless.tests.instances.EqualityInstances import io.protoless.tests.samples._ +import io.protoless.generic.SemiAutoEncoderDecoderInstances -class SemiAutoEncoderDecoderSuite extends ProtolessSuite with EqualityInstances with EncoderDecoderAssertions { +class SemiAutoEncoderDecoderSuite extends ProtolessSuite with EqualityInstances with EncoderDecoderAssertions with SemiAutoEncoderDecoderInstances { - import io.protoless.generic.semiauto._ + import io.protoless.generic.semiauto.{deriveEncoder, deriveDecoder} implicit val decoderTestCaseAllFields: Decoder[TestCaseAllFields] = deriveDecoder[TestCaseAllFields] implicit val decoderTestCaseOptionalFields: Decoder[TestCaseOptionalFields] = deriveDecoder[TestCaseOptionalFields]