package shapeless
package ops
package record {
import shapeless.record._
@annotation.implicitNotFound(msg = "No field ${K} in record ${L}")
trait Selector[L <: HList, K] {
type Out
def apply(l : L): Out
}
trait LowPrioritySelector {
type Aux[L <: HList, K, Out0] = Selector[L, K] { type Out = Out0 }
implicit def hlistSelect[H, T <: HList, K]
(implicit st : Selector[T, K]): Aux[H :: T, K, st.Out] =
new Selector[H :: T, K] {
type Out = st.Out
def apply(l : H :: T): Out = st(l.tail)
}
}
object Selector extends LowPrioritySelector {
implicit def hlistSelect1[K, V, T <: HList]: Aux[FieldType[K, V] :: T, K, V] =
new Selector[FieldType[K, V] :: T, K] {
type Out = V
def apply(l : FieldType[K, V] :: T): Out = l.head
}
}
trait Updater[L <: HList, F] extends DepFn2[L, F] { type Out <: HList }
trait LowPriorityUpdater {
type Aux[L <: HList, F, Out0 <: HList] = Updater[L, F] { type Out = Out0 }
implicit def hlistUpdater1[H, T <: HList, K, V]
(implicit ut : Updater[T, FieldType[K, V]]): Aux[H :: T, FieldType[K, V], H :: ut.Out] =
new Updater[H :: T, FieldType[K, V]] {
type Out = H :: ut.Out
def apply(l: H :: T, f: FieldType[K, V]): Out = l.head :: ut(l.tail, f)
}
}
object Updater extends LowPriorityUpdater {
implicit def hnilUpdater[L <: HNil, F]: Aux[L, F, F :: HNil] =
new Updater[L, F] {
type Out = F :: HNil
def apply(l: L, f: F): Out = f :: HNil
}
implicit def hlistUpdater2[K, V, T <: HList]: Aux[FieldType[K, V] :: T, FieldType[K, V], FieldType[K, V] :: T] =
new Updater[FieldType[K, V] :: T, FieldType[K, V]] {
type Out = FieldType[K, V] :: T
def apply(l: FieldType[K, V] :: T, f: FieldType[K, V]): Out = f :: l.tail
}
}
@annotation.implicitNotFound(msg = "No field ${F} with value of type ${A} in record ${L}")
trait Modifier[L <: HList, F, A, B] extends DepFn2[L, A => B] { type Out <: HList }
object Modifier {
type Aux[L <: HList, F, A, B, Out0 <: HList] = Modifier[L, F, A, B] { type Out = Out0 }
implicit def hlistModify1[F, A, B, T <: HList]: Aux[FieldType[F, A] :: T, F, A, B, FieldType[F, B] :: T] =
new Modifier[FieldType[F, A] :: T, F, A, B] {
type Out = FieldType[F, B] :: T
def apply(l: FieldType[F, A] :: T, f: A => B): Out = field[F](f(l.head)) :: l.tail
}
implicit def hlistModify[H, T <: HList, F, A, B]
(implicit mt: Modifier[T, F, A, B]): Aux[H :: T, F, A, B, H :: mt.Out] =
new Modifier[H :: T, F, A, B] {
type Out = H :: mt.Out
def apply(l: H :: T, f: A => B): Out = l.head :: mt(l.tail, f)
}
}
@annotation.implicitNotFound(msg = "No field ${K} in record ${L}")
trait Remover[L <: HList, K] extends DepFn1[L]
trait LowPriorityRemover {
type Aux[L <: HList, K, Out0] = Remover[L, K] { type Out = Out0 }
implicit def hlistRemove[H, T <: HList, K, V, OutT <: HList]
(implicit rt: Aux[T, K, (V, OutT)]): Aux[H :: T, K, (V, H :: OutT)] =
new Remover[H :: T, K] {
type Out = (V, H :: OutT)
def apply(l : H :: T): Out = {
val (v, tail) = rt(l.tail)
(v, l.head :: tail)
}
}
}
object Remover extends LowPriorityRemover {
implicit def hlistRemove1[K, V, T <: HList]: Aux[FieldType[K, V] :: T, K, (V, T)] =
new Remover[FieldType[K, V] :: T, K] {
type Out = (V, T)
def apply(l: FieldType[K, V] :: T): Out = (l.head, l.tail)
}
}
@annotation.implicitNotFound(msg = "No field ${K1} in record ${L}")
trait Renamer[L <: HList, K1, K2] extends DepFn1[L] { type Out <: HList }
object Renamer {
type Aux[L <: HList, K1, K2, Out0 <: HList] = Renamer[L, K1, K2] { type Out = Out0 }
implicit def hlistRenamer1[T <: HList, K1, K2, V]: Aux[FieldType[K1, V] :: T, K1, K2, FieldType[K2, V] :: T] =
new Renamer[FieldType[K1, V] :: T, K1, K2] {
type Out = FieldType[K2, V] :: T
def apply(l: FieldType[K1, V] :: T): Out = field[K2](l.head : V) :: l.tail
}
implicit def hlistRenamer[H, T <: HList, K1, K2, V]
(implicit rn: Renamer[T, K1, K2]): Aux[H :: T, K1, K2, H :: rn.Out] =
new Renamer[H :: T, K1, K2] {
type Out = H :: rn.Out
def apply(l: H :: T): Out = l.head :: rn(l.tail)
}
}
trait Keys[L <: HList] extends DepFn0 { type Out <: HList }
object Keys {
type Aux[L <: HList, Out0 <: HList] = Keys[L] { type Out = Out0 }
implicit def hnilKeys[L <: HNil]: Aux[L, HNil] =
new Keys[L] {
type Out = HNil
def apply(): Out = HNil
}
implicit def hlistKeys[K, V, T <: HList](implicit wk: Witness.Aux[K], kt: Keys[T]): Aux[FieldType[K, V] :: T, K :: kt.Out] =
new Keys[FieldType[K, V] :: T] {
type Out = K :: kt.Out
def apply(): Out = wk.value :: kt()
}
}
trait Values[L <: HList] extends DepFn1[L] { type Out <: HList }
object Values {
type Aux[L <: HList, Out0 <: HList] = Values[L] { type Out = Out0 }
implicit def hnilValues[L <: HNil]: Aux[L, HNil] =
new Values[L] {
type Out = HNil
def apply(l: L): Out = HNil
}
implicit def hlistValues[K, V, T <: HList](implicit vt: Values[T]): Aux[FieldType[K, V] :: T, V :: vt.Out] =
new Values[FieldType[K, V] :: T] {
type Out = V :: vt.Out
def apply(l: FieldType[K, V] :: T): Out = (l.head: V) :: vt(l.tail)
}
}
}