Skip to content

Commit 148bd5b

Browse files
committed
Move Tuple to src-{non-}bootstrapped library
1 parent 587945b commit 148bd5b

File tree

2 files changed

+217
-0
lines changed

2 files changed

+217
-0
lines changed
Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
package scala
2+
import annotation.showAsInfix
3+
import compiletime._
4+
import internal._
5+
6+
// non-bootstrapped
7+
8+
/** Tuple of arbitrary arity */
9+
sealed trait Tuple extends Any {
10+
import Tuple._
11+
12+
/** Create a copy this tuple as an Array */
13+
inline def toArray: Array[Object] =
14+
scala.runtime.Tuple.toArray(this)
15+
16+
/** Create a copy this tuple as an IArray */
17+
inline def toIArray: IArray[Object] =
18+
scala.runtime.Tuple.toIArray(this)
19+
20+
/** Return a new tuple by prepending the element to `this` tuple.
21+
* This operation is O(this.size)
22+
*/
23+
inline def *: [H, This >: this.type <: Tuple] (x: H): H *: This =
24+
scala.runtime.Tuple.cons(x, this).asInstanceOf[H *: This]
25+
26+
/** Return a new tuple by concatenating `this` tuple with `that` tuple.
27+
* This operation is O(this.size + that.size)
28+
*/
29+
inline def ++ [This >: this.type <: Tuple](that: Tuple): Concat[This, that.type] =
30+
scala.runtime.Tuple.concat(this, that).asInstanceOf[Concat[This, that.type]]
31+
32+
/** Return the size (or arity) of the tuple */
33+
inline def size[This >: this.type <: Tuple]: Size[This] =
34+
scala.runtime.Tuple.size(this).asInstanceOf[Size[This]]
35+
36+
/** Given two tuples, `(a1, ..., an)` and `(a1, ..., an)`, returns a tuple
37+
* `((a1, b1), ..., (an, bn))`. If the two tuples have different sizes,
38+
* the extra elements of the larger tuple will be disregarded.
39+
* The result is typed as `((A1, B1), ..., (An, Bn))` if at least one of the
40+
* tuple types has a `Unit` tail. Otherwise the result type is
41+
* `(A1, B1) *: ... *: (Ai, Bi) *: Tuple`
42+
*/
43+
inline def zip[This >: this.type <: Tuple, T2 <: Tuple](t2: T2): Zip[This, T2] =
44+
scala.runtime.Tuple.zip(this, t2).asInstanceOf[Zip[This, T2]]
45+
46+
/** Called on a tuple `(a1, ..., an)`, returns a new tuple `(f(a1), ..., f(an))`.
47+
* The result is typed as `(F[A1], ..., F[An])` if the tuple type is fully known.
48+
* If the tuple is of the form `a1 *: ... *: Tuple` (that is, the tail is not known
49+
* to be the cons type.
50+
*/
51+
inline def map[F[_]](f: [t] => t => F[t]): Map[this.type, F] =
52+
scala.runtime.Tuple.map(this, f).asInstanceOf[Map[this.type, F]]
53+
54+
/** Given a tuple `(a1, ..., am)`, returns the tuple `(a1, ..., an)` consisting
55+
* of its first n elements.
56+
*/
57+
inline def take[This >: this.type <: Tuple](n: Int): Take[This, n.type] =
58+
scala.runtime.Tuple.take(this, n).asInstanceOf[Take[This, n.type]]
59+
60+
61+
/** Given a tuple `(a1, ..., am)`, returns the tuple `(an+1, ..., am)` consisting
62+
* all its elements except the first n ones.
63+
*/
64+
inline def drop[This >: this.type <: Tuple](n: Int): Drop[This, n.type] =
65+
scala.runtime.Tuple.drop(this, n).asInstanceOf[Drop[This, n.type]]
66+
67+
/** Given a tuple `(a1, ..., am)`, returns a pair of the tuple `(a1, ..., an)`
68+
* consisting of the first n elements, and the tuple `(an+1, ..., am)` consisting
69+
* of the remaining elements.
70+
*/
71+
inline def splitAt[This >: this.type <: Tuple](n: Int): Split[This, n.type] =
72+
scala.runtime.Tuple.splitAt(this, n).asInstanceOf[Split[This, n.type]]
73+
}
74+
75+
object Tuple {
76+
77+
/** Type of the head of a tuple */
78+
type Head[X <: NonEmptyTuple] = X match {
79+
case x *: _ => x
80+
}
81+
82+
/** Type of the tail of a tuple */
83+
type Tail[X <: NonEmptyTuple] <: Tuple = X match {
84+
case _ *: xs => xs
85+
}
86+
87+
/** Type of the concatenation of two tuples */
88+
type Concat[X <: Tuple, +Y <: Tuple] <: Tuple = X match {
89+
case Unit => Y
90+
case x1 *: xs1 => x1 *: Concat[xs1, Y]
91+
}
92+
93+
/** Type of the element a position N in the tuple X */
94+
type Elem[X <: Tuple, N <: Int] = X match {
95+
case x *: xs =>
96+
N match {
97+
case 0 => x
98+
case S[n1] => Elem[xs, n1]
99+
}
100+
}
101+
102+
/** Literal constant Int size of a tuple */
103+
type Size[X <: Tuple] <: Int = X match {
104+
case Unit => 0
105+
case x *: xs => S[Size[xs]]
106+
}
107+
108+
/** Converts a tuple `(T1, ..., Tn)` to `(F[T1], ..., F[Tn])` */
109+
type Map[Tup <: Tuple, F[_]] <: Tuple = Tup match {
110+
case Unit => Unit
111+
case h *: t => F[h] *: Map[t, F]
112+
}
113+
114+
/** Given two tuples, `A1 *: ... *: An * At` and `B1 *: ... *: Bn *: Bt`
115+
* where at least one of `At` or `Bt` is `Unit` or `Tuple`,
116+
* returns the tuple type `(A1, B1) *: ... *: (An, Bn) *: Ct`
117+
* where `Ct` is `Unit` if `At` or `Bt` is `Unit`, otherwise `Ct` is `Tuple`.
118+
*/
119+
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple = (T1, T2) match {
120+
case (h1 *: t1, h2 *: t2) => (h1, h2) *: Zip[t1, t2]
121+
case (Unit, _) => Unit
122+
case (_, Unit) => Unit
123+
case _ => Tuple
124+
}
125+
126+
/** Converts a tuple `(F[T1], ..., F[Tn])` to `(T1, ... Tn)` */
127+
type InverseMap[X <: Tuple, F[_]] <: Tuple = X match {
128+
case F[x] *: t => x *: InverseMap[t, F]
129+
case Unit => Unit
130+
}
131+
132+
/** Implicit evidence. IsMappedBy[F][X] is present in the implicit scope iff
133+
* X is a tuple for which each element's type is constructed via `F`. E.g.
134+
* (F[A1], ..., F[An]), but not `(F[A1], B2, ..., F[An])` where B2 does not
135+
* have the shape of `F[A]`.
136+
*/
137+
type IsMappedBy[F[_]] = [X <: Tuple] =>> X =:= Map[InverseMap[X, F], F]
138+
139+
/** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */
140+
type Take[T <: Tuple, N <: Int] <: Tuple = N match {
141+
case 0 => Unit
142+
case S[n1] => T match {
143+
case Unit => Unit
144+
case x *: xs => x *: Take[xs, n1]
145+
}
146+
}
147+
148+
/** Transforms a tuple `(T1, ..., Tn)` into `(Ti+1, ..., Tn)`. */
149+
type Drop[T <: Tuple, N <: Int] <: Tuple = N match {
150+
case 0 => T
151+
case S[n1] => T match {
152+
case Unit => Unit
153+
case x *: xs => Drop[xs, n1]
154+
}
155+
}
156+
157+
/** Splits a tuple (T1, ..., Tn) into a pair of two tuples `(T1, ..., Ti)` and
158+
* `(Ti+1, ..., Tn)`.
159+
*/
160+
type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])
161+
162+
/** Convert an array into a tuple of unknown arity and types */
163+
def fromArray[T](xs: Array[T]): Tuple = {
164+
val xs2 = xs match {
165+
case xs: Array[Object] => xs
166+
case xs => xs.map(_.asInstanceOf[Object])
167+
}
168+
scala.runtime.Tuple.fromArray(xs2).asInstanceOf[Tuple]
169+
}
170+
171+
/** Convert an immutable array into a tuple of unknown arity and types */
172+
def fromIArray[T](xs: IArray[T]): Tuple = {
173+
val xs2: IArray[Object] = xs match {
174+
case xs: IArray[Object] => xs
175+
case xs =>
176+
// TODO support IArray.map
177+
xs.asInstanceOf[Array[T]].map(_.asInstanceOf[Object]).asInstanceOf[IArray[Object]]
178+
}
179+
scala.runtime.Tuple.fromIArray(xs2).asInstanceOf[Tuple]
180+
}
181+
182+
/** Convert a Product into a tuple of unknown arity and types */
183+
def fromProduct(product: Product): Tuple =
184+
scala.runtime.Tuple.fromProduct(product)
185+
186+
def fromProductTyped[P <: Product](p: P)(using m: scala.deriving.Mirror.ProductOf[P]): m.MirroredElemTypes =
187+
Tuple.fromArray(p.productIterator.toArray).asInstanceOf[m.MirroredElemTypes] // TODO use toIArray of Object to avoid double/triple array copy
188+
}
189+
190+
/** Tuple of arbitrary non-zero arity */
191+
sealed trait NonEmptyTuple extends Tuple with Product {
192+
import Tuple._
193+
194+
/** Get the i-th element of this tuple.
195+
* Equivalent to productElement but with a precise return type.
196+
*/
197+
inline def apply[This >: this.type <: NonEmptyTuple](n: Int): Elem[This, n.type] =
198+
scala.runtime.Tuple.apply(this, n).asInstanceOf[Elem[This, n.type]]
199+
200+
/** Get the head of this tuple */
201+
inline def head[This >: this.type <: NonEmptyTuple]: Head[This] =
202+
scala.runtime.Tuple.apply(this, 0).asInstanceOf[Head[This]]
203+
204+
/** Get the tail of this tuple.
205+
* This operation is O(this.size)
206+
*/
207+
inline def tail[This >: this.type <: NonEmptyTuple]: Tail[This] =
208+
scala.runtime.Tuple.tail(this).asInstanceOf[Tail[This]]
209+
210+
}
211+
212+
@showAsInfix
213+
sealed abstract class *:[+H, +T <: Tuple] extends NonEmptyTuple
214+
215+
object *: {
216+
def unapply[H, T <: Tuple](x: H *: T): (H, T) = (x.head, x.tail)
217+
}

0 commit comments

Comments
 (0)