This repository was archived by the owner on Oct 25, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathDiscriminatedCodec.scala
More file actions
59 lines (48 loc) · 1.49 KB
/
DiscriminatedCodec.scala
File metadata and controls
59 lines (48 loc) · 1.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package io.pg.config
import io.circe.Codec
import io.circe.Decoder
import io.circe.DecodingFailure
import io.circe.Json
import scala.deriving.Mirror
// Temporary replacement for https://github.com/circe/circe/pull/1800
object DiscriminatedCodec {
import scala.deriving._
import scala.compiletime._
private inline def deriveAll[T <: Tuple]: List[Codec.AsObject[_]] = inline erasedValue[T] match {
case _: EmptyTuple => Nil
case _: (h *: t) =>
Codec
.AsObject
.derived[h](
// feels odd but works
using summonInline[Mirror.Of[h]]
) :: deriveAll[t]
}
inline def derived[A](
discriminator: String
)(
using inline m: Mirror.SumOf[A]
): Codec.AsObject[A] = {
val codecs: List[Codec.AsObject[A]] = deriveAll[m.MirroredElemTypes].map(_.asInstanceOf[Codec.AsObject[A]])
val labels =
summonAll[Tuple.Map[m.MirroredElemLabels, ValueOf]]
.toList
.asInstanceOf[List[ValueOf[String]]]
.map(_.value)
Codec
.AsObject
.from[A](
Decoder[String].at(discriminator).flatMap { key =>
val index = labels.indexOf(key)
if (index < 0) Decoder.failedWithMessage(s"Unknown discriminator field $discriminator: $key")
else codecs(index)
},
value => {
val index = m.ordinal(value)
codecs(index)
.mapJsonObject(_.add(discriminator, Json.fromString(labels(index))))
.encodeObject(value)
}
)
}
}