Skip to content

Instantly share code, notes, and snippets.

@psttf
Created December 23, 2014 13:49
Show Gist options
  • Save psttf/a5bcaebd7a0ba196fee4 to your computer and use it in GitHub Desktop.
Save psttf/a5bcaebd7a0ba196fee4 to your computer and use it in GitHub Desktop.
Projection of one shapeless extensive record to another. Results in a record that contains the same fields in the same order. Possibilities of mapping different case classes (via LabelledGeneric) are also included.
import shapeless._
import shapeless.ops.hlist.Tupler
import syntax.singleton._
import record._
object o {
trait Projection[F <: HList, L <: HList] extends DepFn1[L] { type Out <: HList}
object Projection{
implicit def hnil[L <: HList] = new Projection[HNil, L]{
override type Out = HNil
override def apply(t: L) = HNil
}
implicit def projectHead[FH, FT <: HList, L <: HList, O](implicit
projectTail: Projection[FT, L],
sel: ops.record.Selector[L, FH]
) = new Projection[FieldType[FH, O] :: FT, L] {
override type Out = sel.Out :: projectTail.Out
override def apply(l: L) = sel(l) :: projectTail(l)
}
def record[F <: HList, L <: HList, T](
gen: LabelledGeneric[T]{ type Repr = F }, l: L
)(implicit projector: o.Projection[F, L]): projector.Out = projector(l)
def apply[F <: HList, L <: HList, T, P, R <: HList](
l: L, p: P => T
)(implicit
gen: LabelledGeneric[T]{ type Repr = F },
projector: o.Projection[F, L] { type Out = R },
tupler: Tupler.Aux[R, P]
): T = {
val record = projector(l)
p(tupler(record))
}
def apply[A, F <: HList, L <: HList, T, P, R <: HList](
a: A, p: P => T
)(implicit
genA: LabelledGeneric[A]{ type Repr = L },
genB: LabelledGeneric[T]{ type Repr = F },
projector: o.Projection[F, L] { type Out = R },
tupler: Tupler.Aux[R, P]
): T = {
val record = projector(genA to a)
p(tupler(record))
}
}
}
case class A(z: Boolean, y: String, x: Int)
case class B(y: String, z: Boolean, q: String)
case class C(y: String, r:Int, z: Boolean, q: String)
val a = A(true, "qwe", 1)
val b = B("qwe", true, "rty")
o.Projection(LabelledGeneric[A].to(a) + ('q ->> "abc"), B.tupled)
o.Projection(C("sss", 3, false, "kkk"), B.tupled)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment