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

io.circe.KeyDecoder.scala Maven / Gradle / Ivy

There is a newer version: 0.9.3
Show newest version
package io.circe

import cats.MonadError
import java.util.UUID
import scala.annotation.tailrec

/**
 * A type class that provides a conversion from a string used as a JSON key to a
 * value of type `A`.
 */
abstract class KeyDecoder[A] extends Serializable { self =>
  /**
   * Convert a value to String.
   */
  def apply(key: String): Option[A]

  /**
   * Construct an instance for type `B` from an instance for type `A`.
   */
  final def map[B](f: A => B): KeyDecoder[B] = new KeyDecoder[B] {
    final def apply(key: String): Option[B] = self(key).map(f)
  }

  /**
   * Construct an instance for type `B` from an instance for type `A` given a
   * monadic function.
   */
  final def flatMap[B](f: A => KeyDecoder[B]): KeyDecoder[B] = new KeyDecoder[B] {
    final def apply(key: String): Option[B] = self(key).flatMap(a => f(a)(key))
  }
}

final object KeyDecoder {
  def apply[A](implicit A: KeyDecoder[A]): KeyDecoder[A] = A

  def instance[A](f: String => Option[A]): KeyDecoder[A] = new KeyDecoder[A] {
    final def apply(key: String): Option[A] = f(key)
  }

  private[this] def numberInstance[A](f: String => A): KeyDecoder[A] = new KeyDecoder[A] {
    final def apply(key: String): Option[A] = try Some(f(key)) catch {
      case _: NumberFormatException => None
    }
  }

  implicit val decodeKeyString: KeyDecoder[String] = new KeyDecoder[String] {
    final def apply(key: String): Option[String] = Some(key)
  }

  implicit val decodeKeySymbol: KeyDecoder[Symbol] = new KeyDecoder[Symbol] {
    final def apply(key: String): Option[Symbol] = Some(Symbol(key))
  }

  implicit val decodeKeyUUID: KeyDecoder[UUID] = new KeyDecoder[UUID] {
    final def apply(key: String): Option[UUID] = if (key.length == 36) {
      try Some(UUID.fromString(key)) catch {
        case _: IllegalArgumentException => None
      }
    } else None
  }

  implicit val decodeKeyByte: KeyDecoder[Byte] = numberInstance(_.toByte)
  implicit val decodeKeyShort: KeyDecoder[Short] = numberInstance(_.toShort)
  implicit val decodeKeyInt: KeyDecoder[Int] = numberInstance(_.toInt)
  implicit val decodeKeyLong: KeyDecoder[Long] = numberInstance(_.toLong)

  implicit val keyDecoderInstances: MonadError[KeyDecoder, Unit] = new MonadError[KeyDecoder, Unit] {
    final def pure[A](a: A): KeyDecoder[A] = new KeyDecoder[A] {
      final def apply(key: String): Option[A] = Some(a)
    }

    override final def map[A, B](fa: KeyDecoder[A])(f: A => B): KeyDecoder[B] = fa.map(f)

    final def flatMap[A, B](fa: KeyDecoder[A])(f: A => KeyDecoder[B]): KeyDecoder[B] = fa.flatMap(f)

    final def raiseError[A](e: Unit): KeyDecoder[A] = new KeyDecoder[A] {
      final def apply(key: String): Option[A] = None
    }

    final def handleErrorWith[A](fa: KeyDecoder[A])(f: Unit => KeyDecoder[A]): KeyDecoder[A] = new KeyDecoder[A] {
      final def apply(key: String): Option[A] = f(())(key)
    }

    final def tailRecM[A, B](a: A)(f: A => KeyDecoder[Either[A, B]]): KeyDecoder[B] = new KeyDecoder[B] {
      @tailrec
      private[this] def step(key: String, a1: A): Option[B] = f(a1)(key) match {
        case None => None
        case Some(Left(a2)) => step(key, a2)
        case Some(Right(b)) => Some(b)
      }

      final def apply(key: String): Option[B] = step(key, a)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy