Skip to content

Instantly share code, notes, and snippets.

@vaclavsvejcar
Created October 8, 2019 11:09
Show Gist options
  • Save vaclavsvejcar/dbddce8fa8dfbca0dba6eddc3c5b39bc to your computer and use it in GitHub Desktop.
Save vaclavsvejcar/dbddce8fa8dfbca0dba6eddc3c5b39bc to your computer and use it in GitHub Desktop.
import shapeless._
import scala.annotation.implicitNotFound
/*
* Used type names:
* - A = type of the sealed trait
* - C = type of the coproduct
* - H = type of the iterated singleton (case object) instance
* - T = type of the iterated coproduct
*/
trait AllSingletons[A, C <: Coproduct] {
def values: List[A]
}
object AllSingletons {
implicit def cnilSingletons[A]: AllSingletons[A, CNil] = new AllSingletons[A, CNil] {
def values: Nil.type = Nil
}
implicit def coproductSingletons[A, H <: A, T <: Coproduct](
implicit tail: AllSingletons[A, T],
witness: Witness.Aux[H]): AllSingletons[A, H :+: T] = new AllSingletons[A, H :+: T] {
def values: List[A] = witness.value :: tail.values
}
}
@implicitNotFound(
"Cannot enumerate the ${A} sealed trait. Make sure only case objects extends this trait.")
trait EnumCoproduct[A] {
/**
* Returns all ''case object'' instances for the given ''sealed trait''. If any ''case class''
* extends this sealed trait, this call will end up with compile error.
*
* @return set of case objects extending sealed trait
*/
def values: Set[A]
}
/**
* Utilities allowing to enumerate the case objects of the sealed trait.
*/
object EnumCoproduct {
implicit def fromAllSingletons[A, C <: Coproduct](
implicit gen: Generic.Aux[A, C],
singletons: AllSingletons[A, C]): EnumCoproduct[A] = new EnumCoproduct[A] {
def values: Set[A] = singletons.values.toSet
}
def apply[A](implicit instance: EnumCoproduct[A]): EnumCoproduct[A] = instance
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment