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

cats.kernel.Eq.scala Maven / Gradle / Ivy

The newest version!
package cats.kernel

import java.util.UUID
import scala.collection.immutable.{BitSet, Queue, SortedMap, SortedSet}
import scala.concurrent.duration.{Duration, FiniteDuration}
import scala.math.Equiv
import scala.{specialized => sp}
import scala.util.{Failure, Success, Try}
import compat.scalaVersionSpecific._

/**
 * A type class used to determine equality between 2 instances of the same
 * type. Any 2 instances `x` and `y` are equal if `eqv(x, y)` is `true`.
 * Moreover, `eqv` should form an equivalence relation.
 */
trait Eq[@sp A] extends Any with Serializable { self =>

  /**
   * Returns `true` if `x` and `y` are equivalent, `false` otherwise.
   */
  def eqv(x: A, y: A): Boolean

  /**
   * Returns `false` if `x` and `y` are equivalent, `true` otherwise.
   */
  def neqv(x: A, y: A): Boolean = !eqv(x, y)
}

abstract class EqFunctions[E[T] <: Eq[T]] {
  def eqv[@sp A](x: A, y: A)(implicit ev: E[A]): Boolean =
    ev.eqv(x, y)

  def neqv[@sp A](x: A, y: A)(implicit ev: E[A]): Boolean =
    ev.neqv(x, y)

}

trait EqToEquivConversion {

  /**
   * Implicitly derive a `scala.math.Equiv[A]` from a `Eq[A]`
   * instance.
   */
  implicit def catsKernelEquivForEq[A](implicit ev: Eq[A]): Equiv[A] = new Equiv[A] {
    def equiv(a: A, b: A) = ev.eqv(a, b)
  }
}

@suppressUnusedImportWarningForScalaVersionSpecific
object Eq
    extends EqFunctions[Eq]
    with EqToEquivConversion
    with ScalaVersionSpecificOrderInstances
    with instances.TupleOrderInstances
    with PartialOrderInstances {

  /**
   * Access an implicit `Eq[A]`.
   */
  @inline final def apply[A](implicit ev: Eq[A]): Eq[A] = ev

  /**
   * Convert an implicit `Eq[B]` to an `Eq[A]` using the given
   * function `f`.
   */
  def by[@sp A, @sp B](f: A => B)(implicit ev: Eq[B]): Eq[A] =
    new Eq[A] {
      def eqv(x: A, y: A) = ev.eqv(f(x), f(y))
    }

  /**
   * Return an Eq that gives the result of the and of eq1 and eq2
   * note this is idempotent
   */
  def and[@sp A](eq1: Eq[A], eq2: Eq[A]): Eq[A] =
    new Eq[A] {
      def eqv(x: A, y: A) = eq1.eqv(x, y) && eq2.eqv(x, y)
    }

  /**
   * Return an Eq that gives the result of the or of this and that
   * Note this is idempotent
   */
  def or[@sp A](eq1: Eq[A], eq2: Eq[A]): Eq[A] =
    new Eq[A] {
      def eqv(x: A, y: A) = eq1.eqv(x, y) || eq2.eqv(x, y)
    }

  /**
   * Create an `Eq` instance from an `eqv` implementation.
   */
  def instance[A](f: (A, A) => Boolean): Eq[A] =
    new Eq[A] {
      def eqv(x: A, y: A) = f(x, y)
    }

  /**
   * An `Eq[A]` that delegates to universal equality (`==`).
   *
   * This can be useful for case classes, which have reasonable `equals`
   * implementations
   */
  def fromUniversalEquals[A]: Eq[A] =
    new Eq[A] {
      def eqv(x: A, y: A) = x == y
    }

  /**
   * Everything is the same
   */
  def allEqual[A]: Eq[A] = new Eq[A] {
    def eqv(x: A, y: A) = true
  }

  /**
   * This is a monoid that creates an Eq that
   * checks that all equality checks pass
   */
  def allEqualBoundedSemilattice[A]: BoundedSemilattice[Eq[A]] = new BoundedSemilattice[Eq[A]] {
    def empty = allEqual[A]
    def combine(e1: Eq[A], e2: Eq[A]): Eq[A] = Eq.and(e1, e2)
    override def combineAllOption(es: IterableOnce[Eq[A]]): Option[Eq[A]] =
      if (es.iterator.isEmpty) None
      else {
        val materialized = es.iterator.toVector
        Some(new Eq[A] {
          def eqv(x: A, y: A) = materialized.forall(_.eqv(x, y))
        })
      }
  }

  /**
   * This is a monoid that creates an Eq that
   * checks that at least one equality check passes
   */
  def anyEqualSemilattice[A]: Semilattice[Eq[A]] = new Semilattice[Eq[A]] {
    def combine(e1: Eq[A], e2: Eq[A]): Eq[A] = Eq.or(e1, e2)
    override def combineAllOption(es: IterableOnce[Eq[A]]): Option[Eq[A]] =
      if (es.iterator.isEmpty) None
      else {
        val materialized = es.iterator.toVector
        Some(new Eq[A] {
          def eqv(x: A, y: A) = materialized.exists(_.eqv(x, y))
        })
      }
  }

  implicit def catsKernelInstancesForBitSet: PartialOrder[BitSet] with Hash[BitSet] =
    cats.kernel.instances.bitSet.catsKernelStdOrderForBitSet
  implicit def catsKernelPartialOrderForSet[A]: PartialOrder[Set[A]] =
    cats.kernel.instances.set.catsKernelStdPartialOrderForSet[A]
  implicit def catsKernelOrderForEither[A: Order, B: Order]: Order[Either[A, B]] =
    cats.kernel.instances.either.catsStdOrderForEither[A, B]

  implicit def catsKernelInstancesForUnit: Order[Unit] with Hash[Unit] =
    cats.kernel.instances.unit.catsKernelStdOrderForUnit
  implicit def catsKernelInstancesForBoolean: Order[Boolean] with Hash[Boolean] =
    cats.kernel.instances.boolean.catsKernelStdOrderForBoolean
  implicit def catsKernelInstancesForByte: Order[Byte] with Hash[Byte] =
    cats.kernel.instances.byte.catsKernelStdOrderForByte
  implicit def catsKernelInstancesForShort: Order[Short] with Hash[Short] =
    cats.kernel.instances.short.catsKernelStdOrderForShort
  implicit def catsKernelInstancesForInt: Order[Int] with Hash[Int] = cats.kernel.instances.int.catsKernelStdOrderForInt
  implicit def catsKernelInstancesForLong: Order[Long] with Hash[Long] =
    cats.kernel.instances.long.catsKernelStdOrderForLong
  implicit def catsKernelInstancesForBigInt: Order[BigInt] with Hash[BigInt] =
    cats.kernel.instances.bigInt.catsKernelStdOrderForBigInt
  implicit def catsKernelInstancesForBigDecimal: Order[BigDecimal] with Hash[BigDecimal] =
    cats.kernel.instances.bigDecimal.catsKernelStdOrderForBigDecimal
  implicit def catsKernelInstancesForDuration: Order[Duration] with Hash[Duration] =
    cats.kernel.instances.duration.catsKernelStdOrderForDuration
  implicit def catsKernelInstancesForFiniteDuration: Order[FiniteDuration] with Hash[FiniteDuration] =
    cats.kernel.instances.all.catsKernelStdOrderForFiniteDuration
  implicit def catsKernelInstancesForChar: Order[Char] with Hash[Char] =
    cats.kernel.instances.char.catsKernelStdOrderForChar
  implicit def catsKernelInstancesForSymbol: Order[Symbol] with Hash[Symbol] =
    cats.kernel.instances.symbol.catsKernelStdOrderForSymbol
  implicit def catsKernelInstancesForString: Order[String] with Hash[String] =
    cats.kernel.instances.string.catsKernelStdOrderForString
  implicit def catsKernelInstancesForUUID: Order[UUID] with Hash[UUID] =
    cats.kernel.instances.uuid.catsKernelStdOrderForUUID
  implicit def catsKernelInstancesForDouble: Order[Double] with Hash[Double] =
    cats.kernel.instances.double.catsKernelStdOrderForDouble
  implicit def catsKernelInstancesForFloat: Order[Float] with Hash[Float] =
    cats.kernel.instances.float.catsKernelStdOrderForFloat

  implicit def catsKernelOrderForOption[A: Order]: Order[Option[A]] =
    cats.kernel.instances.option.catsKernelStdOrderForOption[A]
  implicit def catsKernelOrderForList[A: Order]: Order[List[A]] =
    cats.kernel.instances.list.catsKernelStdOrderForList[A]
  implicit def catsKernelOrderForVector[A: Order]: Order[Vector[A]] =
    cats.kernel.instances.vector.catsKernelStdOrderForVector[A]
  implicit def catsKernelOrderForQueue[A: Order]: Order[Queue[A]] =
    cats.kernel.instances.queue.catsKernelStdOrderForQueue[A]
  implicit def catsKernelOrderForSortedSet[A: Order]: Order[SortedSet[A]] =
    cats.kernel.instances.sortedSet.catsKernelStdOrderForSortedSet[A]
  implicit def catsKernelOrderForFunction0[A: Order]: Order[() => A] =
    cats.kernel.instances.function.catsKernelOrderForFunction0[A]

  /**
   * you may wish to do equality by making `implicit val eqT: Eq[Throwable] = Eq.allEqual`
   * doing a fine grained equality on Throwable can make the code very execution
   * order dependent
   */
  implicit def catsStdEqForTry[A, T](implicit A: Eq[A], T: Eq[Throwable]): Eq[Try[A]] =
    new Eq[Try[A]] {
      def eqv(x: Try[A], y: Try[A]): Boolean = (x, y) match {
        case (Success(a), Success(b)) => A.eqv(a, b)
        case (Failure(a), Failure(b)) => T.eqv(a, b)
        case _                        => false
      }
    }
}

