I have the following classes;
trait Part
case class Part1() extends Part
case class Part2() extends Part
case class Part3(part1: Part1, part2: Part2) extends Part
case class Part4(part1: Part1, part2: Option[Part2], part3: List[Part3]) extends Part
case class Part5(name: String, part4: Part4) extends Part
I classify Part1
and Part2
as simple parts and, Part3
and Part4
as 'grouped parts' because they consist of only other parts or some effect of other parts.
I want to be able to convert grouped parts to list of parts and vice-versa. But I want to do this using only two methods. One for grouped part to list and one for list to grouped part because I have hundreds of classes that extend Part
and I don't want to write a method to all of them.
I managed to do the conversion of grouped part to list as follows;
type IsParts[x] <: Boolean = x match {
case Part => true
case List[Part] => true
case Option[Part] => true
case _ => false
}
def getParts[T <: Product](p: T)
(using
mirror: Mirror.ProductOf[T],
ev: Tuple.Filter[mirror.MirroredElemTypes, IsParts] =:= mirror.MirroredElemTypes) : List[Part] = {
p.productIterator.toList.flatMap{e => e match {
case p: Part => List(p)
case ps: List[Part] => ps
case op: Option[Part] => op.map(p => List(p)).getOrElse(List())
}}.asInstanceOf[List[Part]]
}
and it works as expected
val p1 = Part1()
val p2 = Part2()
val p3 = Part3(p1, p2)
val p4 = Part4(p1, None, List(p3))
val p5 = Part5("part 5", p4)
@main def hello: Unit =
println(s"Part1 : ${getParts(p1)}") // Part1 : List()
println(s"Part2 : ${getParts(p2)}") // Part2 : List()
println(s"Part3 : ${getParts(p3)}") // Part3 : List(Part1(), Part2())
println(s"Part4 : ${getParts(p4)}") // Part4 : List(Part1(), Part3(Part1(),Part2()))
// getParts(p5) // does not compile as expected.
How can I convert a list of parts to a grouped part? (Ignoring the fact that a function from list of parts to a grouped part is partial.)
Codewise I'm asking the implementation of something similar to this:
def toGroupedPart[T <: Part](parts: List[Part])
(using
mirror: Mirror.ProductOf[T],
ev: Tuple.Filter[mirror.MirroredElemTypes, IsParts] =:= mirror.MirroredElemTypes): T = ???
and I would use it like;
toGroupedPart[Part4](myPartList) // returns Part4
// toGroupedPart[Part5](myPartList) // does not compile because Part5 is not a grouped part.
Scastie for the working part.