Skip to content

Commit

Permalink
Use refinement types on mirrors - fixes #706
Browse files Browse the repository at this point in the history
  • Loading branch information
mpilquist committed Sep 22, 2022
1 parent cc469ff commit 044f787
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 28 deletions.
11 changes: 8 additions & 3 deletions modules/core/shared/src/main/scala-3/syntax/CodecOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
Expand All @@ -50,4 +55,4 @@ trait ToCodecOpsLow {
new CodecOpsLow(self)
}

object codec extends ToCodecOps
object codec extends ToCodecOps
10 changes: 8 additions & 2 deletions modules/core/shared/src/main/scala-3/syntax/DecoderOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)

}

Expand All @@ -38,4 +44,4 @@ trait ToDecoderOpsLow {
new DecoderOpsLow(self)
}

object decoder extends ToDecoderOps
object decoder extends ToDecoderOps
12 changes: 9 additions & 3 deletions modules/core/shared/src/main/scala-3/syntax/EncoderOps.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
Expand All @@ -38,4 +44,4 @@ trait ToEncoderOpsLow {
new EncoderOpsLow(self)
}

object encoder extends ToEncoderOps
object encoder extends ToEncoderOps
71 changes: 51 additions & 20 deletions modules/core/shared/src/main/scala-3/util/Twiddler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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)) }
}

Expand Down Expand Up @@ -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)
}

0 comments on commit 044f787

Please sign in to comment.