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

enumeratum.values.ValueEnum.scala Maven / Gradle / Ivy

There is a newer version: 1.5.15
Show newest version
package enumeratum.values

import enumeratum.{EnumMacros, ValueEnumMacros}

import scala.collection.immutable._
import scala.language.experimental.macros

/**
  * Base trait for a Value-based enums.
  *
  * Example:
  *
  * {{{
  * scala> sealed abstract class Greeting(val value: Int) extends IntEnumEntry
  *
  * scala> object Greeting extends IntEnum[Greeting] {
  *      |   val values = findValues
  *      |   case object Hello   extends Greeting(1)
  *      |   case object GoodBye extends Greeting(2)
  *      |   case object Hi      extends Greeting(3)
  *      |   case object Bye     extends Greeting(4)
  *      | }
  *
  * scala> Greeting.withValueOpt(1)
  * res0: Option[Greeting] = Some(Hello)
  *
  * scala> Greeting.withValueOpt(6)
  * res1: Option[Greeting] = None
  * }}}
  */
sealed trait ValueEnum[ValueType, EntryType <: ValueEnumEntry[ValueType]] {

  /**
    * Map of [[ValueType]] to [[EntryType]] members
    */
  final lazy val valuesToEntriesMap: Map[ValueType, EntryType] =
    values.map(v => v.value -> v).toMap

  /**
    * The sequence of values for your [[Enum]]. You will typically want
    * to implement this in your extending class as a `val` so that `withValue`
    * and friends are as efficient as possible.
    *
    * Feel free to implement this however you'd like (including messing around with ordering, etc) if that
    * fits your needs better.
    */
  def values: IndexedSeq[EntryType]

  /**
    * Tries to get an [[EntryType]] by the supplied value. The value corresponds to the .value
    * of the case objects implementing [[EntryType]]
    *
    * Like [[Enumeration]]'s `withValue`, this method will throw if the value does not match any of the values'
    * `.value` values.
    */
  @SuppressWarnings(Array("org.wartremover.warts.Throw"))
  def withValue(i: ValueType): EntryType =
    withValueOpt(i).getOrElse(throw new NoSuchElementException(buildNotFoundMessage(i)))

  /**
    * Optionally returns an [[EntryType]] for a given value.
    */
  def withValueOpt(i: ValueType): Option[EntryType] = valuesToEntriesMap.get(i)

  private lazy val existingEntriesString = values.map(_.value).mkString(", ")

  private def buildNotFoundMessage(i: ValueType): String = {
    s"$i is not a member of ValueEnum ($existingEntriesString)"
  }

}

/*
 * For the sake of keeping implementations of ValueEnums constrainted to a subset that we have tested to work relatively well,
 * the following traits are implementations of the sealed trait.
 *
 * There is a bit of repetition in order to supply the findValues method (esp in the comments) because we are using a macro
 * and macro invocations cannot provide implementations for a super class's abstract method
 */

object IntEnum {

  /**
    * Materializes an IntEnum for a given IntEnumEntry
    */
  implicit def materialiseIntValueEnum[EntryType <: IntEnumEntry]: IntEnum[EntryType] =
    macro EnumMacros.materializeEnumImpl[EntryType]

}

/**
  * Value enum with [[IntEnumEntry]] entries
  */
trait IntEnum[A <: IntEnumEntry] extends ValueEnum[Int, A] {

  /**
    * Method that returns a Seq of [[A]] objects that the macro was able to find.
    *
    * You will want to use this in some way to implement your [[values]] method. In fact,
    * if you aren't using this method...why are you even bothering with this lib?
    */
  protected def findValues: IndexedSeq[A] = macro ValueEnumMacros.findIntValueEntriesImpl[A]

}

object LongEnum {

  /**
    * Materializes a LongEnum for an scope LongEnumEntry
    */
  implicit def materialiseLongValueEnum[EntryType <: LongEnumEntry]: LongEnum[EntryType] =
    macro EnumMacros.materializeEnumImpl[EntryType]

}

/**
  * Value enum with [[LongEnumEntry]] entries
  */
trait LongEnum[A <: LongEnumEntry] extends ValueEnum[Long, A] {

  /**
    * Method that returns a Seq of [[A]] objects that the macro was able to find.
    *
    * You will want to use this in some way to implement your [[values]] method. In fact,
    * if you aren't using this method...why are you even bothering with this lib?
    */
  final protected def findValues: IndexedSeq[A] = macro ValueEnumMacros.findLongValueEntriesImpl[A]
}

object ShortEnum {

  /**
    * Materializes a ShortEnum for an in-scope ShortEnumEntry
    */
  implicit def materialiseShortValueEnum[EntryType <: ShortEnumEntry]: ShortEnum[EntryType] =
    macro EnumMacros.materializeEnumImpl[EntryType]

}

/**
  * Value enum with [[ShortEnumEntry]] entries
  */
trait ShortEnum[A <: ShortEnumEntry] extends ValueEnum[Short, A] {

  /**
    * Method that returns a Seq of [[A]] objects that the macro was able to find.
    *
    * You will want to use this in some way to implement your [[values]] method. In fact,
    * if you aren't using this method...why are you even bothering with this lib?
    */
  final protected def findValues: IndexedSeq[A] =
    macro ValueEnumMacros.findShortValueEntriesImpl[A]
}

object StringEnum {

  /**
    * Materializes a StringEnum for an in-scope StringEnumEntry
    */
  implicit def materialiseStringValueEnum[EntryType <: StringEnumEntry]: StringEnum[EntryType] =
    macro EnumMacros.materializeEnumImpl[EntryType]

}

/**
  * Value enum with [[StringEnumEntry]] entries
  *
  * This is similar to [[enumeratum.Enum]], but different in that values must be
  * literal values. This restraint allows us to enforce uniqueness at compile time.
  *
  * Note that uniqueness is only guaranteed if you do not do any runtime string manipulation on values.
  */
trait StringEnum[A <: StringEnumEntry] extends ValueEnum[String, A] {

  /**
    * Method that returns a Seq of [[A]] objects that the macro was able to find.
    *
    * You will want to use this in some way to implement your [[values]] method. In fact,
    * if you aren't using this method...why are you even bothering with this lib?
    */
  final protected def findValues: IndexedSeq[A] =
    macro ValueEnumMacros.findStringValueEntriesImpl[A]
}

object ByteEnum {

  /**
    * Materializes a ByteEnum for an in-scope ByteEnumEntry
    */
  implicit def materialiseByteValueEnum[EntryType <: ByteEnumEntry]: ByteEnum[EntryType] =
    macro EnumMacros.materializeEnumImpl[EntryType]

}

/**
  * Value enum with [[ByteEnumEntry]] entries
  *
  * This is similar to [[enumeratum.Enum]], but different in that values must be
  * literal values. This restraint allows us to enforce uniqueness at compile time.
  *
  * Note that uniqueness is only guaranteed if you do not do any runtime string manipulation on values.
  */
trait ByteEnum[A <: ByteEnumEntry] extends ValueEnum[Byte, A] {

  /**
    * Method that returns a Seq of [[A]] objects that the macro was able to find.
    *
    * You will want to use this in some way to implement your [[values]] method. In fact,
    * if you aren't using this method...why are you even bothering with this lib?
    */
  final protected def findValues: IndexedSeq[A] = macro ValueEnumMacros.findByteValueEntriesImpl[A]
}

object CharEnum {

  /**
    * Materializes a CharEnum for an in-scope CharEnumEntry
    */
  implicit def materialiseCharValueEnum[EntryType <: CharEnumEntry]: CharEnum[EntryType] =
    macro EnumMacros.materializeEnumImpl[EntryType]

}

/**
  * Value enum with [[CharEnumEntry]] entries
  *
  * This is similar to [[enumeratum.Enum]], but different in that values must be
  * literal values. This restraint allows us to enforce uniqueness at compile time.
  *
  * Note that uniqueness is only guaranteed if you do not do any runtime string manipulation on values.
  */
trait CharEnum[A <: CharEnumEntry] extends ValueEnum[Char, A] {

  /**
    * Method that returns a Seq of [[A]] objects that the macro was able to find.
    *
    * You will want to use this in some way to implement your [[values]] method. In fact,
    * if you aren't using this method...why are you even bothering with this lib?
    */
  final protected def findValues: IndexedSeq[A] = macro ValueEnumMacros.findCharValueEntriesImpl[A]
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy