scala.Tuple.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scala3-library_sjs1_3 Show documentation
Show all versions of scala3-library_sjs1_3 Show documentation
scala3-library-bootstrappedJS
package scala
import annotation.showAsInfix
import compiletime.*
import compiletime.ops.int.*
/** Tuple of arbitrary arity */
sealed trait Tuple extends Product {
import Tuple.*
/** Create a copy of this tuple as an Array */
inline def toArray: Array[Object] =
runtime.Tuples.toArray(this)
/** Create a copy of this tuple as a List */
inline def toList: List[Union[this.type]] =
this.productIterator.toList
.asInstanceOf[List[Union[this.type]]]
/** Create a copy of this tuple as an IArray */
inline def toIArray: IArray[Object] =
runtime.Tuples.toIArray(this)
/** Return a copy of `this` tuple with an element appended */
inline def :* [This >: this.type <: Tuple, L] (x: L): This :* L =
runtime.Tuples.append(x, this).asInstanceOf[This :* L]
/** Return a new tuple by prepending the element to `this` tuple.
* This operation is O(this.size)
*/
inline def *: [H, This >: this.type <: Tuple] (x: H): H *: This =
runtime.Tuples.cons(x, this).asInstanceOf[H *: This]
/** Get the i-th element of this tuple.
* Equivalent to productElement but with a precise return type.
*/
inline def apply[This >: this.type <: Tuple](n: Int): Elem[This, n.type] =
runtime.Tuples.apply(this, n).asInstanceOf[Elem[This, n.type]]
/** Get the head of this tuple */
inline def head[This >: this.type <: Tuple]: Head[This] =
runtime.Tuples.apply(this, 0).asInstanceOf[Head[This]]
/** Get the initial part of the tuple without its last element */
inline def init[This >: this.type <: Tuple]: Init[This] =
runtime.Tuples.init(this).asInstanceOf[Init[This]]
/** Get the last of this tuple */
inline def last[This >: this.type <: Tuple]: Last[This] =
runtime.Tuples.last(this).asInstanceOf[Last[This]]
/** Get the tail of this tuple.
* This operation is O(this.size)
*/
inline def tail[This >: this.type <: Tuple]: Tail[This] =
runtime.Tuples.tail(this).asInstanceOf[Tail[This]]
/** Return a new tuple by concatenating `this` tuple with `that` tuple.
* This operation is O(this.size + that.size)
*/
inline def ++ [This >: this.type <: Tuple](that: Tuple): This ++ that.type =
runtime.Tuples.concat(this, that).asInstanceOf[This ++ that.type]
/** Return the size (or arity) of the tuple */
inline def size[This >: this.type <: Tuple]: Size[This] =
runtime.Tuples.size(this).asInstanceOf[Size[This]]
/** Given two tuples, `(a1, ..., an)` and `(a1, ..., an)`, returns a tuple
* `((a1, b1), ..., (an, bn))`. If the two tuples have different sizes,
* the extra elements of the larger tuple will be disregarded.
* The result is typed as `((A1, B1), ..., (An, Bn))` if at least one of the
* tuple types has a `EmptyTuple` tail. Otherwise the result type is
* `(A1, B1) *: ... *: (Ai, Bi) *: Tuple`
*/
inline def zip[This >: this.type <: Tuple, T2 <: Tuple](t2: T2): Zip[This, T2] =
runtime.Tuples.zip(this, t2).asInstanceOf[Zip[This, T2]]
/** Called on a tuple `(a1, ..., an)`, returns a new tuple `(f(a1), ..., f(an))`.
* The result is typed as `(F[A1], ..., F[An])` if the tuple type is fully known.
* If the tuple is of the form `a1 *: ... *: Tuple` (that is, the tail is not known
* to be the cons type.
*/
inline def map[F[_]](f: [t] => t => F[t]): Map[this.type, F] =
runtime.Tuples.map(this, f).asInstanceOf[Map[this.type, F]]
/** Given a tuple `(a1, ..., am)`, returns the tuple `(a1, ..., an)` consisting
* of its first n elements.
*/
inline def take[This >: this.type <: Tuple](n: Int): Take[This, n.type] =
runtime.Tuples.take(this, n).asInstanceOf[Take[This, n.type]]
/** Given a tuple `(a1, ..., am)`, returns the tuple `(an+1, ..., am)` consisting
* all its elements except the first n ones.
*/
inline def drop[This >: this.type <: Tuple](n: Int): Drop[This, n.type] =
runtime.Tuples.drop(this, n).asInstanceOf[Drop[This, n.type]]
/** Given a tuple `(a1, ..., am)`, returns a pair of the tuple `(a1, ..., an)`
* consisting of the first n elements, and the tuple `(an+1, ..., am)` consisting
* of the remaining elements.
*/
inline def splitAt[This >: this.type <: Tuple](n: Int): Split[This, n.type] =
runtime.Tuples.splitAt(this, n).asInstanceOf[Split[This, n.type]]
/** Given a tuple `(a1, ..., am)`, returns the reversed tuple `(am, ..., a1)`
* consisting all its elements.
*/
inline def reverse[This >: this.type <: Tuple]: Reverse[This] =
runtime.Tuples.reverse(this).asInstanceOf[Reverse[This]]
}
object Tuple {
/** Type of a tuple with an element appended */
type Append[X <: Tuple, Y] <: NonEmptyTuple = X match {
case EmptyTuple => Y *: EmptyTuple
case x *: xs => x *: Append[xs, Y]
}
/** An infix shorthand for `Append[X, Y]` */
infix type :*[X <: Tuple, Y] = Append[X, Y]
/** Type of the head of a tuple */
type Head[X <: Tuple] = X match {
case x *: _ => x
}
/** Type of the initial part of the tuple without its last element */
type Init[X <: Tuple] <: Tuple = X match {
case _ *: EmptyTuple => EmptyTuple
case x *: xs =>
x *: Init[xs]
}
/** Type of the tail of a tuple */
type Tail[X <: Tuple] <: Tuple = X match {
case _ *: xs => xs
}
/** Type of the last element of a tuple */
type Last[X <: Tuple] = X match {
case x *: EmptyTuple => x
case _ *: xs => Last[xs]
}
/** Type of the concatenation of two tuples */
type Concat[X <: Tuple, +Y <: Tuple] <: Tuple = X match {
case EmptyTuple => Y
case x1 *: xs1 => x1 *: Concat[xs1, Y]
}
/** An infix shorthand for `Concat[X, Y]` */
infix type ++[X <: Tuple, +Y <: Tuple] = Concat[X, Y]
/** Type of the element at position N in the tuple X */
type Elem[X <: Tuple, N <: Int] = X match {
case x *: xs =>
N match {
case 0 => x
case S[n1] => Elem[xs, n1]
}
}
/** Literal constant Int size of a tuple */
type Size[X <: Tuple] <: Int = X match {
case EmptyTuple => 0
case x *: xs => S[Size[xs]]
}
/** Fold a tuple `(T1, ..., Tn)` into `F[T1, F[... F[Tn, Z]...]]]` */
type Fold[Tup <: Tuple, Z, F[_, _]] = Tup match
case EmptyTuple => Z
case h *: t => F[h, Fold[t, Z, F]]
/** Converts a tuple `(T1, ..., Tn)` to `(F[T1], ..., F[Tn])` */
type Map[Tup <: Tuple, F[_ <: Union[Tup]]] <: Tuple = Tup match {
case EmptyTuple => EmptyTuple
case h *: t => F[h] *: Map[t, F]
}
/** Converts a tuple `(T1, ..., Tn)` to a flattened `(..F[T1], ..., ..F[Tn])` */
type FlatMap[Tup <: Tuple, F[_ <: Union[Tup]] <: Tuple] <: Tuple = Tup match {
case EmptyTuple => EmptyTuple
case h *: t => Concat[F[h], FlatMap[t, F]]
}
/** Filters out those members of the tuple for which the predicate `P` returns `false`.
* A predicate `P[X]` is a type that can be either `true` or `false`. For example:
* ```scala
* type IsString[x] <: Boolean = x match {
* case String => true
* case _ => false
* }
* summon[Tuple.Filter[(1, "foo", 2, "bar"), IsString] =:= ("foo", "bar")]
* ```
* @syntax markdown
*/
type Filter[Tup <: Tuple, P[_ <: Union[Tup]] <: Boolean] <: Tuple = Tup match {
case EmptyTuple => EmptyTuple
case h *: t => P[h] match {
case true => h *: Filter[t, P]
case false => Filter[t, P]
}
}
/** Given two tuples, `A1 *: ... *: An * At` and `B1 *: ... *: Bn *: Bt`
* where at least one of `At` or `Bt` is `EmptyTuple` or `Tuple`,
* returns the tuple type `(A1, B1) *: ... *: (An, Bn) *: Ct`
* where `Ct` is `EmptyTuple` if `At` or `Bt` is `EmptyTuple`, otherwise `Ct` is `Tuple`.
*/
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple = (T1, T2) match {
case (h1 *: t1, h2 *: t2) => (h1, h2) *: Zip[t1, t2]
case (EmptyTuple, _) => EmptyTuple
case (_, EmptyTuple) => EmptyTuple
case _ => Tuple
}
/** Converts a tuple `(F[T1], ..., F[Tn])` to `(T1, ... Tn)` */
type InverseMap[X <: Tuple, F[_]] <: Tuple = X match {
case F[x] *: t => x *: InverseMap[t, F]
case EmptyTuple => EmptyTuple
}
/** Implicit evidence. IsMappedBy[F][X] is present in the implicit scope iff
* X is a tuple for which each element's type is constructed via `F`. E.g.
* (F[A1], ..., F[An]), but not `(F[A1], B2, ..., F[An])` where B2 does not
* have the shape of `F[A]`.
*/
type IsMappedBy[F[_]] = [X <: Tuple] =>> X =:= Map[InverseMap[X, F], F]
/** Type of the reversed tuple */
type Reverse[X <: Tuple] = ReverseOnto[X, EmptyTuple]
/** Prepends all elements of a tuple in reverse order onto the other tuple */
type ReverseOnto[From <: Tuple, +To <: Tuple] <: Tuple = From match
case x *: xs => ReverseOnto[xs, x *: To]
case EmptyTuple => To
/** Transforms a tuple `(T1, ..., Tn)` into `(T1, ..., Ti)`. */
type Take[T <: Tuple, N <: Int] <: Tuple = N match {
case 0 => EmptyTuple
case S[n1] => T match {
case EmptyTuple => EmptyTuple
case x *: xs => x *: Take[xs, n1]
}
}
/** Transforms a tuple `(T1, ..., Tn)` into `(Ti+1, ..., Tn)`. */
type Drop[T <: Tuple, N <: Int] <: Tuple = N match {
case 0 => T
case S[n1] => T match {
case EmptyTuple => EmptyTuple
case x *: xs => Drop[xs, n1]
}
}
/** Splits a tuple (T1, ..., Tn) into a pair of two tuples `(T1, ..., Ti)` and
* `(Ti+1, ..., Tn)`.
*/
type Split[T <: Tuple, N <: Int] = (Take[T, N], Drop[T, N])
/** Given a tuple `(T1, ..., Tn)`, returns a union of its
* member types: `T1 | ... | Tn`. Returns `Nothing` if the tuple is empty.
*/
type Union[T <: Tuple] = Fold[T, Nothing, [x, y] =>> x | y]
/** A type level Boolean indicating whether the tuple `X` has an element
* that matches `Y`.
* @pre The elements of `X` are assumed to be singleton types
*/
type Contains[X <: Tuple, Y] <: Boolean = X match
case Y *: _ => true
case _ *: xs => Contains[xs, Y]
case EmptyTuple => false
/** A type level Boolean indicating whether the type `Y` contains
* none of the elements of `X`.
* @pre The elements of `X` and `Y` are assumed to be singleton types
*/
type Disjoint[X <: Tuple, Y <: Tuple] <: Boolean = X match
case x *: xs => Contains[Y, x] match
case true => false
case false => Disjoint[xs, Y]
case EmptyTuple => true
/** Empty tuple */
def apply(): EmptyTuple = EmptyTuple
/** Tuple with one element */
def apply[T](x: T): T *: EmptyTuple = Tuple1(x)
/** Matches an empty tuple. */
def unapply(x: EmptyTuple): true = true
/** Convert an array into a tuple of unknown arity and types */
def fromArray[T](xs: Array[T]): Tuple = {
val xs2 = xs match {
case xs: Array[Object] => xs
case xs => xs.map(_.asInstanceOf[Object])
}
runtime.Tuples.fromArray(xs2)
}
/** Convert an immutable array into a tuple of unknown arity and types */
def fromIArray[T](xs: IArray[T]): Tuple = {
val xs2: IArray[Object] = xs match {
case xs: IArray[Object] @unchecked => xs
case _ =>
xs.map(_.asInstanceOf[Object])
}
runtime.Tuples.fromIArray(xs2)
}
/** Convert a Product into a tuple of unknown arity and types */
def fromProduct(product: Product): Tuple =
runtime.Tuples.fromProduct(product)
def fromProductTyped[P <: Product](p: P)(using m: scala.deriving.Mirror.ProductOf[P]): m.MirroredElemTypes =
runtime.Tuples.fromProduct(p).asInstanceOf[m.MirroredElemTypes]
given canEqualEmptyTuple: CanEqual[EmptyTuple, EmptyTuple] = CanEqual.derived
given canEqualTuple[H1, T1 <: Tuple, H2, T2 <: Tuple](
using eqHead: CanEqual[H1, H2], eqTail: CanEqual[T1, T2]
): CanEqual[H1 *: T1, H2 *: T2] = CanEqual.derived
}
/** A tuple of 0 elements */
type EmptyTuple = EmptyTuple.type
/** A tuple of 0 elements. */
case object EmptyTuple extends Tuple {
override def toString(): String = "()"
}
/** Tuple of arbitrary non-zero arity */
sealed trait NonEmptyTuple extends Tuple
@showAsInfix
sealed abstract class *:[+H, +T <: Tuple] extends NonEmptyTuple
object *: {
def unapply[H, T <: Tuple](x: H *: T): (H, T) = (x.head, x.tail)
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy