-
-
Notifications
You must be signed in to change notification settings - Fork 609
/
HList.scala
147 lines (127 loc) · 4.1 KB
/
HList.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package slick.collection.heterogeneous
import scala.annotation.unchecked.uncheckedVariance as uv
import scala.reflect.ClassTag
import slick.lifted.{MappedScalaProductShape, Shape, ShapeLevel}
/** A heterogenous list where each element has its own type. */
sealed abstract class HList extends Product {
/** The type of this HList object */
type Self <: HList
/** The type of the first element */
type Head
/** The type of the tail of this HList */
type Tail <: HList
/** The type of prepending an element of type E to this HList */
type :: [E] = HCons[E, Self]
/** Get the first element, or throw a NoSuchElementException if this HList is empty. */
def head: Head
/** Get the tail of the list, or throw a NoSuchElementException if this HList is empty. */
def tail: Tail
/** Return this HList typed as `Self`/ */
def self: Self
/** Check if this HList is non-empty. */
def nonEmpty: Boolean
/** Convert this HList to a `List[Any]`. */
def toList: List[Any]
/** Check if this list is empty. */
final def isEmpty = !nonEmpty
/** Get the length of this list. */
@inline final def length: Int = productArity
/** Get the length of this list as an `Int`. */
final def productArity: Int = {
var i = 0
var h = this
while(h.nonEmpty) {
i += 1
h = h.tail
}
i
}
/** Prepend an element to this HList, returning a new HList. */
@inline final def :: [E](elem: E): :: [E] = new HCons[E, Self](elem, this.asInstanceOf[Self])
/** Drop the first `n` elements from this HList. */
final def drop(i: Int): HList = {
var h = this
var ii = i
while(ii > 0) {
ii -= 1
h = h.tail
}
h
}
final def productElement(i: Int): Any = drop(i).head
/** Evaluate a function for each element of this HList. */
final def foreach(f: Any => Unit): Unit = {
var h = this
while(h.nonEmpty) {
f(h.head)
h = h.tail
}
}
override final def toString = {
val b = new StringBuffer
foreach { v =>
v match {
case _: HList =>
b.append("(").append(v).append(")")
case _ =>
b.append(v)
}
b.append(" :: ") }
b.append("HNil").toString
}
override final lazy val hashCode: Int = toList.hashCode
override final def equals(that: Any) = that match {
case that: HList => toList == that.toList
case _ => false
}
final def canEqual(that: Any) = that.isInstanceOf[HList]
}
object HList {
import syntax.*
final class HListShape[
Level <: ShapeLevel,
M <: HList,
U <: HList : ClassTag,
P <: HList
](val shapes: Seq[Shape[? <: ShapeLevel, ?, ?, ?]]) extends MappedScalaProductShape[Level, HList, M, U, P] {
override def buildValue(elems: IndexedSeq[Any]): HList = elems.foldRight(HNil: HList)(_ :: _)
override def copy(shapes: Seq[Shape[? <: ShapeLevel, ?, ?, ?]]): HListShape[Level, Nothing, U, Nothing] =
new HListShape(shapes)
}
implicit def hnilShape[Level <: ShapeLevel]: HListShape[Level, HNil.type, HNil.type, HNil.type] =
new HListShape[Level, HNil.type, HNil.type, HNil.type](Nil)
implicit def hconsShape[
Level <: ShapeLevel,
M1,
M2 <: HList,
U1,
U2 <: HList,
P1,
P2 <: HList
](implicit s1: Shape[? <: Level, M1, U1, P1],
s2: HListShape[? <: Level, M2, U2, P2]): HListShape[Level, M1 :: M2, U1 :: U2, P1 :: P2] =
new HListShape[Level, M1 :: M2, U1 :: U2, P1 :: P2](s1 +: s2.shapes)
}
/** A cons cell of an `HList`, containing an element type and the element */
final class HCons[+H, +T <: HList](val head: H, val tail: T) extends HList {
type Self = HCons[H @uv, T @uv]
type Head = H @uv
type Tail = T @uv
def self = this
def toList: List[Any] = head :: tail.toList
def nonEmpty = true
}
object HCons {
def unapply[H, T <: HList](l: HCons[H, T]) = Some((l.head, l.tail))
}
/** The empty `HList` */
object HNil extends HList {
type Self = HNil.type
type Head = Nothing
type Tail = Nothing
def self = HNil
def head = throw new NoSuchElementException("HNil.head")
def tail = throw new NoSuchElementException("HNil.tail")
override def toList: Nil.type = Nil
def nonEmpty = false
}