zio.schema.CaseSet.scala Maven / Gradle / Ivy
The newest version!
package zio.schema
import scala.collection.immutable.ListMap
import zio.Chunk
import zio.schema.Schema._
sealed trait CaseSet { self =>
import CaseSet.{ :+: }
type EnumType
type Accessors[Whole, Lens[_, _, _], Prism[_, _, _], Traversal[_, _]]
def :+:[A](head: Case[EnumType, A]): A :+: CaseSet.Aux[EnumType]
// def ++[That](that: That)(implicit append: Append[EnumType, self.type, That]): append.Out
def toMap: ListMap[String, Schema[_]]
def toSeq: Seq[Case[EnumType, _]]
def makeAccessors(whole: Enum[EnumType], b: AccessorBuilder): Accessors[EnumType, b.Lens, b.Prism, b.Traversal]
}
object CaseSet {
type Aux[EnumType0] = CaseSet { type EnumType = EnumType0 }
final case class Empty[Z]() extends CaseSet { self =>
type EnumType = Z
override type Accessors[Whole, Lens[_, _, _], Prism[_, _, _], Traversal[_, _]] = Unit
override def :+:[A](head: Case[EnumType, A]): A :+: Empty[EnumType] = Cons(head, self)
def ++[That](that: That)(implicit append: Append[Z, Empty[Z], That]): append.Out =
append(self, that)
override def toMap: ListMap[String, Schema[_]] = ListMap.empty
override def toSeq: Seq[Case[Z, _]] = Seq.empty
override def makeAccessors(
whole: Enum[EnumType],
b: AccessorBuilder
): Accessors[EnumType, b.Lens, b.Prism, b.Traversal] = ()
override def toString: String = "Empty"
}
object Empty {
type Aux[Z] = CaseSet.Empty[Z] { type EnumType = Z }
}
sealed trait :+:[A, +T <: CaseSet] extends CaseSet {
def head: Case[EnumType, A]
}
final case class Cons[A, +T <: CaseSet.Aux[Z], Z](head: Case[Z, A], tail: T) extends :+:[A, T] { self =>
type EnumType = Z
override type Accessors[Whole, Lens[_, _, _], Prism[_, _, _], Traversal[_, _]] =
(Prism[head.id.type, Whole, A], tail.Accessors[Whole, Lens, Prism, Traversal])
override def :+:[B](head2: Case[Z, B]): Cons[B, Cons[A, T, Z], Z] = Cons(head2, self)
def ++[That](that: That)(implicit append: Append[Z, Cons[A, T, Z], That]): append.Out =
append(self, that)
override def toMap: ListMap[String, Schema[_]] = ListMap(head.id -> head.schema) ++ tail.toMap
override def toSeq: Seq[Case[Z, _]] =
Seq(head) ++ tail.toSeq
override def makeAccessors(
whole: Enum[EnumType],
b: AccessorBuilder
): Accessors[EnumType, b.Lens, b.Prism, b.Traversal] =
(b.makePrism(whole, head), tail.makeAccessors(whole, b))
override def toString: String = s"$head :+: $tail"
}
val :+: = Cons
def apply[Z](c: Case[Z, _]*): CaseSet = c.foldRight[CaseSet.Aux[Z]](Empty[Z]()) {
case (c, cs) => Cons(c, cs)
}
def caseOf[A: Schema, Z >: A](
id: String
)(unsafeDeconstruct: Z => A)(construct: A => Z)(isCase: Z => Boolean): Cons[A, Empty[Z], Z] =
Cons(Case(id, Schema[A], unsafeDeconstruct, construct, isCase, Chunk.empty), Empty[Z]())
}
object Cons0 {
type Aux[A, T <: CaseSet.Aux[Z], Z] = CaseSet.Cons[A, T, Z] { type EnumType = Z }
}
sealed trait Append[EnumType, -Left, -Right] {
type Out <: CaseSet.Aux[EnumType]
def apply(left: Left, right: Right): Out
}
object Append extends AppendLowPriority {
import CaseSet._
type WithOut[EnumType, Left, Right, Out0] = Append[EnumType, Left, Right] { type Out = Out0 }
implicit def AppendCons[A, T <: CaseSet.Aux[Z], Z, That <: CaseSet.Aux[Z]](
implicit append: Append[Z, T, That]
): Append.WithOut[Z, Cons[A, T, Z], That, Cons[A, append.Out, Z]] =
new Append[Z, Cons[A, T, Z], That] {
override type Out = Cons[A, append.Out, Z]
def apply(left: Cons[A, T, Z], right: That): Out =
Cons(left.head, append(left.tail, right))
}
}
trait AppendLowPriority extends AppendLowPriority2 {
implicit def AppendEmptyRight[T <: CaseSet.Aux[Z], Z]: Append.WithOut[Z, T, CaseSet.Empty[Z], T] =
new Append[Z, T, CaseSet.Empty[Z]] {
override type Out = T
def apply(left: T, right: CaseSet.Empty[Z]): Out = left
}
}
trait AppendLowPriority2 {
implicit def AppendEmptyLeft[T <: CaseSet.Aux[Z], Z]: Append.WithOut[Z, CaseSet.Empty[Z], T, T] =
new Append[Z, CaseSet.Empty[Z], T] {
override type Out = T
def apply(left: CaseSet.Empty[Z], right: T): Out = right
}
}