private[kernel] trait PartialOrderInstances extends HashInstances {
  implicit def catsKernelPartialOrderForOption[A: PartialOrder]: PartialOrder[Option[A]] =
    cats.kernel.instances.option.catsKernelStdPartialOrderForOption[A]
  implicit def catsKernelPartialOrderForList[A: PartialOrder]: PartialOrder[List[A]] =
    cats.kernel.instances.list.catsKernelStdPartialOrderForList[A]
  implicit def catsKernelPartialOrderForVector[A: PartialOrder]: PartialOrder[Vector[A]] =
    cats.kernel.instances.vector.catsKernelStdPartialOrderForVector[A]
  implicit def catsKernelPartialOrderForQueue[A: PartialOrder]: PartialOrder[Queue[A]] =
    cats.kernel.instances.queue.catsKernelStdPartialOrderForQueue[A]
  implicit def catsKernelPartialOrderForFunction0[A: PartialOrder]: PartialOrder[() => A] =
    cats.kernel.instances.function.catsKernelPartialOrderForFunction0[A]
}

private[kernel] trait HashInstances extends EqInstances {
  implicit def catsKernelHashForSet[A]: Hash[Set[A]] = cats.kernel.instances.set.catsKernelStdHashForSet[A]
  implicit def catsKernelHashForOption[A: Hash]: Hash[Option[A]] =
    cats.kernel.instances.option.catsKernelStdHashForOption[A]
  implicit def catsKernelHashForList[A: Hash]: Hash[List[A]] = cats.kernel.instances.list.catsKernelStdHashForList[A]
  implicit def catsKernelHashForVector[A: Hash]: Hash[Vector[A]] =
    cats.kernel.instances.vector.catsKernelStdHashForVector[A]
  implicit def catsKernelHashForQueue[A: Hash]: Hash[Queue[A]] =
    cats.kernel.instances.queue.catsKernelStdHashForQueue[A]
  implicit def catsKernelHashForSortedSet[A: Order: Hash]: Hash[SortedSet[A]] =
    cats.kernel.instances.sortedSet.catsKernelStdHashForSortedSet[A]
  implicit def catsKernelHashForFunction0[A: Hash]: Hash[() => A] =
    cats.kernel.instances.function.catsKernelHashForFunction0[A]
  implicit def catsKernelHashForMap[K: Hash, V: Hash]: Hash[Map[K, V]] =
    cats.kernel.instances.map.catsKernelStdHashForMap[K, V]
  implicit def catsKernelHashForSortedMap[K: Order: Hash, V: Hash]: Hash[SortedMap[K, V]] =
    cats.kernel.instances.sortedMap.catsKernelStdHashForSortedMap[K, V]
  implicit def catsKernelHashForEither[A: Hash, B: Hash]: Hash[Either[A, B]] =
    cats.kernel.instances.either.catsStdHashForEither[A, B]
}

private[kernel] trait EqInstances {
  implicit def catsKernelEqForOption[A: Eq]: Eq[Option[A]] = cats.kernel.instances.option.catsKernelStdEqForOption[A]
  implicit def catsKernelEqForList[A: Eq]: Eq[List[A]] = cats.kernel.instances.list.catsKernelStdEqForList[A]
  implicit def catsKernelEqForVector[A: Eq]: Eq[Vector[A]] = cats.kernel.instances.vector.catsKernelStdEqForVector[A]
  implicit def catsKernelEqForQueue[A: Eq]: Eq[Queue[A]] = cats.kernel.instances.queue.catsKernelStdEqForQueue[A]
  implicit def catsKernelEqForFunction0[A: Eq]: Eq[() => A] = cats.kernel.instances.function.catsKernelEqForFunction0[A]
  implicit def catsKernelEqForMap[K, V: Eq]: Eq[Map[K, V]] = cats.kernel.instances.map.catsKernelStdEqForMap[K, V]
  implicit def catsKernelEqForSortedMap[K: Order, V: Eq]: Eq[SortedMap[K, V]] =
    cats.kernel.instances.sortedMap.catsKernelStdEqForSortedMap[K, V]
  implicit def catsKernelEqForEither[A: Eq, B: Eq]: Eq[Either[A, B]] =
    cats.kernel.instances.either.catsStdEqForEither[A, B]
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy