Last active
November 21, 2018 18:32
-
-
Save netanelrabinowitz/7b9619fa68a3ff0da2afbd35698f2b2e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * User: netanelrabinowitz | |
| * Date: 16/12/2017 | |
| * Time: 14:11 | |
| */ | |
| import shapeless._ | |
| import shapeless.ops.hlist | |
| import shapeless.labelled.{field, FieldType} | |
| trait Default[A] { | |
| def default: A | |
| } | |
| object Default { | |
| def pure[A](empty: => A): Default[A] = { | |
| new Default[A] { | |
| override def default: A = empty | |
| } | |
| } | |
| def apply[A](implicit default: Default[A]): Default[A] = default | |
| implicit val intDefault: Default[Int] = pure(0) | |
| implicit val doubleDefault: Default[Double] = pure(0.0) | |
| implicit val strDefault: Default[String] = pure("") | |
| implicit val booleanDefault: Default[Boolean] = pure(false) | |
| implicit def optionDefault[A]: Default[Option[A]] = pure(None) | |
| implicit def listDefault[A]: Default[List[A]] = pure(Nil) | |
| implicit def mapDefault[K, V]: Default[Map[K, V]] = pure(Map.empty) | |
| // product | |
| implicit val hnilDefault: Default[HNil] = | |
| pure(HNil) | |
| implicit def hlistDefault[H, T <: HList]( | |
| implicit | |
| hEncoder: Default[H], | |
| tEncoder: Default[T]): Default[H :: T] = { | |
| pure { | |
| hEncoder.default :: tEncoder.default | |
| } | |
| } | |
| implicit def genericDefault[A, R]( | |
| implicit | |
| gen: Generic.Aux[A, R], | |
| default: Default[R]): Default[A] = { | |
| pure(gen.from(default.default)) | |
| } | |
| } | |
| trait Evo[A, B] { | |
| def apply(a: A): B | |
| } | |
| object Evo { | |
| // simpler version without the use of Diff and the ability to add new fields to newer versions | |
| // implicit def genericEvolution[A, B, ARepr <: HList, BRepr <: HList, Unaligned <: HList]( | |
| // implicit | |
| // aGen : LabelledGeneric.Aux[A, ARepr], | |
| // bGen : LabelledGeneric.Aux[B, BRepr], | |
| // inter : hlist.Intersection.Aux[ARepr, BRepr, Unaligned], | |
| // align : hlist.Align[Unaligned, BRepr] | |
| // ): Evo[A, B] = { | |
| // new Evo[A, B] { | |
| // def apply(a: A): B = bGen.from(align.apply(inter.apply(aGen.to(a)))) | |
| // } | |
| // } | |
| def pure[A](empty: => A): Default[A] = | |
| new Default[A] { | |
| def default: A = empty | |
| } | |
| implicit val hnilDefault: Default[HNil] = | |
| pure[HNil](HNil) | |
| implicit def hlistDefault[K <: Symbol, H, T <: HList]( | |
| implicit | |
| hDefault: Lazy[Default[H]], | |
| tDefault: Default[T]): Default[FieldType[K, H] :: T] = | |
| pure(field[K](hDefault.value.default) :: tDefault.default) | |
| implicit def genericEvolution[ | |
| A, B, ARepr <: HList, BRepr <: HList, | |
| Common <: HList, Added <: HList, Unaligned <: HList]( | |
| implicit | |
| aGen : LabelledGeneric.Aux[A, ARepr], | |
| bGen : LabelledGeneric.Aux[B, BRepr], | |
| inter : hlist.Intersection.Aux[ARepr, BRepr, Common], | |
| diff : hlist.Diff.Aux[BRepr, Common, Added], | |
| default : Default[Added], | |
| prepend : hlist.Prepend.Aux[Added, Common, Unaligned], | |
| align : hlist.Align[Unaligned, BRepr] | |
| ): Evo[A, B] = { | |
| new Evo[A, B] { | |
| def apply(a: A): B = | |
| bGen.from(align(prepend(default.default, inter(aGen.to(a))))) | |
| } | |
| } | |
| implicit class EvoOps[A](a: A) { | |
| def to[B](implicit evolve: Evo[A, B]): B = | |
| evolve.apply(a) | |
| } | |
| } | |
| object Main { | |
| import Evo._ | |
| case class V1(str: String, int: Int, bool: Boolean) | |
| case class V2(bool: Boolean, str: String, double: Double) | |
| def main(args: Array[String]): Unit = { | |
| val v1 = V1("yolo", 3, true) | |
| val v2 = v1.to[V2] | |
| println(v2) // V2(true,yolo, 0.0) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment