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

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

package io.circe.shapes

import cats.data.Validated
import io.circe.{ Decoder, DecodingFailure, Encoder, HCursor }
import scala.collection.GenTraversable
import shapeless.{ AdditiveCollection, Nat, Sized }
import shapeless.ops.nat.ToInt

trait SizedInstances {
  implicit final def decodeSized[L <: Nat, C[X] <: GenTraversable[X], A](
    implicit
    decodeCA: Decoder[C[A]],
    ev: AdditiveCollection[C[A]],
    toInt: ToInt[L]
  ): Decoder[Sized[C[A], L]] = new Decoder[Sized[C[A], L]] {
    private[this] def checkSize(coll: C[A]): Option[Sized[C[A], L]] =
      if (coll.size == toInt()) Some(Sized.wrap[C[A], L](coll)) else None

    private[this] def failure(c: HCursor): DecodingFailure = DecodingFailure(s"Sized[C[A], _${toInt()}]", c.history)

    def apply(c: HCursor): Decoder.Result[Sized[C[A], L]] =
      decodeCA(c) match {
        case Right(as) =>
          checkSize(as) match {
            case Some(s) => Right(s)
            case None    => Left(failure(c))
          }
        case l @ Left(_) => l.asInstanceOf[Decoder.Result[Sized[C[A], L]]]
      }

    override def decodeAccumulating(c: HCursor): Decoder.AccumulatingResult[Sized[C[A], L]] =
      decodeCA.decodeAccumulating(c) match {
        case Validated.Valid(as) =>
          checkSize(as) match {
            case Some(s) => Validated.valid(s)
            case None    => Validated.invalidNel(failure(c))
          }
        case l @ Validated.Invalid(_) => l.asInstanceOf[Decoder.AccumulatingResult[Sized[C[A], L]]]
      }
  }

  implicit def encodeSized[L <: Nat, C[_], A](implicit encodeCA: Encoder[C[A]]): Encoder[Sized[C[A], L]] =
    encodeCA.contramap(_.unsized)
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy