Created
September 24, 2015 09:42
-
-
Save Astrac/82370b0794c98eeb99f0 to your computer and use it in GitHub Desktop.
A map from types to values of other types
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
import shapeless._ | |
import shapeless.ops.hlist._ | |
sealed trait SameSize[L1 <: HList, L2 <: HList] | |
object SameSize { | |
def apply[L1 <: HList, L2 <: HList] = new SameSize[L1, L2] {} | |
implicit def hnilHasSameLength = SameSize[HNil, HNil] | |
implicit def hlistHasSameLength[L1 <: HList, L2 <: HList, L1T <: HList, L2T <: HList](implicit | |
l1IsHCons: IsHCons.Aux[L1, _, L1T], | |
l2IsHCons: IsHCons.Aux[L2, _, L2T], | |
recurse: SameSize[L1T, L2T]) = SameSize[L1, L2] | |
} | |
sealed trait IndexOfType[L <: HList, F] { | |
type Out <: Nat | |
} | |
object IndexOfType { | |
type Aux[L <: HList, T, O <: Nat] = IndexOfType[L, T] { type Out = O } | |
def apply[L <: HList, F, O <: Nat] = new IndexOfType[L, F] { type Out = O } | |
implicit def typeIsInTail[L <: HList, T <: HList, F, O <: Nat](implicit | |
isHCons: IsHCons.Aux[L, _, T], | |
findInTail: IndexOfType.Aux[T, F, O]): IndexOfType.Aux[L, F, Succ[O]] = IndexOfType[L, F, Succ[O]] | |
implicit def typeIsHead[L <: HList, H, F](implicit | |
isHCons: IsHCons.Aux[L, H, _], | |
ev: H =:= F): IndexOfType.Aux[L, F, _0] = IndexOfType[L, F, _0] | |
} | |
trait NotContains[L <: HList, F] | |
object NotContains { | |
def apply[L <: HList, F] = new NotContains[L, F] {} | |
implicit def hNilNotContains[F] = NotContains[HNil, F] | |
implicit def hTailNotContains[L <: HList, H, T <: HList, F](implicit | |
isHCons: IsHCons.Aux[L, H, T], | |
isNotH: H =:!= F, | |
isNotInHTail: NotContains[T, F]) = NotContains[L, F] | |
} | |
class TypeMap[KS <: HList, VS <: HList](val values: VS)(implicit sizeEq: SameSize[KS, VS]) { | |
sealed trait Getter[K] { | |
type Out | |
def value: Out | |
} | |
object Getter { | |
type Aux[K, O] = Getter[K] { type Out = O } | |
implicit def instance[K, KI <: Nat, O](implicit | |
kidx: IndexOfType.Aux[KS, K, KI], | |
res: At.Aux[VS, KI, O]): Getter.Aux[K, O] = new Getter[K] { | |
type Out = O | |
val value = res(values) | |
} | |
} | |
final class Setter[K] { | |
def apply[V](value: V)(implicit nc: NotContains[KS, K]) = | |
new TypeMap[K :: KS, V :: VS](value :: values) | |
} | |
final class Replacer[K] { | |
def apply[V, KI <: Nat, O <: HList, OV](v: V)(implicit | |
idx: IndexOfType.Aux[KS, K, KI], | |
old: At.Aux[VS, KI, OV], | |
rep: ReplaceAt.Aux[VS, KI, V, (OV, O)], | |
ss: SameSize[KS, O]) = new TypeMap[KS, O](rep(values, v)._2) | |
} | |
def get[K](implicit g: Getter[K]): g.Out = g.value | |
def set[K] = new Setter[K] | |
def replace[K] = new Replacer[K] | |
} | |
object TypeMap { | |
def empty = new TypeMap[HNil, HNil](HNil) | |
} | |
object Test { | |
val x = TypeMap.empty | |
.set[String](1) | |
.set[Boolean]("Foo") | |
.set[Double](true) | |
.replace[String](1.2) | |
val a: Double = x.get[String] | |
val b: String = x.get[Boolean] | |
val c: Boolean = x.get[Double] | |
// Does not compile | |
// x.get[Int] - No such a key | |
// x.replace[Int](2) - No such a key | |
// x.set[String]('c') - The key is already set | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment