Skip to content

Commit 21929a8

Browse files
committed
Move Tuple.scala to src-bootstrapped
1 parent dcd1da6 commit 21929a8

File tree

2 files changed

+326
-0
lines changed

2 files changed

+326
-0
lines changed
Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
// non-bootstrapped version of Tuple.scala
2+
3+
package scala
4+
5+
import annotation.{experimental, showAsInfix}
6+
import compiletime.*
7+
import compiletime.ops.int.*
8+
9+
/** Tuple of arbitrary arity */
10+
sealed trait Tuple extends Product {
11+
import Tuple.*
12+
13+
/** Create a copy of this tuple as an Array */
14+
inline def toArray: Array[Object] =
15+
runtime.Tuples.toArray(this)
16+
17+
/** Create a copy of this tuple as a List */
18+
inline def toList: List[Union[this.type]] =
19+
this.productIterator.toList
20+
.asInstanceOf[List[Union[this.type]]]
21+
22+
/** Create a copy of this tuple as an IArray */
23+
inline def toIArray: IArray[Object] =
24+
runtime.Tuples.toIArray(this)
25+
26+
/** Return a copy of `this` tuple with an element appended */
27+
inline def :* [This >: this.type <: Tuple, L] (x: L): Append[This, L] =
28+
runtime.Tuples.append(x, this).asInstanceOf[Append[This, L]]
29+
30+
/** Return a new tuple by prepending the element to `this` tuple.
31+
* This operation is O(this.size)
32+
*/
33+
inline def *: [H, This >: this.type <: Tuple] (x: H): H *: This =
34+
runtime.Tuples.cons(x, this).asInstanceOf[H *: This]
35+
36+
/** Return a new tuple by concatenating `this` tuple with `that` tuple.
37+
* This operation is O(this.size + that.size)
38+
*/
39+
inline def ++ [This >: this.type <: Tuple](that: Tuple): Concat[This, that.type] =
40+
runtime.Tuples.concat(this, that).asInstanceOf[Concat[This, that.type]]
41+
42+
/** Return the size (or arity) of the tuple */
43+
inline def size[This >: this.type <: Tuple]: Size[This] =
44+
runtime.Tuples.size(this).asInstanceOf[Size[This]]
45+
46+
/** Given two tuples, `(a1, ..., an)` and `(a1, ..., an)`, returns a tuple
47+
* `((a1, b1), ..., (an, bn))`. If the two tuples have different sizes,
48+
* the extra elements of the larger tuple will be disregarded.
49+
* The result is typed as `((A1, B1), ..., (An, Bn))` if at least one of the
50+
* tuple types has a `EmptyTuple` tail. Otherwise the result type is
51+
* `(A1, B1) *: ... *: (Ai, Bi) *: Tuple`
52+
*/
53+
inline def zip[This >: this.type <: Tuple, T2 <: Tuple](t2: T2): Zip[This, T2] =
54+
runtime.Tuples.zip(this, t2).asInstanceOf[Zip[This, T2]]
55+
56+
/** Called on a tuple `(a1, ..., an)`, returns a new tuple `(f(a1), ..., f(an))`.
57+
* The result is typed as `(F[A1], ..., F[An])` if the tuple type is fully known.
58+
* If the tuple is of the form `a1 *: ... *: Tuple` (that is, the tail is not known
59+
* to be the cons type.
60+
*/
61+
inline def map[F[_]](f: [t] => t => F[t]): Map[this.type, F] =
62+
runtime.Tuples.map(this, f).asInstanceOf[Map[this.type, F]]
63+
64+
/** Given a tuple `(a1, ..., am)`, returns the tuple `(a1, ..., an)` consisting
65+
* of its first n elements.
66+
*/
67+
inline def take[This >: this.type <: Tuple](n: Int): Take[This, n.type] =
68+
runtime.Tuples.take(this, n).asInstanceOf[Take[This, n.type]]
69+
70+
71+
/** Given a tuple `(a1, ..., am)`, returns the tuple `(an+1, ..., am)` consisting
72+
* all its elements except the first n ones.
73+
*/
74+
inline def drop[This >: this.type <: Tuple](n: Int): Drop[This, n.type] =
75+
runtime.Tuples.drop(this, n).asInstanceOf[Drop[This, n.type]]
76+
77+
/** Given a tuple `(a1, ..., am)`, returns a pair of the tuple `(a1, ..., an)`
78+
* consisting of the first n elements, and the tuple `(an+1, ..., am)` consisting
79+
* of the remaining elements.
80+
*/
81+
inline def splitAt[This >: this.type <: Tuple](n: Int): Split[This, n.type] =
82+
runtime.Tuples.splitAt(this, n).asInstanceOf[Split[This, n.type]]
83+
84+
/** Given a tuple `(a1, ..., am)`, returns the reversed tuple `(am, ..., a1)`
85+
* consisting all its elements.
86+
*/
87+
@experimental
88+
inline def reverse[This >: this.type <: Tuple]: Reverse[This] =
89+
runtime.Tuples.reverse(this).asInstanceOf[Reverse[This]]
90+
}
91+
92+
object Tuple {
93+
94+
/** Type of a tuple with an element appended */
95+
type Append[X <: Tuple, Y] <: NonEmptyTuple = X match {
96+
case EmptyTuple => Y *: EmptyTuple
97+
case x *: xs => x *: Append[xs, Y]
98+
}
99+
100+
/** Type of the head of a tuple */
101+
type Head[X <: Tuple] = X match {
102+
case x *: _ => x
103+
}
104+
105+
/** Type of the initial part of the tuple without its last element */
106+
type Init[X <: Tuple] <: Tuple = X match {
107+
case _ *: EmptyTuple => EmptyTuple
108+
case x *: xs =>
109+
x *: Init[xs]
110+
}
111+
112+
/** Type of the tail of a tuple */
113+
type Tail[X <: Tuple] <: Tuple = X match {
114+
case _ *: xs => xs
115+
}
116+
117+
/** Type of the last element of a tuple */
118+
type Last[X <: Tuple] = X match {
119+
case x *: EmptyTuple => x
120+
case _ *: xs => Last[xs]
121+
}
122+
123+
/** Type of the concatenation of two tuples */
124+
type Concat[X <: Tuple, +Y <: Tuple] <: Tuple = X match {
125+
case EmptyTuple => Y
126+
case x1 *: xs1 => x1 *: Concat[xs1, Y]
127+
}
128+
129+
/** Type of the element at position N in the tuple X */
130+
type Elem[X <: Tuple, N <: Int] = X match {
131+
case x *: xs =>
132+
N match {
133+
case 0 => x
134+
case S[n1] => Elem[xs, n1]
135+
}
136+
}
137+
138+
/** Literal constant Int size of a tuple */
139+
type Size[X <: Tuple] <: Int = X match {
140+
case EmptyTuple => 0
141+
case x *: xs => S[Size[xs]]
142+
}
143+
144+
/** Fold a tuple `(T1, ..., Tn)` into `F[T1, F[... F[Tn, Z]...]]]` */
145+
type Fold[Tup <: Tuple, Z, F[_, _]] = Tup match
146+
case EmptyTuple => Z
147+
case h *: t => F[h, Fold[t, Z, F]]
148+
149+
/** Converts a tuple `(T1, ..., Tn)` to `(F[T1], ..., F[Tn])` */
150+
type Map[Tup <: Tuple, F[_ <: Union[Tup]]] <: Tuple = Tup match {
151+
case EmptyTuple => EmptyTuple
152+
case h *: t => F[h] *: Map[t, F]
153+
}
154+
155+
/** Converts a tuple `(T1, ..., Tn)` to a flattened `(..F[T1], ..., ..F[Tn])` */
156+
type FlatMap[Tup <: Tuple, F[_ <: Union[Tup]] <: Tuple] <: Tuple = Tup match {
157+
case EmptyTuple => EmptyTuple
158+
case h *: t => Concat[F[h], FlatMap[t, F]]
159+
}
160+
161+
/** Filters out those members of the tuple for which the predicate `P` returns `false`.
162+
* A predicate `P[X]` is a type that can be either `true` or `false`. For example:
163+
* ```scala
164+
* type IsString[x] <: Boolean = x match {
165+
* case String => true
166+
* case _ => false
167+
* }
168+
* summon[Tuple.Filter[(1, "foo", 2, "bar"), IsString] =:= ("foo", "bar")]
169+
* ```
170+
* @syntax markdown
171+
*/
172+
type Filter[Tup <: Tuple, P[_] <: Boolean] <: Tuple = Tup match {
173+
case EmptyTuple => EmptyTuple
174+
case h *: t => P[h] match {
175+
case true => h *: Filter[t, P]
176+
case false => Filter[t, P]
177+
}
178+
}
179+
180+
/** Given two tuples, `A1 *: ... *: An * At` and `B1 *: ... *: Bn *: Bt`
181+
* where at least one of `At` or `Bt` is `EmptyTuple` or `Tuple`,
182+
* returns the tuple type `(A1, B1) *: ... *: (An, Bn) *: Ct`
183+
* where `Ct` is `EmptyTuple` if `At` or `Bt` is `EmptyTuple`, otherwise `Ct` is `Tuple`.
184+
*/
185+
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple = (T1, T2) match {
186+
case (h1 *: t1, h2 *: t2) => (h1, h2) *: Zip[t1, t2]
187+
case (EmptyTuple, _) => EmptyTuple
188+
case (_, EmptyTuple) => EmptyTuple
189+
case _ => Tuple
190+
}
191+
192+
/** Converts a tuple `(F[T1], ..., F[Tn])` to `(T1, ... Tn)` */
193+
type InverseMap[X <: Tuple, F[_]] <: Tuple = X match {
194+
case F[x] *: t => x *: InverseMap[t, F]
195+
case EmptyTuple => EmptyTuple
196+
}
197+
198+
/** Implicit evidence. IsMappedBy[F][X] is present in the implicit scope iff
199+
* X is a tuple for which each element's type is constructed via `F`. E.g.
200+
* (F[A1], ..., F[An]), but not `(F[A1], B2, ..., F[An])` where B2 does not
201+
* have the shape of `F[A]`.
202+
*/
203+
type IsMappedBy[F[_]] = [X <: Tuple] =>> X =:= Map[InverseMap[X, F], F]
204+
205+
/** Type of the reversed tuple */
206+
@experimental
207+
type Reverse[X <: Tuple] = ReverseOnto[X, EmptyTuple]
208+
209+
/** Prepends all elements of a tuple in reverse order onto the other tuple */
210+
@experimental
211+
type ReverseOnto[From <: Tuple, +To <: Tuple] <: Tuple = From match
212+
case x *: xs => ReverseOnto[xs, x *: To]
213+
case EmptyTuple => To
214+
215+
/** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */
216+
type Take[T <: Tuple, N <: Int] <: Tuple = N match {
217+
case 0 => EmptyTuple
218+
case S[n1] => T match {
219+
case EmptyTuple => EmptyTuple
220+
case x *: xs => x *: Take[xs, n1]
221+
}
222+
}
223+
224+
/** Transforms a tuple `(T1, ..., Tn)` into `(Ti+1, ..., Tn)`. */
225+
type Drop[T <: Tuple, N <: Int] <: Tuple = N match {
226+
case 0 => T
227+
case S[n1] => T match {
228+
case EmptyTuple => EmptyTuple
229+
case x *: xs => Drop[xs, n1]
230+
}
231+
}
232+
233+
/** Splits a tuple (T1, ..., Tn) into a pair of two tuples `(T1, ..., Ti)` and
234+
* `(Ti+1, ..., Tn)`.
235+
*/
236+
type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])
237+
238+
/** Given a tuple `(T1, ..., Tn)`, returns a union of its
239+
* member types: `T1 | ... | Tn`. Returns `Nothing` if the tuple is empty.
240+
*/
241+
type Union[T <: Tuple] = Fold[T, Nothing, [x, y] =>> x | y]
242+
243+
/** Empty tuple */
244+
def apply(): EmptyTuple = EmptyTuple
245+
246+
/** Tuple with one element */
247+
def apply[T](x: T): T *: EmptyTuple = Tuple1(x)
248+
249+
/** Matches an empty tuple. */
250+
def unapply(x: EmptyTuple): true = true
251+
252+
/** Convert an array into a tuple of unknown arity and types */
253+
def fromArray[T](xs: Array[T]): Tuple = {
254+
val xs2 = xs match {
255+
case xs: Array[Object] => xs
256+
case xs => xs.map(_.asInstanceOf[Object])
257+
}
258+
runtime.Tuples.fromArray(xs2)
259+
}
260+
261+
/** Convert an immutable array into a tuple of unknown arity and types */
262+
def fromIArray[T](xs: IArray[T]): Tuple = {
263+
val xs2: IArray[Object] = xs match {
264+
case xs: IArray[Object] @unchecked => xs
265+
case _ =>
266+
xs.map(_.asInstanceOf[Object])
267+
}
268+
runtime.Tuples.fromIArray(xs2)
269+
}
270+
271+
/** Convert a Product into a tuple of unknown arity and types */
272+
def fromProduct(product: Product): Tuple =
273+
runtime.Tuples.fromProduct(product)
274+
275+
def fromProductTyped[P <: Product](p: P)(using m: scala.deriving.Mirror.ProductOf[P]): m.MirroredElemTypes =
276+
runtime.Tuples.fromProduct(p).asInstanceOf[m.MirroredElemTypes]
277+
278+
given canEqualEmptyTuple: CanEqual[EmptyTuple, EmptyTuple] = CanEqual.derived
279+
given canEqualTuple[H1, T1 <: Tuple, H2, T2 <: Tuple](
280+
using eqHead: CanEqual[H1, H2], eqTail: CanEqual[T1, T2]
281+
): CanEqual[H1 *: T1, H2 *: T2] = CanEqual.derived
282+
}
283+
284+
/** A tuple of 0 elements */
285+
type EmptyTuple = EmptyTuple.type
286+
287+
/** A tuple of 0 elements. */
288+
case object EmptyTuple extends Tuple {
289+
override def toString(): String = "()"
290+
}
291+
292+
/** Tuple of arbitrary non-zero arity */
293+
sealed trait NonEmptyTuple extends Tuple {
294+
import Tuple.*
295+
296+
/** Get the i-th element of this tuple.
297+
* Equivalent to productElement but with a precise return type.
298+
*/
299+
inline def apply[This >: this.type <: NonEmptyTuple](n: Int): Elem[This, n.type] =
300+
runtime.Tuples.apply(this, n).asInstanceOf[Elem[This, n.type]]
301+
302+
/** Get the head of this tuple */
303+
inline def head[This >: this.type <: NonEmptyTuple]: Head[This] =
304+
runtime.Tuples.apply(this, 0).asInstanceOf[Head[This]]
305+
306+
/** Get the initial part of the tuple without its last element */
307+
inline def init[This >: this.type <: NonEmptyTuple]: Init[This] =
308+
runtime.Tuples.init(this).asInstanceOf[Init[This]]
309+
310+
/** Get the last of this tuple */
311+
inline def last[This >: this.type <: NonEmptyTuple]: Last[This] =
312+
runtime.Tuples.last(this).asInstanceOf[Last[This]]
313+
314+
/** Get the tail of this tuple.
315+
* This operation is O(this.size)
316+
*/
317+
inline def tail[This >: this.type <: NonEmptyTuple]: Tail[This] =
318+
runtime.Tuples.tail(this).asInstanceOf[Tail[This]]
319+
}
320+
321+
@showAsInfix
322+
sealed abstract class *:[+H, +T <: Tuple] extends NonEmptyTuple
323+
324+
object *: {
325+
def unapply[H, T <: Tuple](x: H *: T): (H, T) = (x.head, x.tail)
326+
}

0 commit comments

Comments
 (0)