|
| 1 | +package scala |
| 2 | +import annotation.experimental |
| 3 | +import compiletime.ops.boolean.* |
| 4 | + |
| 5 | +@experimental |
| 6 | +object NamedTuple: |
| 7 | + |
| 8 | + opaque type AnyNamedTuple = Any |
| 9 | + opaque type NamedTuple[N <: Tuple, V <: Tuple] >: V <: AnyNamedTuple = V |
| 10 | + |
| 11 | + def apply[N <: Tuple, V <: Tuple](x: V) = x |
| 12 | + |
| 13 | + def unapply[N <: Tuple, V <: Tuple](x: NamedTuple[N, V]): Some[V] = Some(x) |
| 14 | + |
| 15 | + extension [V <: Tuple](x: V) |
| 16 | + inline def withNames[N <: Tuple]: NamedTuple[N, V] = x |
| 17 | + |
| 18 | + extension [N <: Tuple, V <: Tuple](x: NamedTuple[N, V]) |
| 19 | + |
| 20 | + inline def values: V = x |
| 21 | + |
| 22 | + inline def size: Tuple.Size[V] = values.size |
| 23 | + |
| 24 | + // This intentionally works for empty named tuples as well. I think NnEmptyTuple is a dead end |
| 25 | + // and should be reverted, justy like NonEmptyList is also appealing at first, but a bad idea |
| 26 | + // in the end. |
| 27 | + inline def apply(n: Int): Tuple.Elem[V, n.type] = |
| 28 | + inline values match |
| 29 | + case tup: NonEmptyTuple => tup(n).asInstanceOf[Tuple.Elem[V, n.type]] |
| 30 | + case tup => tup.productElement(n).asInstanceOf[Tuple.Elem[V, n.type]] |
| 31 | + |
| 32 | + inline def head: Tuple.Elem[V, 0] = apply(0) |
| 33 | + inline def tail: Tuple.Drop[V, 1] = values.drop(1) |
| 34 | + |
| 35 | + inline def last: Tuple.Last[V] = apply(size - 1).asInstanceOf[Tuple.Last[V]] |
| 36 | + inline def init: Tuple.Init[V] = values.take(size - 1).asInstanceOf[Tuple.Init[V]] |
| 37 | + |
| 38 | + inline def take(n: Int): NamedTuple[Tuple.Take[N, n.type], Tuple.Take[V, n.type]] = |
| 39 | + values.take(n) |
| 40 | + |
| 41 | + inline def drop(n: Int): NamedTuple[Tuple.Drop[N, n.type], Tuple.Drop[V, n.type]] = |
| 42 | + values.drop(n) |
| 43 | + |
| 44 | + inline def splitAt(n: Int): NamedTuple[Tuple.Split[N, n.type], Tuple.Split[V, n.type]] = |
| 45 | + values.splitAt(n) |
| 46 | + |
| 47 | + inline def ++ [N2 <: Tuple, V2 <: Tuple](that: NamedTuple[N2, V2])(using Tuple.Disjoint[N, N2] =:= true) |
| 48 | + : NamedTuple[Tuple.Concat[N, N2], Tuple.Concat[V, V2]] |
| 49 | + = values ++ that.values |
| 50 | + |
| 51 | + // inline def :* [L] (x: L): NamedTuple[Append[N, ???], Append[V, L] = ??? |
| 52 | + // inline def *: [H] (x: H): NamedTuple[??? *: N], H *: V] = ??? |
| 53 | + |
| 54 | + inline def map[F[_]](f: [t] => t => F[t]): NamedTuple[N, Tuple.Map[V, F]] = |
| 55 | + values.map(f).asInstanceOf[NamedTuple[N, Tuple.Map[V, F]]] |
| 56 | + |
| 57 | + inline def reverse: NamedTuple[Tuple.Reverse[N], Tuple.Reverse[V]] = |
| 58 | + values.reverse |
| 59 | + |
| 60 | + inline def zip[V2 <: Tuple](that: NamedTuple[N, V2]): NamedTuple[N, Tuple.Zip[V, V2]] = |
| 61 | + values.zip(that.values) |
| 62 | + |
| 63 | + inline def toList: List[Tuple.Union[V]] = values.toList.asInstanceOf[List[Tuple.Union[V]]] |
| 64 | + inline def toArray: Array[Object] = values.toArray |
| 65 | + inline def toIArray: IArray[Object] = values.toIArray |
| 66 | + |
| 67 | + end extension |
| 68 | + |
| 69 | + /** The names of the named tuple type `NT` */ |
| 70 | + type Names[NT <: AnyNamedTuple] <: Tuple = NT match |
| 71 | + case NamedTuple[n, _] => n |
| 72 | + |
| 73 | + /** The value types of the named tuple type `NT` */ |
| 74 | + type DropNames[NT <: AnyNamedTuple] <: Tuple = NT match |
| 75 | + case NamedTuple[_, x] => x |
| 76 | + |
| 77 | + type Size[X <: AnyNamedTuple] = Tuple.Size[DropNames[X]] |
| 78 | + |
| 79 | + type Elem[X <: AnyNamedTuple, N <: Int] = Tuple.Elem[DropNames[X], N] |
| 80 | + |
| 81 | + type Head[X <: AnyNamedTuple] = Elem[X, 0] |
| 82 | + |
| 83 | + type Last[X <: AnyNamedTuple] = Tuple.Last[DropNames[X]] |
| 84 | + |
| 85 | + type Init[X <: AnyNamedTuple] = |
| 86 | + NamedTuple[Tuple.Init[Names[X]], Tuple.Init[DropNames[X]]] |
| 87 | + |
| 88 | + type Tail[X <: AnyNamedTuple] = Drop[X, 1] |
| 89 | + |
| 90 | + type Take[X <: AnyNamedTuple, N <: Int] = |
| 91 | + NamedTuple[Tuple.Take[Names[X], N], Tuple.Take[DropNames[X], N]] |
| 92 | + |
| 93 | + type Drop[X <: AnyNamedTuple, N <: Int] = |
| 94 | + NamedTuple[Tuple.Drop[Names[X], N], Tuple.Drop[DropNames[X], N]] |
| 95 | + |
| 96 | + type Split[X <: AnyNamedTuple, N <: Int] = (Take[X, N], Drop[X, N]) |
| 97 | + |
| 98 | + type Concat[X <: AnyNamedTuple, Y <: AnyNamedTuple] = |
| 99 | + NamedTuple[Tuple.Concat[Names[X], Names[Y]], Tuple.Concat[DropNames[X], DropNames[Y]]] |
| 100 | + |
| 101 | + type Map[X <: AnyNamedTuple, F[_ <: Tuple.Union[DropNames[X]]]] = |
| 102 | + NamedTuple[Names[X], Tuple.Map[DropNames[X], F]] |
| 103 | + |
| 104 | + type Reverse[X <: AnyNamedTuple] = |
| 105 | + NamedTuple[Tuple.Reverse[Names[X]], Tuple.Reverse[DropNames[X]]] |
| 106 | + |
| 107 | + type Zip[X <: AnyNamedTuple, Y <: AnyNamedTuple] = |
| 108 | + Tuple.Conforms[Names[X], Names[Y]] match |
| 109 | + case true => |
| 110 | + NamedTuple[Names[X], Tuple.Zip[DropNames[X], DropNames[Y]]] |
| 111 | + |
| 112 | +end NamedTuple |
0 commit comments