Skip to content

Commit 9e143ef

Browse files
ydnardeadprogram
authored andcommitted
reflect: add Go 1.24 iter.Seq[2] methods
1 parent d5c70a1 commit 9e143ef

File tree

2 files changed

+198
-0
lines changed

2 files changed

+198
-0
lines changed

src/reflect/iter.go

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// Copyright 2024 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package reflect
6+
7+
import "iter"
8+
9+
func rangeNum[T int8 | int16 | int32 | int64 | int |
10+
uint8 | uint16 | uint32 | uint64 | uint |
11+
uintptr, N int64 | uint64](v N) iter.Seq[Value] {
12+
return func(yield func(v Value) bool) {
13+
// cannot use range T(v) because no core type.
14+
for i := T(0); i < T(v); i++ {
15+
if !yield(ValueOf(i)) {
16+
return
17+
}
18+
}
19+
}
20+
}
21+
22+
// Seq returns an iter.Seq[Value] that loops over the elements of v.
23+
// If v's kind is Func, it must be a function that has no results and
24+
// that takes a single argument of type func(T) bool for some type T.
25+
// If v's kind is Pointer, the pointer element type must have kind Array.
26+
// Otherwise v's kind must be Int, Int8, Int16, Int32, Int64,
27+
// Uint, Uint8, Uint16, Uint32, Uint64, Uintptr,
28+
// Array, Chan, Map, Slice, or String.
29+
func (v Value) Seq() iter.Seq[Value] {
30+
// TODO: canRangeFunc
31+
// if canRangeFunc(v.typ()) {
32+
// return func(yield func(Value) bool) {
33+
// rf := MakeFunc(v.Type().In(0), func(in []Value) []Value {
34+
// return []Value{ValueOf(yield(in[0]))}
35+
// })
36+
// v.Call([]Value{rf})
37+
// }
38+
// }
39+
switch v.Kind() {
40+
case Int:
41+
return rangeNum[int](v.Int())
42+
case Int8:
43+
return rangeNum[int8](v.Int())
44+
case Int16:
45+
return rangeNum[int16](v.Int())
46+
case Int32:
47+
return rangeNum[int32](v.Int())
48+
case Int64:
49+
return rangeNum[int64](v.Int())
50+
case Uint:
51+
return rangeNum[uint](v.Uint())
52+
case Uint8:
53+
return rangeNum[uint8](v.Uint())
54+
case Uint16:
55+
return rangeNum[uint16](v.Uint())
56+
case Uint32:
57+
return rangeNum[uint32](v.Uint())
58+
case Uint64:
59+
return rangeNum[uint64](v.Uint())
60+
case Uintptr:
61+
return rangeNum[uintptr](v.Uint())
62+
case Pointer:
63+
if v.Elem().Kind() != Array {
64+
break
65+
}
66+
return func(yield func(Value) bool) {
67+
v = v.Elem()
68+
for i := 0; i < v.Len(); i++ {
69+
if !yield(ValueOf(i)) {
70+
return
71+
}
72+
}
73+
}
74+
case Array, Slice:
75+
return func(yield func(Value) bool) {
76+
for i := 0; i < v.Len(); i++ {
77+
if !yield(ValueOf(i)) {
78+
return
79+
}
80+
}
81+
}
82+
case String:
83+
return func(yield func(Value) bool) {
84+
for i := range v.String() {
85+
if !yield(ValueOf(i)) {
86+
return
87+
}
88+
}
89+
}
90+
case Map:
91+
return func(yield func(Value) bool) {
92+
i := v.MapRange()
93+
for i.Next() {
94+
if !yield(i.Key()) {
95+
return
96+
}
97+
}
98+
}
99+
case Chan:
100+
return func(yield func(Value) bool) {
101+
for value, ok := v.Recv(); ok; value, ok = v.Recv() {
102+
if !yield(value) {
103+
return
104+
}
105+
}
106+
}
107+
}
108+
panic("reflect: " + v.Type().String() + " cannot produce iter.Seq[Value]")
109+
}
110+
111+
// Seq2 returns an iter.Seq2[Value, Value] that loops over the elements of v.
112+
// If v's kind is Func, it must be a function that has no results and
113+
// that takes a single argument of type func(K, V) bool for some type K, V.
114+
// If v's kind is Pointer, the pointer element type must have kind Array.
115+
// Otherwise v's kind must be Array, Map, Slice, or String.
116+
func (v Value) Seq2() iter.Seq2[Value, Value] {
117+
// TODO: canRangeFunc2
118+
// if canRangeFunc2(v.typ()) {
119+
// return func(yield func(Value, Value) bool) {
120+
// rf := MakeFunc(v.Type().In(0), func(in []Value) []Value {
121+
// return []Value{ValueOf(yield(in[0], in[1]))}
122+
// })
123+
// v.Call([]Value{rf})
124+
// }
125+
// }
126+
switch v.Kind() {
127+
case Pointer:
128+
if v.Elem().Kind() != Array {
129+
break
130+
}
131+
return func(yield func(Value, Value) bool) {
132+
v = v.Elem()
133+
for i := 0; i < v.Len(); i++ {
134+
if !yield(ValueOf(i), v.Index(i)) {
135+
return
136+
}
137+
}
138+
}
139+
case Array, Slice:
140+
return func(yield func(Value, Value) bool) {
141+
for i := 0; i < v.Len(); i++ {
142+
if !yield(ValueOf(i), v.Index(i)) {
143+
return
144+
}
145+
}
146+
}
147+
case String:
148+
return func(yield func(Value, Value) bool) {
149+
for i, v := range v.String() {
150+
if !yield(ValueOf(i), ValueOf(v)) {
151+
return
152+
}
153+
}
154+
}
155+
case Map:
156+
return func(yield func(Value, Value) bool) {
157+
i := v.MapRange()
158+
for i.Next() {
159+
if !yield(i.Key(), i.Value()) {
160+
return
161+
}
162+
}
163+
}
164+
}
165+
panic("reflect: " + v.Type().String() + " cannot produce iter.Seq2[Value, Value]")
166+
}

