Skip to content

Commit e2ccd13

Browse files
committed
Add NamedTuple object to library
1 parent da8b362 commit e2ccd13

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

library/src/scala/NamedTuple.scala

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
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

Comments
 (0)