Search code examples
scalaenumsshapelessscala-macroshlist

Scala Enumeration to HList with shapeless


Supposing there is a regular Scala Enumeration object, something like

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}

Is it possible to transform it to shapeless HList without explicitly specifying full HList's type signature? I have come across ProductArgs which almost what I need, but it still needs to be fed each enum value as separate arguments. At the same time compiler does know the type and the size of enums collection so it must be possible.


Solution

  • Try

    import shapeless.HList
    import scala.language.experimental.macros
    import scala.reflect.macros.whitebox
    
    object Macros {
      object WeekDay extends Enumeration {
        type WeekDay = Value
        val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
      }
    
      trait ToHList {
        type T <: HList
      }
    
      def toHList(enum: Enumeration): ToHList = macro impl
    
      def impl(c: whitebox.Context)(enum: c.Tree): c.Tree = {
        import c.universe._
        val enum1 = c.eval(c.Expr[Enumeration](c.untypecheck(enum)))
        val valueNames = enum1.values.toList.map(_.toString)
        val tpe = valueNames.foldLeft[c.Tree](tq"shapeless.HNil")(
          (acc, v) => tq"shapeless.::[$enum.${TermName(v)}.type, $acc]"
        )
        q"new Macros.ToHList { type T = $tpe }"
      }
    }
    
    import Macros._
    import shapeless.ops.hlist.Reify
    val tohlist = toHList(WeekDay)
    Reify[tohlist.T].apply() // Sun :: Sat :: Fri :: Thu :: Wed :: Tue :: Mon :: HNil