src/reflect/type.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,12 @@ type Type interface {
329329
// OverflowUint reports whether the uint64 x cannot be represented by type t.
330330
// It panics if t's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
331331
OverflowUint(x uint64) bool
332+
333+
// CanSeq reports whether a [Value] with this type can be iterated over using [Value.Seq].
334+
CanSeq() bool
335+
336+
// CanSeq2 reports whether a [Value] with this type can be iterated over using [Value.Seq2].
337+
CanSeq2() bool
332338
}
333339

334340
type rawType struct {
@@ -359,6 +365,32 @@ func (t *rawType) AssignableTo(u Type) bool {
359365
return t.RawType.AssignableTo(&(u.(*rawType).RawType))
360366
}
361367

368+
func (t *rawType) CanSeq() bool {
369+
switch t.Kind() {
370+
case Int8, Int16, Int32, Int64, Int, Uint8, Uint16, Uint32, Uint64, Uint, Uintptr, Array, Slice, Chan, String, Map:
371+
return true
372+
case Func:
373+
return false // TODO: implement canRangeFunc
374+
// return canRangeFunc(&t.)
375+
case Pointer:
376+
return t.Elem().Kind() == Array
377+
}
378+
return false
379+
}
380+
381+
func (t *rawType) CanSeq2() bool {
382+
switch t.Kind() {
383+
case Array, Slice, String, Map:
384+
return true
385+
case Func:
386+
return false // TODO: implement canRangeFunc2
387+
// return canRangeFunc2(&t.t)
388+
case Pointer:
389+
return t.Elem().Kind() == Array
390+
}
391+
return false
392+
}
393+
362394
func (t *rawType) ConvertibleTo(u Type) bool {
363395
panic("unimplemented: (reflect.Type).ConvertibleTo()")
364396
}

0 commit comments

Comments
 (0)