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

io.kinoplan.utils.nullable.Nullable.scala Maven / Gradle / Ivy

The newest version!
package io.kinoplan.utils.nullable

/** Option-like data type that distinguishes null values from absent ones. */
sealed trait Nullable[+A] extends Product with Serializable {
  import Nullable._

  def fold[B](ifNull: => B, ifAbsent: => B, ifPresent: A => B): B = this match {
    case Null       => ifNull
    case Absent     => ifAbsent
    case NonNull(a) => ifPresent(a)
  }

  /** Fold if non-Absent. */
  def foldPresent[B](ifPresent: Option[A] => B): Option[B] =
    fold(Some(ifPresent(None)), None, a => Some(ifPresent(Some(a))))

  def exists(p: A => Boolean): Boolean = fold(false, false, a => p(a))
  def map[B](f: A => B): Nullable[B] = fold(Null, Absent, a => NonNull(f(a)))
  def flatMap[B](f: A => Nullable[B]): Nullable[B] = fold(Null, Absent, f)
  def orElse[B >: A](nb: Nullable[B]): Nullable[B] = fold(nb, nb, NonNull(_))
  def toOption: Option[A] = fold(None, None, Some(_))

  def toOptionOption: Option[Option[A]] = fold(Some(None), None, a => Some(Some(a)))

  def isNull: Boolean = fold(ifNull = true, ifAbsent = false, _ => false)

  def isAbsent: Boolean = fold(ifNull = false, ifAbsent = true, _ => false)

  def isPresent: Boolean = fold(ifNull = false, ifAbsent = false, _ => true)

}

object Nullable {

  case object Null extends Nullable[Nothing]
  case object Absent extends Nullable[Nothing]
  case class NonNull[A](value: A) extends Nullable[A]

  def orNull[A](o: Option[A]): Nullable[A] = o.fold(Null: Nullable[A])(NonNull(_))

  def orAbsent[A](o: Option[A]): Nullable[A] = o.fold(Absent: Nullable[A])(NonNull(_))

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy