@@ -28,100 +28,27 @@ object NamedTuple:
2828 extension [V <: Tuple ](x : V )
2929 inline def withNames [N <: Tuple ]: NamedTuple [N , V ] = x
3030
31- export NamedTupleDecomposition .{Names , DropNames }
31+ export NamedTupleDecomposition .{
32+ Names , DropNames ,
33+ apply , size , init , last , tail , take , drop , splitAt , ++ , map , reverse , zip , toList , toArray , toIArray
34+ }
3235
3336 extension [N <: Tuple , V <: Tuple ](x : NamedTuple [N , V ])
3437
38+ // ALL METHODS DEPENDING ON `toTuple` MUST BE EXPORTED FROM `NamedTupleDecomposition`
3539 /** The underlying tuple without the names */
3640 inline def toTuple : V = x
3741
38- /** The number of elements in this tuple */
39- inline def size : Tuple .Size [V ] = toTuple.size
40-
4142 // This intentionally works for empty named tuples as well. I think NonEmptyTuple is a dead end
4243 // and should be reverted, just like NonEmptyList is also appealing at first, but a bad idea
4344 // in the end.
4445
45- /** The value (without the name) at index `n` of this tuple */
46- inline def apply (n : Int ): Tuple .Elem [V , n.type ] =
47- inline toTuple match
48- case tup : NonEmptyTuple => tup(n).asInstanceOf [Tuple .Elem [V , n.type ]]
49- case tup => tup.productElement(n).asInstanceOf [Tuple .Elem [V , n.type ]]
50-
5146 /** The first element value of this tuple */
52- inline def head : Tuple .Elem [V , 0 ] = apply(0 )
53-
54- /** The tuple consisting of all elements of this tuple except the first one */
55- inline def tail : NamedTuple [Tuple .Tail [N ], Tuple .Tail [V ]] =
56- toTuple.drop(1 ).asInstanceOf [NamedTuple [Tuple .Tail [N ], Tuple .Tail [V ]]]
57-
58- /** The last element value of this tuple */
59- inline def last : Tuple .Last [V ] = apply(size - 1 ).asInstanceOf [Tuple .Last [V ]]
60-
61- /** The tuple consisting of all elements of this tuple except the last one */
62- inline def init : NamedTuple [Tuple .Init [N ], Tuple .Init [V ]] =
63- toTuple.take(size - 1 ).asInstanceOf [NamedTuple [Tuple .Init [N ], Tuple .Init [V ]]]
64-
65- /** The tuple consisting of the first `n` elements of this tuple, or all
66- * elements if `n` exceeds `size`.
67- */
68- inline def take (n : Int ): NamedTuple [Tuple .Take [N , n.type ], Tuple .Take [V , n.type ]] =
69- toTuple.take(n)
70-
71- /** The tuple consisting of all elements of this tuple except the first `n` ones,
72- * or no elements if `n` exceeds `size`.
73- */
74- inline def drop (n : Int ): NamedTuple [Tuple .Drop [N , n.type ], Tuple .Drop [V , n.type ]] =
75- toTuple.drop(n)
76-
77- /** The tuple `(x.take(n), x.drop(n))` */
78- inline def splitAt (n : Int ):
79- (NamedTuple [Tuple .Take [N , n.type ], Tuple .Take [V , n.type ]],
80- NamedTuple [Tuple .Drop [N , n.type ], Tuple .Drop [V , n.type ]]) =
81- // would be nice if this could have type `Split[NamedTuple[N, V]]` instead, but
82- // we get a type error then. Similar for other methods here.
83- toTuple.splitAt(n)
84-
85- /** The tuple consisting of all elements of this tuple followed by all elements
86- * of tuple `that`. The names of the two tuples must be disjoint.
87- */
88- inline def ++ [N2 <: Tuple , V2 <: Tuple ](that : NamedTuple [N2 , V2 ])(using Tuple .Disjoint [N , N2 ] =:= true )
89- : NamedTuple [Tuple .Concat [N , N2 ], Tuple .Concat [V , V2 ]]
90- = toTuple ++ that.toTuple
47+ inline def head : Tuple .Elem [V , 0 ] = x.apply(0 )
9148
9249 // inline def :* [L] (x: L): NamedTuple[Append[N, ???], Append[V, L] = ???
9350 // inline def *: [H] (x: H): NamedTuple[??? *: N], H *: V] = ???
9451
95- /** The named tuple consisting of all element values of this tuple mapped by
96- * the polymorphic mapping function `f`. The names of elements are preserved.
97- * If `x = (n1 = v1, ..., ni = vi)` then `x.map(f) = `(n1 = f(v1), ..., ni = f(vi))`.
98- */
99- inline def map [F [_]](f : [t] => t => F [t]): NamedTuple [N , Tuple .Map [V , F ]] =
100- toTuple.map(f).asInstanceOf [NamedTuple [N , Tuple .Map [V , F ]]]
101-
102- /** The named tuple consisting of all elements of this tuple in reverse */
103- inline def reverse : NamedTuple [Tuple .Reverse [N ], Tuple .Reverse [V ]] =
104- toTuple.reverse
105-
106- /** The named tuple consisting of all elements values of this tuple zipped
107- * with corresponding element values in named tuple `that`.
108- * If the two tuples have different sizes,
109- * the extra elements of the larger tuple will be disregarded.
110- * The names of `x` and `that` at the same index must be the same.
111- * The result tuple keeps the same names as the operand tuples.
112- */
113- inline def zip [V2 <: Tuple ](that : NamedTuple [N , V2 ]): NamedTuple [N , Tuple .Zip [V , V2 ]] =
114- toTuple.zip(that.toTuple)
115-
116- /** A list consisting of all element values */
117- inline def toList : List [Tuple .Union [V ]] = toTuple.toList.asInstanceOf [List [Tuple .Union [V ]]]
118-
119- /** An array consisting of all element values */
120- inline def toArray : Array [Object ] = toTuple.toArray
121-
122- /** An immutable array consisting of all element values */
123- inline def toIArray : IArray [Object ] = toTuple.toIArray
124-
12552 end extension
12653
12754 /** The size of a named tuple, represented as a literal constant subtype of Int */
@@ -212,6 +139,85 @@ end NamedTuple
212139@ experimental
213140object NamedTupleDecomposition :
214141 import NamedTuple .*
142+ extension [N <: Tuple , V <: Tuple ](x : NamedTuple [N , V ])
143+ /** The value (without the name) at index `n` of this tuple */
144+ inline def apply (n : Int ): Tuple .Elem [V , n.type ] =
145+ inline x.toTuple match
146+ case tup : NonEmptyTuple => tup(n).asInstanceOf [Tuple .Elem [V , n.type ]]
147+ case tup => tup.productElement(n).asInstanceOf [Tuple .Elem [V , n.type ]]
148+
149+ /** The number of elements in this tuple */
150+ inline def size : Tuple .Size [V ] = x.toTuple.size
151+
152+ /** The last element value of this tuple */
153+ inline def last : Tuple .Last [V ] = apply(size - 1 ).asInstanceOf [Tuple .Last [V ]]
154+
155+ /** The tuple consisting of all elements of this tuple except the last one */
156+ inline def init : NamedTuple [Tuple .Init [N ], Tuple .Init [V ]] =
157+ x.toTuple.take(size - 1 ).asInstanceOf [NamedTuple [Tuple .Init [N ], Tuple .Init [V ]]]
158+
159+ /** The tuple consisting of all elements of this tuple except the first one */
160+ inline def tail : NamedTuple [Tuple .Tail [N ], Tuple .Tail [V ]] =
161+ x.toTuple.drop(1 ).asInstanceOf [NamedTuple [Tuple .Tail [N ], Tuple .Tail [V ]]]
162+
163+ /** The tuple consisting of the first `n` elements of this tuple, or all
164+ * elements if `n` exceeds `size`.
165+ */
166+ inline def take (n : Int ): NamedTuple [Tuple .Take [N , n.type ], Tuple .Take [V , n.type ]] =
167+ x.toTuple.take(n)
168+
169+ /** The tuple consisting of all elements of this tuple except the first `n` ones,
170+ * or no elements if `n` exceeds `size`.
171+ */
172+ inline def drop (n : Int ): NamedTuple [Tuple .Drop [N , n.type ], Tuple .Drop [V , n.type ]] =
173+ x.toTuple.drop(n)
174+
175+ /** The tuple `(x.take(n), x.drop(n))` */
176+ inline def splitAt (n : Int ):
177+ (NamedTuple [Tuple .Take [N , n.type ], Tuple .Take [V , n.type ]],
178+ NamedTuple [Tuple .Drop [N , n.type ], Tuple .Drop [V , n.type ]]) =
179+ // would be nice if this could have type `Split[NamedTuple[N, V]]` instead, but
180+ // we get a type error then. Similar for other methods here.
181+ x.toTuple.splitAt(n)
182+
183+ /** The tuple consisting of all elements of this tuple followed by all elements
184+ * of tuple `that`. The names of the two tuples must be disjoint.
185+ */
186+ inline def ++ [N2 <: Tuple , V2 <: Tuple ](that : NamedTuple [N2 , V2 ])(using Tuple .Disjoint [N , N2 ] =:= true )
187+ : NamedTuple [Tuple .Concat [N , N2 ], Tuple .Concat [V , V2 ]]
188+ = x.toTuple ++ that.toTuple
189+
190+ /** The named tuple consisting of all element values of this tuple mapped by
191+ * the polymorphic mapping function `f`. The names of elements are preserved.
192+ * If `x = (n1 = v1, ..., ni = vi)` then `x.map(f) = `(n1 = f(v1), ..., ni = f(vi))`.
193+ */
194+ inline def map [F [_]](f : [t] => t => F [t]): NamedTuple [N , Tuple .Map [V , F ]] =
195+ x.toTuple.map(f).asInstanceOf [NamedTuple [N , Tuple .Map [V , F ]]]
196+
197+ /** The named tuple consisting of all elements of this tuple in reverse */
198+ inline def reverse : NamedTuple [Tuple .Reverse [N ], Tuple .Reverse [V ]] =
199+ x.toTuple.reverse
200+
201+ /** The named tuple consisting of all elements values of this tuple zipped
202+ * with corresponding element values in named tuple `that`.
203+ * If the two tuples have different sizes,
204+ * the extra elements of the larger tuple will be disregarded.
205+ * The names of `x` and `that` at the same index must be the same.
206+ * The result tuple keeps the same names as the operand tuples.
207+ */
208+ inline def zip [V2 <: Tuple ](that : NamedTuple [N , V2 ]): NamedTuple [N , Tuple .Zip [V , V2 ]] =
209+ x.toTuple.zip(that.toTuple)
210+
211+ /** A list consisting of all element values */
212+ inline def toList : List [Tuple .Union [V ]] = x.toTuple.toList.asInstanceOf [List [Tuple .Union [V ]]]
213+
214+ /** An array consisting of all element values */
215+ inline def toArray : Array [Object ] = x.toTuple.toArray
216+
217+ /** An immutable array consisting of all element values */
218+ inline def toIArray : IArray [Object ] = x.toTuple.toIArray
219+
220+ end extension
215221
216222 /** The names of a named tuple, represented as a tuple of literal string values. */
217223 type Names [X <: AnyNamedTuple ] <: Tuple = X match
0 commit comments