I have a sealed trait/abstract class hierarchy and need to convert its subtypes to strings and these strings back to the types. This code example describes what I want to achieve:
import shapeless._
object Test extends App {
sealed abstract class C(val i: Int)
case object O1 extends C(1)
case object O2 extends C(2)
// lots of other implementations
trait TC[A] {
def f: String
}
implicit object TC1 extends TC[O1.type] {
def f = "O1"
}
implicit object TC2 extends TC[O2.type] {
def f = "O2"
}
object fqn {
val o1 = implicitly[TC[O1.type]].f
val o2 = implicitly[TC[O2.type]].f
def asString(c: C): String = c match {
case O1 ⇒ o1
case O2 ⇒ o2
}
def fromString(s: String): C = s match {
case `o1` ⇒ O1
case `o2` ⇒ O2
}
}
object asString extends Poly1 {
private implicit def impl[A <: C : TC] = at[A](a ⇒ implicitly[TC[A]].f)
def apply(c: C): String = Generic[C].to(c).map(this).unify
}
object fromString {
def apply(s: String): C = ???
}
// This works as expected
println(O1 eq fqn.fromString(fqn.asString(O1)))
println(O2 eq fqn.fromString(fqn.asString(O2)))
// Does not yet work
println(O1 eq fromString(asString(O1)))
println(O2 eq fromString(asString(O2)))
}
Right now, everything works fine with the functionality in fqn
, but it is cumbersome and difficult to maintain for more subtypes of C
. With shapeless I managed to get away with the asString
part but I'm stuck in finding a solution for the fromString
part.
Can anyone think of a way in shapeless (or another library) to implement the fromString
part?
Some more details about my example:
TC
is provided by a library, I can't change it. The typeclasses are generated by macros in this library, therefore the TCN type classes don't directly exist.- I can't easily provide a macro that generates the implementation of
fqn.asString
andfqn.fromString
, therefore I'm looking for a library that already supports this behavior.