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

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

The newest version!
/*
 * Copyright 2024 circe
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.circe.shapes

import cats.data.Validated
import io.circe.Decoder
import io.circe.DecodingFailure
import io.circe.Encoder
import io.circe.HCursor
import shapeless.AdditiveCollection
import shapeless.Nat
import shapeless.Sized
import shapeless.ops.nat.ToInt

import scala.collection.GenTraversable

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("Couldn't decode sized collection", 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 - 2024 Weber Informatics LLC | Privacy Policy