From 044f7876b251a70f01f2904617fc52de5d3a49ee Mon Sep 17 00:00:00 2001 From: Michael Pilquist Date: Wed, 21 Sep 2022 22:14:15 -0400 Subject: [PATCH] Use refinement types on mirrors - fixes #706 --- .../src/main/scala-3/syntax/CodecOps.scala | 11 ++- .../src/main/scala-3/syntax/DecoderOps.scala | 10 ++- .../src/main/scala-3/syntax/EncoderOps.scala | 12 +++- .../src/main/scala-3/util/Twiddler.scala | 71 +++++++++++++------ 4 files changed, 76 insertions(+), 28 deletions(-) diff --git a/modules/core/shared/src/main/scala-3/syntax/CodecOps.scala b/modules/core/shared/src/main/scala-3/syntax/CodecOps.scala index eaf8e18a..1820b282 100644 --- a/modules/core/shared/src/main/scala-3/syntax/CodecOps.scala +++ b/modules/core/shared/src/main/scala-3/syntax/CodecOps.scala @@ -20,11 +20,16 @@ class CodecOps[A <: Tuple](self: Codec[A]) { (other, self).contramapN(t => (t.head, t.tail)) def pimap[P <: Product]( + using m: Mirror.ProductOf[P] { type MirroredElemTypes = A } + ): Codec[P] = + self.imap(m.fromProduct)(p => Tuple.fromProductTyped(p)) + + // For binary compatibility with Skunk 0.3.1 and prior + private[skunk] def pimap[P <: Product]( using m: Mirror.ProductOf[P], i: m.MirroredElemTypes =:= A ): Codec[P] = - self.imap(m.fromProduct)(p => i(Tuple.fromProductTyped(p))) - + pimap(using m.asInstanceOf) } class CodecOpsLow[A](self: Codec[A]) { @@ -50,4 +55,4 @@ trait ToCodecOpsLow { new CodecOpsLow(self) } -object codec extends ToCodecOps \ No newline at end of file +object codec extends ToCodecOps diff --git a/modules/core/shared/src/main/scala-3/syntax/DecoderOps.scala b/modules/core/shared/src/main/scala-3/syntax/DecoderOps.scala index 2b34c8f9..9650636d 100644 --- a/modules/core/shared/src/main/scala-3/syntax/DecoderOps.scala +++ b/modules/core/shared/src/main/scala-3/syntax/DecoderOps.scala @@ -14,10 +14,16 @@ class DecoderOps[A <: Tuple](self: Decoder[A]) { (other, self).mapN(_ *: _) def pmap[P <: Product]( + using m: Mirror.ProductOf[P] { type MirroredElemTypes = A } + ): Decoder[P] = + self.map(m.fromProduct) + + // For binary compatibility with Skunk 0.3.1 and prior + private[skunk] def pmap[P <: Product]( using m: Mirror.ProductOf[P], i: m.MirroredElemTypes =:= A ): Decoder[P] = - self.map(m.fromProduct) + pmap(using m.asInstanceOf) } @@ -38,4 +44,4 @@ trait ToDecoderOpsLow { new DecoderOpsLow(self) } -object decoder extends ToDecoderOps \ No newline at end of file +object decoder extends ToDecoderOps diff --git a/modules/core/shared/src/main/scala-3/syntax/EncoderOps.scala b/modules/core/shared/src/main/scala-3/syntax/EncoderOps.scala index 8b7c53a3..49617dd4 100644 --- a/modules/core/shared/src/main/scala-3/syntax/EncoderOps.scala +++ b/modules/core/shared/src/main/scala-3/syntax/EncoderOps.scala @@ -14,11 +14,17 @@ class EncoderOps[A <: Tuple](self: Encoder[A]) { (other, self).contramapN[B *: A] { case b *: a => (b, a) } def pcontramap[P <: Product]( + using m: Mirror.ProductOf[P] { type MirroredElemTypes = A } + ): Encoder[P] = + self.contramap(p => Tuple.fromProductTyped(p)) + + // For binary compatibility with Skunk 0.3.1 and prior + private[skunk] def pcontramap[P <: Product]( using m: Mirror.ProductOf[P], i: m.MirroredElemTypes =:= A ): Encoder[P] = - self.contramap(p => i(Tuple.fromProductTyped(p))) - + pcontramap(using m.asInstanceOf) + } class EncoderOpsLow[A](self: Encoder[A]) { @@ -38,4 +44,4 @@ trait ToEncoderOpsLow { new EncoderOpsLow(self) } -object encoder extends ToEncoderOps \ No newline at end of file +object encoder extends ToEncoderOps diff --git a/modules/core/shared/src/main/scala-3/util/Twiddler.scala b/modules/core/shared/src/main/scala-3/util/Twiddler.scala index f5c66472..dbb30ff3 100644 --- a/modules/core/shared/src/main/scala-3/util/Twiddler.scala +++ b/modules/core/shared/src/main/scala-3/util/Twiddler.scala @@ -26,62 +26,56 @@ object Twiddler { type Aux[A, O] = Twiddler[A] { type Out = O } given product1[P <: Product, A]( - using m: Mirror.ProductOf[P], - i: m.MirroredElemTypes =:= A *: EmptyTuple - ): (Twiddler[P] { type Out = A }) = + using m: Mirror.ProductOf[P] { type MirroredElemTypes = A *: EmptyTuple } + ): (Twiddler[P] { type Out = A }) = new Twiddler[P] { type Out = A - def to(p: P): Out = i(Tuple.fromProductTyped(p)) match { case a *: EmptyTuple => a } + def to(p: P): Out = Tuple.fromProductTyped(p) match { case a *: EmptyTuple => a } def from(o: Out): P = o match { case a => m.fromProduct(a *: EmptyTuple) } } given product2[P <: Product, A, B]( - using m: Mirror.ProductOf[P], - i: m.MirroredElemTypes =:= (A, B) - ): (Twiddler[P] { type Out = A ~ B }) = + using m: Mirror.ProductOf[P] { type MirroredElemTypes = (A, B) } + ): (Twiddler[P] { type Out = A ~ B }) = new Twiddler[P] { type Out = A ~ B - def to(p: P): Out = i(Tuple.fromProductTyped(p)) match { case (a, b) => a ~ b } + def to(p: P): Out = Tuple.fromProductTyped(p) match { case (a, b) => a ~ b } def from(o: Out): P = o match { case a ~ b => m.fromProduct((a, b)) } } given product3[P <: Product, A, B, C]( - using m: Mirror.ProductOf[P], - i: m.MirroredElemTypes =:= (A, B, C) + using m: Mirror.ProductOf[P] { type MirroredElemTypes = (A, B, C) } ): (Twiddler[P] { type Out = A ~ B ~ C }) = new Twiddler[P] { type Out = A ~ B ~ C - def to(p: P): Out = i(Tuple.fromProductTyped(p)) match { case (a, b, c) => a ~ b ~ c } + def to(p: P): Out = Tuple.fromProductTyped(p) match { case (a, b, c) => a ~ b ~ c } def from(o: Out): P = o match { case a ~ b ~ c => m.fromProduct((a, b, c)) } } given product4[P <: Product, A, B, C, D]( - using m: Mirror.ProductOf[P], - i: m.MirroredElemTypes =:= (A, B, C, D) + using m: Mirror.ProductOf[P] { type MirroredElemTypes = (A, B, C, D) } ): (Twiddler[P] { type Out = A ~ B ~ C ~ D }) = new Twiddler[P] { type Out = A ~ B ~ C ~ D - def to(p: P): Out = i(Tuple.fromProductTyped(p)) match { case (a, b, c, d) => a ~ b ~ c ~ d } + def to(p: P): Out = Tuple.fromProductTyped(p) match { case (a, b, c, d) => a ~ b ~ c ~ d } def from(o: Out): P = o match { case a ~ b ~ c ~ d => m.fromProduct((a, b, c, d)) } } given product5[P <: Product, A, B, C, D, E]( - using m: Mirror.ProductOf[P], - i: m.MirroredElemTypes =:= (A, B, C, D, E) + using m: Mirror.ProductOf[P] { type MirroredElemTypes = (A, B, C, D, E) } ): (Twiddler[P] { type Out = A ~ B ~ C ~ D ~ E }) = new Twiddler[P] { type Out = A ~ B ~ C ~ D ~ E - def to(p: P): Out = i(Tuple.fromProductTyped(p)) match { case (a, b, c, d, e) => a ~ b ~ c ~ d ~ e } + def to(p: P): Out = Tuple.fromProductTyped(p) match { case (a, b, c, d, e) => a ~ b ~ c ~ d ~ e } def from(o: Out): P = o match { case a ~ b ~ c ~ d ~ e => m.fromProduct((a, b, c, d, e)) } } given product6[P <: Product, A, B, C, D, E, F]( - using m: Mirror.ProductOf[P], - i: m.MirroredElemTypes =:= (A, B, C, D, E, F) + using m: Mirror.ProductOf[P] { type MirroredElemTypes = (A, B, C, D, E, F) } ): (Twiddler[P] { type Out = A ~ B ~ C ~ D ~ E ~ F }) = new Twiddler[P] { type Out = A ~ B ~ C ~ D ~ E ~ F - def to(p: P): Out = i(Tuple.fromProductTyped(p)) match { case (a, b, c, d, e, f) => a ~ b ~ c ~ d ~ e ~ f } + def to(p: P): Out = Tuple.fromProductTyped(p) match { case (a, b, c, d, e, f) => a ~ b ~ c ~ d ~ e ~ f } def from(o: Out): P = o match { case a ~ b ~ c ~ d ~ e ~ f => m.fromProduct((a, b, c, d, e, f)) } } @@ -221,5 +215,42 @@ object Twiddler { m.fromProduct((a, b, c, d, e, f, g, h, i, j, k, l, q, r, s, t)) } } + + // For binary compatibility with Skunk 0.3.1 and prior + private[skunk] def product1[P <: Product, A]( + using m: Mirror.ProductOf[P], + i: m.MirroredElemTypes =:= A *: EmptyTuple + ): (Twiddler[P] { type Out = A }) = + product1(using m.asInstanceOf) + + private[skunk] def product2[P <: Product, A, B]( + using m: Mirror.ProductOf[P], + i: m.MirroredElemTypes =:= (A, B) + ): (Twiddler[P] { type Out = A ~ B }) = + product2(using m.asInstanceOf) + + private[skunk] def product3[P <: Product, A, B, C]( + using m: Mirror.ProductOf[P], + i: m.MirroredElemTypes =:= (A, B, C) + ): (Twiddler[P] { type Out = A ~ B ~ C }) = + product3(using m.asInstanceOf) + + private[skunk] def product4[P <: Product, A, B, C, D]( + using m: Mirror.ProductOf[P], + i: m.MirroredElemTypes =:= (A, B, C, D) + ): (Twiddler[P] { type Out = A ~ B ~ C ~ D }) = + product4(using m.asInstanceOf) + + private[skunk] def product5[P <: Product, A, B, C, D, E]( + using m: Mirror.ProductOf[P], + i: m.MirroredElemTypes =:= (A, B, C, D, E) + ): (Twiddler[P] { type Out = A ~ B ~ C ~ D ~ E }) = + product5(using m.asInstanceOf) + + private[skunk] def product6[P <: Product, A, B, C, D, E, F]( + using m: Mirror.ProductOf[P], + i: m.MirroredElemTypes =:= (A, B, C, D, E, F) + ): (Twiddler[P] { type Out = A ~ B ~ C ~ D ~ E ~ F }) = + product6(using m.asInstanceOf) }