shapeless.ops.coproduct.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2013-15 Miles Sabin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package shapeless
package ops
import poly._
import annotation.implicitNotFound
object coproduct {
trait Inject[C <: Coproduct, I] extends Serializable {
def apply(i: I): C
}
object Inject {
def apply[C <: Coproduct, I](implicit inject: Inject[C, I]): Inject[C, I] = inject
implicit def tlInject[H, T <: Coproduct, I](implicit tlInj : Inject[T, I]): Inject[H :+: T, I] = new Inject[H :+: T, I] {
def apply(i: I): H :+: T = Inr(tlInj(i))
}
implicit def hdInject[H, T <: Coproduct]: Inject[H :+: T, H] = new Inject[H :+: T, H] {
def apply(i: H): H :+: T = Inl(i)
}
}
trait Selector[C <: Coproduct, T] extends Serializable {
def apply(c: C): Option[T]
}
object Selector {
def apply[C <: Coproduct, T](implicit select: Selector[C, T]): Selector[C, T] = select
implicit def hdSelector[H, T <: Coproduct]: Selector[H :+: T, H] = new Selector[H :+: T, H] {
def apply(c: H :+: T): Option[H] = c match {
case Inl(h) => Some(h)
case Inr(t) => None
}
}
implicit def tlSelector[H, T <: Coproduct, S](implicit st: Selector[T, S]): Selector[H :+: T, S] = new Selector[H :+: T, S] {
def apply(c: H :+: T): Option[S] = c match {
case Inl(h) => None
case Inr(t) => st(t)
}
}
}
trait At[C <: Coproduct, N <: Nat] extends DepFn1[C] with Serializable {
type A
type Out = Option[A]
}
object At {
def apply[C <: Coproduct, N <: Nat](implicit at: At[C, N]): Aux[C, N, at.A] = at
type Aux[C <: Coproduct, N <: Nat, A0] = At[C, N] { type A = A0 }
implicit def coproductAt0[H, T <: Coproduct]: Aux[H :+: T, Nat._0, H] = new At[H :+: T, Nat._0] {
type A = H
def apply(c: H :+: T): Out = c match {
case Inl(h) => Some(h)
case _ => None
}
}
implicit def coproductAtN[H, T <: Coproduct, N <: Nat](
implicit att: At[T, N]
): Aux[H :+: T, Succ[N], att.A] = new At[H :+: T, Succ[N]] {
type A = att.A
def apply(c: H :+: T): Out = c match {
case Inl(_) => None
case Inr(tail) => att(tail)
}
}
}
trait Partition[C <: Coproduct, U] extends DepFn1[C] with Serializable {
type Prefix <: Coproduct
type Suffix <: Coproduct
type Out = Either[Prefix, Suffix]
def filter(c: C): Option[Prefix] = apply(c).left.toOption
def filterNot(c: C): Option[Suffix] = apply(c).right.toOption
def apply(c: C): Out = toEither(coproduct(c))
def coproduct(c: C): Prefix :+: Suffix :+: CNil
}
object Partition {
def apply[C <: Coproduct, U]
(implicit partition: Partition[C, U]): Aux[C, U, partition.Prefix, partition.Suffix] = partition
type Aux[C <: Coproduct, U, Prefix0 <: Coproduct, Suffix0 <: Coproduct] = Partition[C, U] {
type Prefix = Prefix0
type Suffix = Suffix0
}
implicit def cnilPartition[U]: Aux[CNil, U, CNil, CNil] = new Partition[CNil, U] {
type Prefix = CNil
type Suffix = CNil
def coproduct(c: CNil): Prefix :+: Suffix :+: CNil = Inr(Inr(c))
}
implicit def coproductPartition_Match[H, T <: Coproduct, TPrefix <: Coproduct, TSuffix <: Coproduct](
implicit partition: Aux[T, H, TPrefix, TSuffix]
): Aux[H :+: T, H, H :+: TPrefix, TSuffix] = new Partition[H :+: T, H] {
type Prefix = H :+: TPrefix
type Suffix = TSuffix
def coproduct(c: H :+: T): Prefix :+: Suffix :+: CNil = c match {
case Inl(h) => Inl(Inl(h))
case Inr(t) => partition.coproduct(t) match {
case Inl(h) => Inl(Inr(h))
case Inr(t) => Inr(t)
}
}
}
implicit def coproductPartition_NonMatch[H, T <: Coproduct, TPrefix <: Coproduct, TSuffix <: Coproduct, U](
implicit partition: Aux[T, U, TPrefix, TSuffix], e: U =:!= H
): Aux[H :+: T, U, TPrefix, H :+: TSuffix] = new Partition[H :+: T, U] {
type Prefix = TPrefix
type Suffix = H :+: TSuffix
def coproduct(c: H :+: T): Prefix :+: Suffix :+: CNil = c match {
case Inl(h) => Inr(Inl(Inl(h)))
case Inr(t) => partition.coproduct(t) match {
case Inl(h) => Inl(h)
case Inr(Inl(t)) => Inr(Inl(Inr(t)))
case Inr(Inr(c)) => Inr(Inr(c))
}
}
}
}
trait Filter[C <: Coproduct, U] extends DepFn1[C] with Serializable {
type A <: Coproduct
type Out = Option[A]
}
object Filter {
def apply[C <: Coproduct, U](implicit filter: Filter[C, U]): Aux[C, U, filter.A] = filter
type Aux[C <: Coproduct, U, A0 <: Coproduct] = Filter[C, U] { type A = A0 }
implicit def coproductFilter[C <: Coproduct, U, CPrefix <: Coproduct, CSuffix <: Coproduct](
implicit partition: Partition.Aux[C, U, CPrefix, CSuffix]
): Aux[C, U, CPrefix] = new Filter[C, U] {
type A = CPrefix
def apply(c: C): Out = partition.filter(c)
}
}
trait FilterNot[C <: Coproduct, U] extends DepFn1[C] with Serializable {
type A <: Coproduct
type Out = Option[A]
}
object FilterNot {
def apply[C <: Coproduct, U](implicit filterNot: FilterNot[C, U]): Aux[C, U, filterNot.A] = filterNot
type Aux[C <: Coproduct, U, A0 <: Coproduct] = FilterNot[C, U] { type A = A0 }
implicit def coproductFilterNot[C <: Coproduct, U, CPrefix <: Coproduct, CSuffix <: Coproduct](
implicit partition: Partition.Aux[C, U, CPrefix, CSuffix]
): Aux[C, U, CSuffix] = new FilterNot[C, U] {
type A = CSuffix
def apply(c: C): Out = partition.filterNot(c)
}
}
trait Remove[C <: Coproduct, U] extends DepFn1[C] with Serializable {
type Rest <: Coproduct
type Out = Either[U, Rest]
def inverse(r: Either[U, Rest]): C
def coproduct(c: C): U :+: Rest = apply(c) match {
case Left(u) => Inl(u)
case Right(r) => Inr(r)
}
}
trait LowPriorityRemove {
type Aux[C <: Coproduct, U, Rest0 <: Coproduct] = Remove[C, U] { type Rest = Rest0 }
// Must be given a lower priority than removeHead, so that:
// - the two don't collide for coproducts with repeated types
// - the first element of type I in C is removed
implicit def removeTail[H, T <: Coproduct, U](implicit
tailRemove: Remove[T, U]
): Aux[H :+: T, U, H :+: tailRemove.Rest] = new Remove[H :+: T, U] {
type Rest = H :+: tailRemove.Rest
def apply(c: H :+: T) = c match {
case Inl(h) => Right(Inl(h))
case Inr(t) => tailRemove(t) match {
case Left(i) => Left(i)
case Right(r) => Right(Inr(r))
}
}
def inverse(r: Either[U, H :+: tailRemove.Rest]) = r match {
case Left(i) => Inr(tailRemove.inverse(Left(i)))
case Right(Inl(h)) => Inl(h)
case Right(Inr(t)) => Inr(tailRemove.inverse(Right(t)))
}
}
}
object Remove extends LowPriorityRemove {
def apply[C <: Coproduct, U](implicit remove: Remove[C, U]): Aux[C, U, remove.Rest] = remove
implicit def removeHead[H, T <: Coproduct]: Aux[H :+: T, H, T] = new Remove[H :+: T, H] {
type Rest = T
def apply(c: H :+: T) = c match {
case Inl(h) => Left(h)
case Inr(t) => Right(t)
}
def inverse(r: Either[H, T]) = r match {
case Left(h) => Inl(h)
case Right(t) => Inr(t)
}
}
}
trait RemoveLast[C <: Coproduct, I] extends DepFn1[C] with Serializable {
type Rest <: Coproduct
type Out = Either[I, Rest]
def inverse(r: Either[I, Rest]): C
}
trait LowPriorityRemoveLast {
type Aux[C <: Coproduct, I, Rest0 <: Coproduct] = RemoveLast[C, I] {type Rest = Rest0}
protected def fromRemove[C <: Coproduct, I](remove: Remove[C, I]): Aux[C, I, remove.Rest] =
new RemoveLast[C, I] {
type Rest = remove.Rest
def apply(c: C) = remove(c)
def inverse(r: Either[I, Rest]) = remove.inverse(r)
}
protected def toRemove[C <: Coproduct, I](removeLast: RemoveLast[C, I]): Remove.Aux[C, I, removeLast.Rest] =
new Remove[C, I] {
type Rest = removeLast.Rest
def apply(c: C) = removeLast(c)
def inverse(r: Either[I, Rest]) = removeLast.inverse(r)
}
// Must be given a lower priority than removeLastTail, so that:
// - the two don't collide for coproducts with repeated types
// - the last element of type I in C is removed
implicit def removeLastHead[H, T <: Coproduct]: Aux[H :+: T, H, T] = fromRemove(Remove.removeHead[H, T])
}
object RemoveLast extends LowPriorityRemoveLast {
def apply[C <: Coproduct, I](implicit removeLast: RemoveLast[C, I]): Aux[C, I, removeLast.Rest] = removeLast
implicit def removeLastTail[H, T <: Coproduct, I](implicit
tailRemoveLast: RemoveLast[T, I]
): Aux[H :+: T, I, H :+: tailRemoveLast.Rest] = fromRemove(Remove.removeTail(toRemove(tailRemoveLast)))
}
trait FlatMap[C <: Coproduct, F <: Poly] extends DepFn1[C] with Serializable { type Out <: Coproduct }
object FlatMap {
def apply[C <: Coproduct, F <: Poly](implicit folder: FlatMap[C, F]): Aux[C, F, folder.Out] = folder
type Aux[C <: Coproduct, F <: Poly, Out0 <: Coproduct] = FlatMap[C, F] { type Out = Out0 }
implicit def cnilFlatMap[F <: Poly]: Aux[CNil, F, CNil] = new FlatMap[CNil, F] {
type Out = CNil
def apply(c: CNil): Out = c
}
implicit def cpFlatMap[H, T <: Coproduct, F <: Poly, OutH <: Coproduct, OutT <: Coproduct](
implicit
fh: Case1.Aux[F, H, OutH],
ft: FlatMap.Aux[T, F, OutT],
extendBy: ExtendBy[OutH, OutT]
): Aux[H :+: T, F, extendBy.Out] = new FlatMap[H :+: T, F] {
type Out = extendBy.Out
def apply(c: H :+: T): Out = c match {
case Inl(h) => extendBy.right(fh(h))
case Inr(t) => extendBy.left(ft(t))
}
}
}
trait Mapper[F <: Poly, C <: Coproduct] extends DepFn1[C] with Serializable { type Out <: Coproduct }
object Mapper {
def apply[F <: Poly, C <: Coproduct](implicit mapper: Mapper[F, C]): Aux[F, C, mapper.Out] = mapper
def apply[C <: Coproduct](f: Poly)(implicit mapper: Mapper[f.type, C]): Aux[f.type, C, mapper.Out] = mapper
type Aux[F <: Poly, C <: Coproduct, Out0 <: Coproduct] = Mapper[F, C] { type Out = Out0 }
implicit def cnilMapper[F <: Poly]: Aux[F, CNil, CNil] = new Mapper[F, CNil] {
type Out = CNil
def apply(t: CNil): Out = t
}
implicit def cpMapper[F <: Poly, H, OutH, T <: Coproduct]
(implicit fh: Case1.Aux[F, H, OutH], mt: Mapper[F, T]): Aux[F, H :+: T, OutH :+: mt.Out] =
new Mapper[F, H :+: T] {
type Out = OutH :+: mt.Out
def apply(c: H :+: T): Out = c match {
case Inl(h) => Inl(fh(h))
case Inr(t) => Inr(mt(t))
}
}
}
trait Unifier[C <: Coproduct] extends DepFn1[C] with Serializable
object Unifier {
def apply[C <: Coproduct](implicit unifier: Unifier[C]): Aux[C, unifier.Out] = unifier
type Aux[C <: Coproduct, Out0] = Unifier[C] { type Out = Out0 }
implicit def lstUnifier[H]: Aux[H :+: CNil, H] =
new Unifier[H :+: CNil] {
type Out = H
def apply(c: H :+: CNil): Out = (c: @unchecked) match {
case Inl(h) => h
}
}
implicit def cpUnifier[H1, H2, T <: Coproduct, L, Out0]
(implicit lt: Aux[H2 :+: T, L], u: Lub[H1, L, Out0]): Aux[H1 :+: H2 :+: T, Out0] =
new Unifier[H1 :+: H2 :+: T] {
type Out = Out0
def apply(c: H1 :+: H2 :+: T): Out = c match {
case Inl(h1) => u.left(h1)
case Inr(t) => u.right(lt(t))
}
}
}
trait Folder[F <: Poly, C <: Coproduct] extends DepFn1[C] with Serializable
object Folder {
def apply[F <: Poly, C <: Coproduct](implicit folder: Folder[F, C]): Aux[F, C, folder.Out] = folder
def apply[C <: Coproduct](f: Poly)(implicit folder: Folder[f.type, C]): Aux[f.type, C, folder.Out] = folder
type Aux[F <: Poly, C <: Coproduct, Out0] = Folder[F, C] { type Out = Out0 }
implicit def mkFolder[F <: Poly, C <: Coproduct, M <: Coproduct, Out0]
(implicit mapper: Mapper.Aux[F, C, M], unifier: Unifier.Aux[M, Out0]): Aux[F, C, Out0] =
new Folder[F, C] {
type Out = Out0
def apply(c: C): Out = unifier(mapper(c))
}
}
trait LeftFolder[C <: Coproduct, In, F] extends DepFn2[C,In] with Serializable
object LeftFolder {
def apply[C <: Coproduct, In, F](implicit folder: LeftFolder[C, In, F]): Aux[C, In, F, folder.Out] = folder
type Aux[C <: Coproduct, In, HF, Out0] = LeftFolder[C, In, HF] { type Out = Out0 }
implicit def hdLeftFolder[H, In, F]
(implicit f: Case2.Aux[F, In, H, In]): Aux[H :+: CNil, In, F,In] = new LeftFolder[H :+: CNil, In, F] {
type Out = In
def apply(c: H :+: CNil, in: In): In = f(in,c.head.get)
}
implicit def tlLeftFolder[H, T <: Coproduct, In, HF, OutH]
(implicit f: Case2.Aux[HF, In, H, OutH], ft: Aux[T, In, HF, OutH]): Aux[H :+: T, In, HF, OutH] = new LeftFolder[H :+: T, In, HF] {
type Out = OutH
def apply(c: H :+: T, in: In): Out =
c match {
case Inl(h) => f(in, h)
case Inr(t) => ft(t, in)
}
}
}
/**
* Type class supporting zipping this `Coproduct` with a constant of type `Z` returning a `Coproduct` of tuples of the form
* ({element from input `Coproduct`}, {supplied constant})
*
* @author William Harvey
*/
trait ZipConst[Z, V <: Coproduct] extends DepFn2[Z, V] with Serializable { type Out <: Coproduct }
object ZipConst {
def apply[Z, V <: Coproduct](implicit zipConst: ZipConst[Z, V]): Aux[Z, V, zipConst.Out] = zipConst
type Aux[Z, V <: Coproduct, Out0 <: Coproduct] = ZipConst[Z, V] { type Out = Out0 }
implicit def cnilZipConst[Z]: Aux[Z, CNil, CNil] = new ZipConst[Z, CNil] {
type Out = CNil
def apply(z: Z, v: CNil) = v
}
implicit def cpZipConst[Z, VH, VT <: Coproduct](implicit zipConst: ZipConst[Z, VT]): Aux[Z, VH :+: VT, (VH, Z) :+: zipConst.Out] =
new ZipConst[Z, VH :+: VT] {
type Out = (VH, Z) :+: zipConst.Out
def apply(z: Z, v: VH :+: VT): Out = v match {
case Inl(vh) => Inl((vh, z))
case Inr(vt) => Inr(zipConst(z, vt))
}
}
}
trait ZipWithKeys[K <: HList, V <: Coproduct] extends DepFn1[V] with Serializable { type Out <: Coproduct }
object ZipWithKeys {
import shapeless.labelled._
def apply[K <: HList, V <: Coproduct]
(implicit zipWithKeys: ZipWithKeys[K, V]): Aux[K, V, zipWithKeys.Out] = zipWithKeys
type Aux[K <: HList, V <: Coproduct, Out0 <: Coproduct] = ZipWithKeys[K, V] { type Out = Out0 }
implicit val cnilZipWithKeys: Aux[HNil, CNil, CNil] = new ZipWithKeys[HNil, CNil] {
type Out = CNil
def apply(v: CNil) = v
}
implicit def cpZipWithKeys[KH, VH, KT <: HList, VT <: Coproduct] (implicit zipWithKeys: ZipWithKeys[KT, VT], wkh: Witness.Aux[KH])
: Aux[KH :: KT, VH :+: VT, FieldType[KH, VH] :+: zipWithKeys.Out] =
new ZipWithKeys[KH :: KT, VH :+: VT] {
type Out = FieldType[KH, VH] :+: zipWithKeys.Out
def apply(v: VH :+: VT): Out = v match {
case Inl(vh) => Inl(field[wkh.T](vh))
case Inr(vt) => Inr(zipWithKeys(vt))
}
}
}
/**
* Type class supporting zipping a `Coproduct` with its element indices, resulting in a `Coproduct` of tuples of the form
* ({element from input tuple}, {element index})
*
* @author Andreas Koestler
*/
trait ZipWithIndex[C <: Coproduct] extends DepFn1[C] with Serializable { type Out <: Coproduct; type Idx <: Nat }
object ZipWithIndex {
import shapeless.Nat._
def apply[C <: Coproduct](implicit zipper: ZipWithIndex[C]): Aux[C, zipper.Out] = zipper
type Aux[C <: Coproduct, Out0 <: Coproduct] = ZipWithIndex[C] {type Out = Out0}
implicit def cpZipWithIndex[C <: Coproduct]
(implicit impl: Impl[C, _0]): Aux[C, impl.Out] = new ZipWithIndex[C] {
type Out = impl.Out
def apply(c: C): Out = impl(c)
}
trait Impl[C <: Coproduct, N <: Nat] extends DepFn1[C] with Serializable {
type Out <: Coproduct
}
object Impl {
def apply[C <: Coproduct, N <: Nat](implicit impl: Impl[C, N]): Aux[C, N, impl.Out] = impl
type Aux[C <: Coproduct, N <: Nat, Out0 <: Coproduct] = Impl[C, N] {type Out = Out0}
implicit def singleZipWithIndexImpl[CH, N <: Nat]
(implicit w: Witness.Aux[N]): Aux[CH :+: CNil, N, (CH, N) :+: CNil] = new Impl[CH :+: CNil, N] {
type Out = (CH, N) :+: CNil
def apply(c: CH :+: CNil): Out = Coproduct[Out]((c.head.get, w.value))
}
implicit def cpZipWithIndexImpl[CH, CT <: Coproduct, N <: Nat, OutC <: Coproduct]
(implicit
impl: Impl[CT, Succ[N]],
w: Witness.Aux[N]
): Aux[CH :+: CT, N, (CH, N) :+: impl.Out] =
new Impl[CH :+: CT, N] {
type Out = (CH, N) :+: impl.Out
def apply(c: CH :+: CT): Out = c match {
case Inl(h) => Inl((h, w.value))
case Inr(t) => Inr(impl(t))
}
}
}
}
/**
* Type class supporting zipping a `Coproduct` with an `HList`, resulting in a `Coproduct` of tuples of the form
* ({element from input `Coproduct`}, {element from input `HList`})
*
* @author William Harvey
*/
trait ZipWith[H <: HList, V <: Coproduct] extends DepFn2[H, V] with Serializable { type Out <: Coproduct }
object ZipWith {
def apply[H <: HList, V <: Coproduct](implicit zipWith: ZipWith[H, V]): Aux[H, V, zipWith.Out] = zipWith
type Aux[H <: HList, V <: Coproduct, Out0 <: Coproduct] = ZipWith[H, V] { type Out = Out0 }
implicit def cnilZipWith: Aux[HNil, CNil, CNil] = new ZipWith[HNil, CNil] {
type Out = CNil
def apply(h: HNil, v: CNil) = v
}
implicit def cpZipWith[HH, HT <: HList, VH, VT <: Coproduct](implicit zipWith: ZipWith[HT, VT]):
Aux[HH :: HT, VH :+: VT, (VH, HH) :+: zipWith.Out] = new ZipWith[HH :: HT, VH :+: VT] {
type Out = (VH, HH) :+: zipWith.Out
def apply(h: HH :: HT, v: VH :+: VT): Out = v match {
case Inl(vh) => Inl((vh, h.head))
case Inr(vt) => Inr(zipWith(h.tail, vt))
}
}
}
/**
* Type class supporting computing the type-level Nat corresponding to the length of this `Coproduct'.
*
* @author Stacy Curl
*/
trait Length[C <: Coproduct] extends DepFn0 with Serializable { type Out <: Nat }
object Length {
def apply[C <: Coproduct](implicit length: Length[C]): Aux[C, length.Out] = length
type Aux[C <: Coproduct, Out0 <: Nat] = Length[C] { type Out = Out0 }
implicit def cnilLength: Aux[CNil, Nat._0] = new Length[CNil] {
type Out = Nat._0
def apply(): Out = Nat._0
}
implicit def coproductLength[H, T <: Coproduct, N <: Nat]
(implicit lt: Aux[T, N], sn: Witness.Aux[Succ[N]]): Aux[H :+: T, Succ[N]] = new Length[H :+: T] {
type Out = Succ[N]
def apply(): Out = sn.value
}
}
/**
* Type class supporting extending a coproduct on the right
*
* @author Stacy Curl
*/
trait ExtendRight[C <: Coproduct, T] extends DepFn1[C] with Serializable { type Out <: Coproduct }
object ExtendRight {
def apply[C <: Coproduct, T]
(implicit extendRight: ExtendRight[C, T]): Aux[C, T, extendRight.Out] = extendRight
type Aux[C <: Coproduct, T, Out0 <: Coproduct] = ExtendRight[C, T] { type Out = Out0 }
implicit def extendRightSingleton[H, A]: Aux[H :+: CNil, A, H :+: A :+: CNil] =
new ExtendRight[H :+: CNil, A] {
type Out = H :+: A :+: CNil
def apply(c: H :+: CNil): Out = c match {
case Inl(h) => Inl(h)
case Inr(t) => Inr(Inr(t))
}
}
implicit def extendRightCoproduct[H, T <: Coproduct, A, AT <: Coproduct]
(implicit extendRight: Aux[T, A, AT]): Aux[H :+: T, A, H :+: AT] =
new ExtendRight[H :+: T, A] {
type Out = H :+: AT
def apply(c: H :+: T) = c match {
case Inl(h) => Inl(h)
case Inr(t) => Inr(extendRight(t))
}
}
}
trait ExtendBy[L <: Coproduct, R <: Coproduct] extends Serializable {
type Out <: Coproduct
def right(l: L): Out
def left(r: R): Out
}
object ExtendBy {
def apply[L <: Coproduct, R <: Coproduct]
(implicit extendBy: ExtendBy[L, R]): Aux[L, R, extendBy.Out] = extendBy
type Aux[L <: Coproduct, R <: Coproduct, Out0 <: Coproduct] = ExtendBy[L, R] { type Out = Out0 }
implicit def extendBy[L <: Coproduct, R <: Coproduct, Out0 <: Coproduct](
implicit extendLeftBy: ExtendLeftBy.Aux[L, R, Out0], extendRightBy: ExtendRightBy.Aux[L, R, Out0]
): ExtendBy.Aux[L, R, Out0] = new ExtendBy[L, R] {
type Out = Out0
def right(l: L): Out = extendRightBy(l)
def left(r: R): Out = extendLeftBy(r)
}
}
trait ExtendLeftBy[L <: Coproduct, R <: Coproduct] extends DepFn1[R] with Serializable { type Out <: Coproduct }
object ExtendLeftBy {
def apply[L <: Coproduct, R <: Coproduct]
(implicit extendLeftBy: ExtendLeftBy[L, R]): Aux[L, R, extendLeftBy.Out] = extendLeftBy
type Aux[L <: Coproduct, R <: Coproduct, Out0 <: Coproduct] = ExtendLeftBy[L, R] { type Out = Out0 }
implicit def extendLeftByCoproduct[L <: Coproduct, R <: Coproduct, RevL <: Coproduct](
implicit reverseL: Reverse.Aux[L, RevL], impl: Impl[RevL, R]
): Aux[L, R, impl.Out] = new ExtendLeftBy[L, R] {
type Out = impl.Out
def apply(r: R): Out = impl(r)
}
trait Impl[RevL <: Coproduct, R <: Coproduct] extends DepFn1[R] with Serializable { type Out <: Coproduct }
object Impl {
type Aux[RevL <: Coproduct, R <: Coproduct, Out0 <: Coproduct] = Impl[RevL, R] { type Out = Out0 }
implicit def extendLeftByCNilImpl[R <: Coproduct]: Aux[CNil, R, R] = new Impl[CNil, R] {
type Out = R
def apply(r: R): Out = r
}
implicit def extendLeftByCoproductImpl[H, T <: Coproduct, R <: Coproduct](
implicit extendLeftBy: Impl[T, H :+: R]
): Aux[H :+: T, R, extendLeftBy.Out] = new Impl[H :+: T, R] {
type Out = extendLeftBy.Out
def apply(r: R): Out = extendLeftBy(Inr[H, R](r))
}
}
}
trait ExtendRightBy[L <: Coproduct, R <: Coproduct] extends DepFn1[L] with Serializable { type Out <: Coproduct }
object ExtendRightBy {
def apply[L <: Coproduct, R <: Coproduct]
(implicit extendRightBy: ExtendRightBy[L, R]): Aux[L, R, extendRightBy.Out] = extendRightBy
type Aux[L <: Coproduct, R <: Coproduct, Out0 <: Coproduct] = ExtendRightBy[L, R] { type Out = Out0 }
implicit def extendRightByCNil[L <: Coproduct]: Aux[L, CNil, L] = new ExtendRightBy[L, CNil] {
type Out = L
def apply(l: L): Out = l
}
implicit def extendRightByCoproduct[L <: Coproduct, H, LH <: Coproduct, T <: Coproduct](
implicit extendRight: ExtendRight.Aux[L, H, LH], extendRightBy: ExtendRightBy[LH, T]
): Aux[L, H :+: T, extendRightBy.Out] = new ExtendRightBy[L, H :+: T] {
type Out = extendRightBy.Out
def apply(l: L): Out = extendRightBy(extendRight(l))
}
}
/**
* Type class supporting rotating a Coproduct left
*
* @author Stacy Curl
* @author Alexandre Archambault
*/
trait RotateLeft[C <: Coproduct, N <: Nat] extends DepFn1[C] with Serializable { type Out <: Coproduct }
object RotateLeft extends LowPriorityRotateLeft {
type Aux[C <: Coproduct, N <: Nat, Out0] = RotateLeft[C, N] { type Out = Out0 }
def apply[C <: Coproduct, N <: Nat]
(implicit rotateLeft: RotateLeft[C, N]): Aux[C, N, rotateLeft.Out] = rotateLeft
implicit def cnilRotateLeft[N <: Nat]: RotateLeft.Aux[CNil, N, CNil] = new RotateLeft[CNil, N] {
type Out = CNil
def apply(c: CNil) = c
}
/** Binary compatibility stub */
def implToRotateLeft[C <: Coproduct, N <: Nat, Size <: Nat, NModSize <: Succ[_]](implicit
length: Length.Aux[C, Size],
mod: nat.Mod.Aux[N, Size, NModSize],
impl: Impl[C, NModSize]
): Aux[C, N, impl.Out] =
new RotateLeft[C, N] {
type Out = impl.Out
def apply(c: C): Out = impl(c)
}
/** Binary compatibility stub */
trait Impl[C <: Coproduct, N <: Nat] extends DepFn1[C] with Serializable { type Out <: Coproduct }
/** Binary compatibility stub */
object Impl {
type Aux[C <: Coproduct, N <: Nat, Out0 <: Coproduct] = Impl[C, N] { type Out = Out0 }
def rotateCoproductOne[H, T <: Coproduct, TH <: Coproduct]
(implicit extendRight: ExtendRight.Aux[T, H, TH], inject: Inject[TH, H]): Aux[H :+: T, Nat._1, TH] =
new Impl[H :+: T, Nat._1] {
type Out = TH
def apply(c: H :+: T): Out = c match {
case Inl(a) => inject(a)
case Inr(tail) => extendRight(tail)
}
}
def rotateCoproductN[C <: Coproduct, N <: Nat, CN <: Coproduct, CSN <: Coproduct]
(implicit rotateN: Aux[C, N, CN], rotate1: Aux[CN, Nat._1, CSN]): Aux[C, Succ[N], CSN] =
new Impl[C, Succ[N]] {
type Out = CSN
def apply(c: C): Out = rotate1(rotateN(c))
}
}
}
trait LowPriorityRotateLeft {
implicit def coproductRotateLeft[
C <: Coproduct, N <: Nat, Size <: Nat, NModSize <: Nat, Before <: Coproduct, After <: Coproduct
](implicit
length: Length.Aux[C, Size],
mod: nat.Mod.Aux[N, Size, NModSize],
split: Split.Aux[C, NModSize, Before, After],
prepend: Prepend[After, Before]
): RotateLeft.Aux[C, N, prepend.Out] = new RotateLeft[C, N] {
type Out = prepend.Out
def apply(c: C): Out = {
val e = split(c)
prepend(e.swap)
}
}
/** Binary compatibility stub */
def noopRotateLeftImpl[C <: Coproduct, N <: Nat]: RotateLeft.Aux[C, N, C] = new RotateLeft[C, N] {
type Out = C
def apply(c: C): Out = c
}
}
/**
* Type class supporting rotating a Coproduct right
*
* @author Stacy Curl
* @author Alexandre Archambault
*/
trait RotateRight[C <: Coproduct, N <: Nat] extends DepFn1[C] with Serializable { type Out <: Coproduct }
object RotateRight extends LowPriorityRotateRight {
def apply[C <: Coproduct, N <: Nat]
(implicit rotateRight: RotateRight[C, N]): Aux[C, N, rotateRight.Out] = rotateRight
implicit def cnilRotateRight[N <: Nat]: RotateRight.Aux[CNil, N, CNil] = new RotateRight[CNil, N] {
type Out = CNil
def apply(c: CNil) = c
}
/** Binary compatibility stub */
def hlistRotateRight[
C <: Coproduct, N <: Nat, Size <: Nat, NModSize <: Succ[_], Size_Diff_NModSize <: Nat
](implicit
length: Length.Aux[C, Size],
mod: nat.Mod.Aux[N, Size, NModSize],
diff: nat.Diff.Aux[Size, NModSize, Size_Diff_NModSize],
rotateLeft: RotateLeft.Impl[C, Size_Diff_NModSize]
): Aux[C, N, rotateLeft.Out] = new RotateRight[C, N] {
type Out = rotateLeft.Out
def apply(c: C): Out = rotateLeft(c)
}
}
trait LowPriorityRotateRight {
type Aux[C <: Coproduct, N <: Nat, Out0 <: Coproduct] = RotateRight[C, N] { type Out = Out0 }
implicit def coproductRotateRight[
C <: Coproduct, N <: Nat, Size <: Nat, NModSize <: Nat, Size_Diff_NModSize <: Nat
](implicit
length: Length.Aux[C, Size],
mod: nat.Mod.Aux[N, Size, NModSize],
diff: nat.Diff.Aux[Size, NModSize, Size_Diff_NModSize],
rotateLeft: RotateLeft[C, Size_Diff_NModSize]
): RotateRight.Aux[C, N, rotateLeft.Out] = new RotateRight[C, N] {
type Out = rotateLeft.Out
def apply(c: C): Out = rotateLeft(c)
}
/** Binary compatibility stub */
def noopRotateRight[C <: Coproduct, N <: Nat]: Aux[C, N, C] = new RotateRight[C, N] {
type Out = C
def apply(c: C): Out = c
}
}
/**
* Type class providing access to head and tail of a Coproduct
*
* @author Stacy Curl
*/
trait IsCCons[C <: Coproduct] extends Serializable {
type H
type T <: Coproduct
def head(c: C): Option[H]
def tail(c: C): Option[T]
def cons(e: Either[H, T]): C
}
object IsCCons {
def apply[C <: Coproduct](implicit isCCons: IsCCons[C]): Aux[C, isCCons.H, isCCons.T] = isCCons
type Aux[C <: Coproduct, H0, T0 <: Coproduct] = IsCCons[C] { type H = H0; type T = T0 }
implicit def coproductCCons[H0, T0 <: Coproduct]: Aux[H0 :+: T0, H0, T0] = new IsCCons[H0 :+: T0] {
type H = H0
type T = T0
def head(c: H0 :+: T0): Option[H0] = c match {
case Inl(h) => Some(h)
case _ => None
}
def tail(c: H0 :+: T0): Option[T0] = c match {
case Inr(t) => Some(t)
case _ => None
}
def cons(e: Either[H0, T0]): H0 :+: T0 = e match {
case Left(h) => Inl(h)
case Right(t) => Inr(t)
}
}
}
/**
* Type class supporting splitting this `Coproduct` at the ''nth'' element returning prefix and suffix as a coproduct
*
* @author Stacy Curl, Alexandre Archambault
*/
trait Split[C <: Coproduct, N <: Nat] extends DepFn1[C] with Serializable {
type Left <: Coproduct
type Right <: Coproduct
type Out = Either[Left, Right]
def coproduct(c: C): Left :+: Right :+: CNil = apply(c) match {
case Left(l) =>
Inl(l)
case Right(r) =>
Inr(Inl(r))
}
}
object Split {
def apply[C <: Coproduct, N <: Nat](implicit split: Split[C, N]): Aux[C, N, split.Left, split.Right] = split
type Aux[C <: Coproduct, N <: Nat, L <: Coproduct, R <: Coproduct] =
Split[C, N] { type Left = L; type Right = R }
implicit def splitZero[C <: Coproduct]: Aux[C, Nat._0, CNil, C] =
new Split[C, Nat._0] {
type Left = CNil
type Right = C
def apply(c: C) = Right(c)
}
implicit def splitSucc[H, T <: Coproduct, N <: Nat]
(implicit tail: Split[T, N]): Aux[H :+: T, Succ[N], H :+: tail.Left, tail.Right] =
new Split[H :+: T, Succ[N]] {
type Left = H :+: tail.Left
type Right = tail.Right
def apply(c: H :+: T) = c match {
case Inl(h) => Left(Inl(h))
case Inr(t) => tail(t) match {
case Left(l) => Left(Inr(l))
case Right(r) => Right(r)
}
}
}
}
/**
* Type class supporting taking the first `n`-elements of this `Coproduct`
*
* @author Alexandre Archambault
*/
trait Take[C <: Coproduct, N <: Nat] extends DepFn1[C] with Serializable {
type Taken <: Coproduct
type Out = Option[Taken]
}
object Take {
def apply[C <: Coproduct, N <: Nat](implicit take: Take[C, N]): Aux[C, N, take.Taken] = take
type Aux[C <: Coproduct, N <: Nat, L <: Coproduct] = Take[C, N] { type Taken = L }
implicit def takeZero[C <: Coproduct]: Aux[C, Nat._0, CNil] =
new Take[C, Nat._0] {
type Taken = CNil
def apply(c: C) = None
}
implicit def takeSucc[H, T <: Coproduct, N <: Nat]
(implicit tail: Take[T, N]): Aux[H :+: T, Succ[N], H :+: tail.Taken] =
new Take[H :+: T, Succ[N]] {
type Taken = H :+: tail.Taken
def apply(c: H :+: T) = c match {
case Inl(h) => Some(Coproduct[H :+: tail.Taken](h))
case Inr(t) => tail(t).map(Inr[H, tail.Taken](_))
}
}
}
/**
* Type class supporting dropping the first `n`-elements of this `Coproduct`
*
* @author Alexandre Archambault
*/
trait Drop[C <: Coproduct, N <: Nat] extends DepFn1[C] with Serializable {
type Remaining <: Coproduct
type Out = Option[Remaining]
}
object Drop {
def apply[C <: Coproduct, N <: Nat](implicit drop: Drop[C, N]): Aux[C, N, drop.Remaining] = drop
type Aux[C <: Coproduct, N <: Nat, L <: Coproduct] = Drop[C, N] { type Remaining = L }
implicit def dropZero[C <: Coproduct]: Aux[C, Nat._0, C] =
new Drop[C, Nat._0] {
type Remaining = C
def apply(c: C) = Some(c)
}
implicit def dropSucc[H, T <: Coproduct, N <: Nat]
(implicit tail: Drop[T, N]): Aux[H :+: T, Succ[N], tail.Remaining] =
new Drop[H :+: T, Succ[N]] {
type Remaining = tail.Remaining
def apply(c: H :+: T) = c match {
case Inl(h) => None
case Inr(t) => tail(t)
}
}
}
/**
* Type class supporting reversing a Coproduct
*
* @author Stacy Curl
* @author Alexandre Archambault
*/
trait Reverse[C <: Coproduct] extends DepFn1[C] with Serializable { type Out <: Coproduct }
object Reverse {
def apply[C <: Coproduct](implicit reverse: Reverse[C]): Aux[C, reverse.Out] = reverse
type Aux[C <: Coproduct, Out0 <: Coproduct] = Reverse[C] { type Out = Out0 }
implicit def reverse[C <: Coproduct, Out0 <: Coproduct](implicit reverse: Reverse0[CNil, C, Out0]): Aux[C, Out0] =
new Reverse[C] {
type Out = Out0
def apply(c: C) = reverse(Right(c))
}
trait Reverse0[Acc <: Coproduct, L <: Coproduct, Out <: Coproduct] extends Serializable {
def apply(e: Either[Acc, L]): Out
}
object Reverse0 {
implicit def cnilReverse[Out <: Coproduct]: Reverse0[Out, CNil, Out] =
new Reverse0[Out, CNil, Out] {
def apply(e: Either[Out, CNil]) = e.left.get
}
implicit def cconsReverse[Acc <: Coproduct, InH, InT <: Coproduct, Out <: Coproduct]
(implicit rt: Reverse0[InH :+: Acc, InT, Out]): Reverse0[Acc, InH :+: InT, Out] =
new Reverse0[Acc, InH :+: InT, Out] {
def apply(e: Either[Acc, InH :+: InT]) = rt(e match {
case Left(acc) => Left(Inr(acc))
case Right(Inl(h)) => Left(Inl(h))
case Right(Inr(t)) => Right(t)
})
}
}
/** Binary compatibility stub */
val reverseCNil: Aux[CNil, CNil] = reverse[CNil, CNil]
/** Binary compatibility stub */
def reverseCoproduct[H, T <: Coproduct, ReverseT <: Coproduct, RotateL_HReverseT <: Coproduct](implicit
reverse: Aux[T, ReverseT],
rotateLeft: RotateLeft.Aux[H :+: ReverseT, Nat._1, RotateL_HReverseT],
inject: Inject[RotateL_HReverseT, H]
): Aux[H :+: T, RotateL_HReverseT] = new Reverse[H :+: T] {
type Out = RotateL_HReverseT
def apply(c: H :+: T): Out = c match {
case Inl(h) => inject(h)
case Inr(t) => rotateLeft(Inr[H, ReverseT](reverse(t)))
}
}
}
/**
* Type class supporting permuting this `Coproduct` into the same order as another `Coproduct` with
* the same element types.
*
* @author Michael Pilquist
*/
trait Align[A <: Coproduct, B <: Coproduct] extends (A => B) with Serializable {
def apply(a: A): B
}
object Align {
def apply[A <: Coproduct, B <: Coproduct](implicit a: Align[A, B]): Align[A, B] = a
implicit val cnilAlign: Align[CNil, CNil] = new Align[CNil, CNil] {
def apply(c: CNil): CNil = c
}
implicit def coproductAlign[A <: Coproduct, BH, BT <: Coproduct, R <: Coproduct]
(implicit remove: Remove.Aux[A, BH, R], alignTail: Align[R, BT]): Align[A, BH :+: BT] = new Align[A, BH :+: BT] {
def apply(a: A) = remove(a) match {
case Left(bh) => Inl(bh)
case Right(rest) => Inr(alignTail(rest))
}
}
}
/**
* Type class supporting prepending to this `Coproduct`.
*
* @author Alexandre Archambault
*/
trait Prepend[P <: Coproduct, S <: Coproduct] extends DepFn1[Either[P, S]] with Serializable { type Out <: Coproduct }
trait LowestPriorityPrepend {
type Aux[P <: Coproduct, S <: Coproduct, Out0 <: Coproduct] = Prepend[P, S] { type Out = Out0 }
implicit def cconsPrepend[PH, PT <: Coproduct, S <: Coproduct]
(implicit pt : Prepend[PT, S]): Aux[PH :+: PT, S, PH :+: pt.Out] =
new Prepend[PH :+: PT, S] {
type Out = PH :+: pt.Out
def apply(e : Either[PH :+: PT, S]): Out = e match {
case Left(Inl(h)) => Inl(h)
case Left(Inr(t)) => Inr(pt(Left(t)))
case Right(s) => Inr(pt(Right(s)))
}
}
}
trait LowPriorityPrepend extends LowestPriorityPrepend {
implicit def cnilPrepend0[P <: Coproduct]: Aux[P, CNil, P] =
new Prepend[P, CNil] {
type Out = P
def apply(e : Either[P, CNil]): P = e.left.get
}
}
object Prepend extends LowPriorityPrepend {
def apply[P <: Coproduct, S <: Coproduct](implicit prepend: Prepend[P, S]): Aux[P, S, prepend.Out] = prepend
implicit def cnilPrepend1[S <: Coproduct]: Aux[CNil, S, S] =
new Prepend[CNil, S] {
type Out = S
def apply(e: Either[CNil, S]): S = e.right.get
}
}
/**
* Type class providing access to init and last of a Coproduct
*
* @author Stacy Curl
*/
trait InitLast[C <: Coproduct] extends Serializable {
type I <: Coproduct
type L
def init(c: C): Option[I]
def last(c: C): Option[L]
}
object InitLast {
def apply[C <: Coproduct](implicit initLast: InitLast[C]): Aux[C, initLast.I, initLast.L] = initLast
type Aux[C <: Coproduct, I0 <: Coproduct, L0] = InitLast[C] { type I = I0; type L = L0 }
implicit def initLastCoproduct[C <: Coproduct, ReverseC <: Coproduct, H, T <: Coproduct](
implicit reverse: Reverse.Aux[C, ReverseC], isCCons: IsCCons.Aux[ReverseC, H, T]
): Aux[C, T, H] = new InitLast[C] {
type I = T
type L = H
def init(c: C): Option[I] = isCCons.tail(reverse(c))
def last(c: C): Option[L] = isCCons.head(reverse(c))
}
}
implicit object cnilOrdering extends Ordering[CNil] {
def compare(x: CNil, y: CNil) = 0
}
implicit def coproductPartialOrdering[H, T <: Coproduct]
(implicit ordering: Ordering[H], partialOrdering: PartialOrdering[T]): PartialOrdering[H :+: T] =
new PartialOrdering[H :+: T] {
def lteq(x: H :+: T, y: H :+: T): Boolean = (x, y) match {
case (Inl(xh), Inl(yh)) => ordering.compare(xh, yh) <= 0
case (Inr(xt), Inr(yt)) => partialOrdering.tryCompare(xt, yt).fold(false)(_ <= 0)
case _ => false
}
def tryCompare(x: H :+: T, y: H :+: T): Option[Int] = (x, y) match {
case (Inl(xh), Inl(yh)) => Some(ordering.compare(xh, yh))
case (Inr(xt), Inr(yt)) => partialOrdering.tryCompare(xt, yt)
case _ => None
}
}
/**
* Type class computing the `HList` type corresponding to this `Coproduct`.
*
* @author Miles Sabin
*/
trait ToHList[L <: Coproduct] extends Serializable { type Out <: HList }
object ToHList {
def apply[L <: Coproduct](implicit thl: ToHList[L]): Aux[L, thl.Out] = thl
type Aux[L <: Coproduct, Out0 <: HList] = ToHList[L] { type Out = Out0 }
implicit val cnilToHList: Aux[CNil, HNil] =
new ToHList[CNil] {
type Out = HNil
}
implicit def cconsToHList[H, T <: Coproduct](implicit ut: ToHList[T]): Aux[H :+: T, H :: ut.Out] =
new ToHList[H :+: T] {
type Out = H :: ut.Out
}
}
/**
* Typeclass checking that :
* - coproduct is a sub-union of a bigger coproduct
* - embeds a sub-coproduct into a bigger coproduct
*/
trait Basis[Super <: Coproduct, Sub <: Coproduct] extends DepFn1[Super] with Serializable {
type Rest <: Coproduct
type Out = Either[Rest, Sub]
def inverse(e: Either[Rest, Sub]): Super
}
object Basis {
type Aux[Super <: Coproduct, Sub <: Coproduct, Rest0 <: Coproduct] =
Basis[Super, Sub] { type Rest = Rest0 }
def apply[Super <: Coproduct, Sub <: Coproduct](implicit basis: Basis[Super, Sub]): Aux[Super, Sub, basis.Rest] =
basis
implicit def cnilBasis[Super <: Coproduct]: Aux[Super, CNil, Super] = new Basis[Super, CNil] {
type Rest = Super
def apply(s: Super) = Left(s)
def inverse(e: Either[Rest, CNil]) = e.left.get // No CNil exists, so e cannot be a Right
}
implicit def cconsBasis[Super <: Coproduct, H, T <: Coproduct, TRest <: Coproduct](implicit
tailBasis: Basis.Aux[Super, T, TRest],
remove: RemoveLast[TRest, H]
): Aux[Super, H :+: T, remove.Rest] = new Basis[Super, H :+: T] {
type Rest = remove.Rest
def apply(s: Super) = tailBasis(s) match {
case Left(r) => remove(r) match {
case Left(h) => Right(Inl(h))
case Right(r) => Left(r)
}
case Right(t) => Right(Inr(t))
}
def inverse(e: Either[Rest, H :+: T]) = e match {
case Left(r) => tailBasis.inverse(Left(remove.inverse(Right(r))))
case Right(c) => c match {
case Inl(h) => tailBasis.inverse(Left(remove.inverse(Left(h))))
case Inr(t) => tailBasis.inverse(Right(t))
}
}
}
}
private def toEither[Prefix, Suffix](c: Prefix :+: Suffix :+: CNil): Either[Prefix, Suffix] = c match {
case Inl(prefix) => Left(prefix)
case Inr(Inl(suffix)) => Right(suffix)
case _ => sys.error("Impossible")
}
/**
* Type class supporting reifying a `Coproduct` of singleton types.
*
* @author Jisoo Park
*/
trait Reify[L <: Coproduct] extends DepFn0 with Serializable { type Out <: HList }
object Reify {
def apply[L <: Coproduct](implicit reify: Reify[L]): Aux[L, reify.Out] = reify
type Aux[L <: Coproduct, Out0 <: HList] = Reify[L] { type Out = Out0 }
implicit def cnilReify[L <: CNil]: Aux[L, HNil] =
new Reify[L] {
type Out = HNil
def apply(): Out = HNil
}
implicit def coproductReify[H, T <: Coproduct](implicit
wh: Witness.Aux[H],
rt: Reify[T]
): Aux[H :+: T, H :: rt.Out] =
new Reify[H :+: T] {
type Out = H :: rt.Out
def apply(): Out = wh.value :: rt()
}
}
sealed trait LiftAll[F[_], In <: Coproduct] {
type Out <: HList
def instances: Out
}
object LiftAll {
type Aux[F[_], In0 <: Coproduct, Out0 <: HList] = LiftAll[F, In0] {type Out = Out0}
class Curried[F[_]] {def apply[In <: Coproduct](in: In)(implicit ev: LiftAll[F, In]) = ev}
def apply[F[_]] = new Curried[F]
def apply[F[_], In <: Coproduct](implicit ev: LiftAll[F, In]) = ev
implicit def liftAllCnil[F[_]]: LiftAll.Aux[F, CNil, HNil] = new LiftAll[F, CNil] {
type Out = HNil
def instances = HNil
}
implicit def liftAllCcons[F[_], H, T <: Coproduct, TI <: HList]
(implicit headInstance: F[H], tailInstances: Aux[F, T, TI]): Aux[F, H :+: T, F[H] :: TI] =
new LiftAll[F, H :+: T] {
type Out = F[H] :: TI
def instances = headInstance :: tailInstances.instances
}
}
/**
* Typeclass converting a `Coproduct` to an `Either`
*
* @author Michael Zuber
*/
sealed trait CoproductToEither[C <: Coproduct] extends DepFn1[C] with Serializable
object CoproductToEither {
type Aux[In <: Coproduct, Out0] = CoproductToEither[In] { type Out = Out0 }
implicit def baseToEither[L, R]: CoproductToEither.Aux[L :+: R :+: CNil, Either[L, R]] = new CoproductToEither[L :+: R :+: CNil] {
type Out = Either[L, R]
def apply(t: L :+: R :+: CNil): Either[L, R] = t match {
case Inl(l) => Left(l)
case Inr(Inl(r)) => Right(r)
case _ => ???
}
}
implicit def cconsToEither[L, R <: Coproduct, Out0](implicit
evR: CoproductToEither.Aux[R, Out0]
): CoproductToEither.Aux[L :+: R, Either[L, Out0]] = new CoproductToEither[L :+: R] {
type Out = Either[L, Out0]
def apply(t: L :+: R): Either[L, Out0] = t match {
case Inl(l) => Left(l)
case Inr(r) => Right(evR(r))
}
}
}
/**
* Typeclass converting an `Either` to a `Coproduct`
*
* @author Michael Zuber
*/
sealed trait EitherToCoproduct[L, R] extends DepFn1[Either[L, R]] with Serializable { type Out <: Coproduct }
object EitherToCoproduct extends EitherToCoproductLowPrio {
type Aux[L, R, Out0 <: Coproduct] = EitherToCoproduct[L, R] { type Out = Out0 }
implicit def econsEitherToCoproduct[L, RL, RR, Out0 <: Coproduct](implicit
evR: EitherToCoproduct.Aux[RL, RR, Out0]
): EitherToCoproduct.Aux[L, Either[RL, RR], L :+: Out0] = new EitherToCoproduct[L, Either[RL, RR]] {
type Out = L :+: Out0
def apply(t: Either[L, Either[RL, RR]]): L :+: Out0 = t match {
case Left(l) => Inl(l)
case Right(r) => Inr(evR(r))
}
}
}
trait EitherToCoproductLowPrio {
implicit def baseEitherToCoproduct[L, R]: EitherToCoproduct.Aux[L, R, L :+: R :+: CNil] = new EitherToCoproduct[L, R] {
type Out = L :+: R :+: CNil
def apply(t: Either[L, R]): L :+: R :+: CNil = t match {
case Left(l) => Inl(l)
case Right(r) => Coproduct[L :+: R :+: CNil](r)
}
}
}
/**
* Type class supporting the injection of runtime values of type `Any` in `Coproduct`.
*
* @author Juan José Vázquez Delgado
* @author Fabio Labella
*/
@annotation.implicitNotFound("Implicit not found. CNil has no values, so it's impossible to convert anything to it")
trait RuntimeInject[C <: Coproduct] extends Serializable {
def apply(x: Any): Option[C]
}
object RuntimeInject extends RuntimeInjectLowPrio {
implicit def baseCaseRuntimeInject[H](
implicit castH: Typeable[H]): RuntimeInject[H :+: CNil] =
new RuntimeInject[H :+: CNil] {
def apply(x: Any): Option[H :+: CNil] =
castH.cast(x).map(v => Inl(v))
}
}
trait RuntimeInjectLowPrio {
implicit def inductiveCaseRuntimeInject[H, T <: Coproduct](
implicit next: RuntimeInject[T],
castH: Typeable[H]): RuntimeInject[H :+: T] =
new RuntimeInject[H :+: T] {
def apply(x: Any): Option[H :+: T] = castH.cast(x) match {
case Some(value) => Option(Inl(value))
case None => next(x).map(v => Inr(v))
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy