blob: 9f5c0fafd743d4fdcc7c8717f3d94b81284cc2c4 [file] [log] [blame] [raw]
package li.cil.oc.util
import scala.annotation.tailrec
/**
* https://gist.github.com/viktorklang/1057513
*/
trait ScalaEnum {
import java.util.concurrent.atomic.AtomicReference //Concurrency paranoia
type EnumVal <: Value //This is a type that needs to be found in the implementing class
private val _values = new AtomicReference(Vector[EnumVal]()) //Stores our enum values
//Adds an EnumVal to our storage, uses CCAS to make sure it's thread safe, returns the ordinal
@tailrec private final def addEnumVal(newVal: EnumVal): Int = {
import _values.{get, compareAndSet => CAS}
val oldVec = get
val newVec = oldVec :+ newVal
if ((get eq oldVec) && CAS(oldVec, newVec))
newVec.indexWhere(_ eq newVal)
else
addEnumVal(newVal)
}
def values: Vector[EnumVal] = _values.get //Here you can get all the enums that exist for this type
//This is the trait that we need to extend our EnumVal type with, it does the book-keeping for us
protected trait Value { self: EnumVal => //Enforce that no one mixes in Value in a non-EnumVal type
final val ordinal = addEnumVal(this) //Adds the EnumVal and returns the ordinal
def name: String //All enum values should have a name
override def toString = name //And that name is used for the toString operation
override def equals(other: Any) = this eq other.asInstanceOf[AnyRef]
override def hashCode = 31 * (this.getClass.## + name.## + ordinal)
}
}