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

com.bryghts.enumeration.Enum.scala Maven / Gradle / Ivy

There is a newer version: 0.1.52
Show newest version
package com.bryghts.enumeration

import scala.language.experimental.macros

sealed trait EnumMetadata[T] {
    val typeName: String
    def values: Set[T]
    def apply(name: String): Option[T]
}

/**
 * Created by Marc Esquerrà on 31/05/2014.
 */
abstract class Enum[E](implicit em: EnumMetadata[E]) {

    val typeName = em.typeName
    def values:Set[E] = em.values
    def apply(name: String):Option[E] = em.apply(name)

}

object EnumMetadata {

    implicit def enumMetadataForEnum[T]: EnumMetadata[T] =
        macro enumMetadataForEnumImp[T]

    def enumMetadataForEnumImp[T](c: helpers.Context)(implicit tt: c.WeakTypeTag[T]): c.Expr[EnumMetadata[T]] = {
        import c.universe._

        val name: String = tt.tpe.typeSymbol.name.decodedName.toString
        val vs = {

            val companion = tt.tpe.typeSymbol.companionSymbol//helpers.companion(cls)

            def allSubclasses(in: ClassSymbol):List[ClassSymbol] =
                in :: in.knownDirectSubclasses.toList.map{_.asClass}.flatMap{allSubclasses(_)}

            def allInstances(mod: ModuleSymbol): Set[Symbol] =
                mod.moduleClass.asClass.asType.toType.members.sorted.toSet
                    .flatMap{ i : Symbol => i match {
                        case instance if instance.isModule && (instance.asModule.moduleClass.asType.toType weak_<:< tt.tpe) => Set(instance)
                        case m if m.isModule => allInstances(m.asModule)
                        case _ => Set.empty[Symbol]
                    }}


            val instances = (allInstances(companion.asModule).map{s =>
                q"$s"
            }).toList
            q"Set(..$instances)"
        }

        val tmp = q"""
            new AbstractEnumMetadata[$tt] {
                override val typeName: String =
                    $name

                lazy val values: Set[$tt] =
                    $vs
            }
        """
        c.Expr[com.bryghts.enumeration.EnumMetadata[T]](tmp)
    }

}

abstract class AbstractEnumMetadata[T] extends EnumMetadata[T] {
    private val valuesByName: Map[String, T] = values.map(v => (v.toString.toLowerCase, v)).toMap

    override def values:Set[T]

    override def apply(name: String):Option[T] = Option(name.trim.toLowerCase()).flatMap(valuesByName.get _)
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy