All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.circe.shapes.LabelledCoproductInstances.scala Maven / Gradle / Ivy

The newest version!
package io.circe.shapes

import cats.kernel.Eq
import io.circe.{ Decoder, DecodingFailure, Encoder, HCursor, Json, KeyDecoder, KeyEncoder }
import shapeless.{ :+:, Coproduct, Inl, Inr, Widen, Witness }
import shapeless.labelled.{ field, FieldType }

trait LabelledCoproductInstances extends LowPriorityLabelledCoproductInstances {
  implicit final def decodeSymbolLabelledCCons[K <: Symbol, V, R <: Coproduct](
    implicit
    witK: Witness.Aux[K],
    decodeV: Decoder[V],
    decodeR: Decoder[R]
  ): Decoder[FieldType[K, V] :+: R] = new Decoder[FieldType[K, V] :+: R] {
    def apply(c: HCursor): Decoder.Result[FieldType[K, V] :+: R] =
      Decoder.resultSemigroupK.combineK(
        c.get[V](witK.value.name).right.map(v => Inl(field[K](v))),
        decodeR(c).right.map(Inr(_))
      )
  }

  implicit final def encodeSymbolLabelledCCons[K <: Symbol, V, R <: Coproduct](
    implicit
    witK: Witness.Aux[K],
    encodeV: Encoder[V],
    encodeR: Encoder[R]
  ): Encoder[FieldType[K, V] :+: R] = new Encoder[FieldType[K, V] :+: R] {
    def apply(a: FieldType[K, V] :+: R): Json = a match {
      case Inl(l) => Json.obj((witK.value.name, encodeV(l)))
      case Inr(r) => encodeR(r)
    }
  }
}

private[shapes] trait LowPriorityLabelledCoproductInstances extends CoproductInstances {
  implicit final def decodeLabelledCCons[K, W >: K, V, R <: Coproduct](
    implicit
    witK: Witness.Aux[K],
    widenK: Widen.Aux[K, W],
    eqW: Eq[W],
    decodeW: KeyDecoder[W],
    decodeV: Decoder[V],
    decodeR: Decoder[R]
  ): Decoder[FieldType[K, V] :+: R] = new Decoder[FieldType[K, V] :+: R] {
    private[this] val widened = widenK(witK.value)
    private[this] val isK: String => Boolean = decodeW(_).exists(eqW.eqv(widened, _))

    def apply(c: HCursor): Decoder.Result[FieldType[K, V] :+: R] =
      Decoder.resultSemigroupK.combineK(
        c.keys
          .flatMap(_.find(isK))
          .fold[Decoder.Result[String]](
            Left(DecodingFailure("Record", c.history))
          )(Right(_))
          .right
          .flatMap(c.get[V](_).right.map(v => Inl(field[K](v)))),
        decodeR(c).right.map(Inr(_))
      )
  }

  implicit final def encodeLabelledCCons[K, W >: K, V, R <: Coproduct](
    implicit
    witK: Witness.Aux[K],
    eqW: Eq[W],
    encodeW: KeyEncoder[W],
    encodeV: Encoder[V],
    encodeR: Encoder[R]
  ): Encoder[FieldType[K, V] :+: R] = new Encoder[FieldType[K, V] :+: R] {
    def apply(a: FieldType[K, V] :+: R): Json = a match {
      case Inl(l) => Json.obj((encodeW(witK.value), encodeV(l)))
      case Inr(r) => encodeR(r)
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy