reflect: add Go 1.24 iter.Seq[2] methods

This commit is contained in:
Randy Reddig
2025-03-08 12:49:23 -08:00
committed by Ron Evans
parent d5c70a1cd3
commit 9e143efd73
2 changed files with 198 additions and 0 deletions
+166
View File
@@ -0,0 +1,166 @@
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package reflect
import "iter"
func rangeNum[T int8 | int16 | int32 | int64 | int |
uint8 | uint16 | uint32 | uint64 | uint |
uintptr, N int64 | uint64](v N) iter.Seq[Value] {
return func(yield func(v Value) bool) {
// cannot use range T(v) because no core type.
for i := T(0); i < T(v); i++ {
if !yield(ValueOf(i)) {
return
}
}
}
}
// Seq returns an iter.Seq[Value] that loops over the elements of v.
// If v's kind is Func, it must be a function that has no results and
// that takes a single argument of type func(T) bool for some type T.
// If v's kind is Pointer, the pointer element type must have kind Array.
// Otherwise v's kind must be Int, Int8, Int16, Int32, Int64,
// Uint, Uint8, Uint16, Uint32, Uint64, Uintptr,
// Array, Chan, Map, Slice, or String.
func (v Value) Seq() iter.Seq[Value] {
// TODO: canRangeFunc
// if canRangeFunc(v.typ()) {
// return func(yield func(Value) bool) {
// rf := MakeFunc(v.Type().In(0), func(in []Value) []Value {
// return []Value{ValueOf(yield(in[0]))}
// })
// v.Call([]Value{rf})
// }
// }
switch v.Kind() {
case Int:
return rangeNum[int](v.Int())
case Int8:
return rangeNum[int8](v.Int())
case Int16:
return rangeNum[int16](v.Int())
case Int32:
return rangeNum[int32](v.Int())
case Int64:
return rangeNum[int64](v.Int())
case Uint:
return rangeNum[uint](v.Uint())
case Uint8:
return rangeNum[uint8](v.Uint())
case Uint16:
return rangeNum[uint16](v.Uint())
case Uint32:
return rangeNum[uint32](v.Uint())
case Uint64:
return rangeNum[uint64](v.Uint())
case Uintptr:
return rangeNum[uintptr](v.Uint())
case Pointer:
if v.Elem().Kind() != Array {
break
}
return func(yield func(Value) bool) {
v = v.Elem()
for i := 0; i < v.Len(); i++ {
if !yield(ValueOf(i)) {
return
}
}
}
case Array, Slice:
return func(yield func(Value) bool) {
for i := 0; i < v.Len(); i++ {
if !yield(ValueOf(i)) {
return
}
}
}
case String:
return func(yield func(Value) bool) {
for i := range v.String() {
if !yield(ValueOf(i)) {
return
}
}
}
case Map:
return func(yield func(Value) bool) {
i := v.MapRange()
for i.Next() {
if !yield(i.Key()) {
return
}
}
}
case Chan:
return func(yield func(Value) bool) {
for value, ok := v.Recv(); ok; value, ok = v.Recv() {
if !yield(value) {
return
}
}
}
}
panic("reflect: " + v.Type().String() + " cannot produce iter.Seq[Value]")
}
// Seq2 returns an iter.Seq2[Value, Value] that loops over the elements of v.
// If v's kind is Func, it must be a function that has no results and
// that takes a single argument of type func(K, V) bool for some type K, V.
// If v's kind is Pointer, the pointer element type must have kind Array.
// Otherwise v's kind must be Array, Map, Slice, or String.
func (v Value) Seq2() iter.Seq2[Value, Value] {
// TODO: canRangeFunc2
// if canRangeFunc2(v.typ()) {
// return func(yield func(Value, Value) bool) {
// rf := MakeFunc(v.Type().In(0), func(in []Value) []Value {
// return []Value{ValueOf(yield(in[0], in[1]))}
// })
// v.Call([]Value{rf})
// }
// }
switch v.Kind() {
case Pointer:
if v.Elem().Kind() != Array {
break
}
return func(yield func(Value, Value) bool) {
v = v.Elem()
for i := 0; i < v.Len(); i++ {
if !yield(ValueOf(i), v.Index(i)) {
return
}
}
}
case Array, Slice:
return func(yield func(Value, Value) bool) {
for i := 0; i < v.Len(); i++ {
if !yield(ValueOf(i), v.Index(i)) {
return
}
}
}
case String:
return func(yield func(Value, Value) bool) {
for i, v := range v.String() {
if !yield(ValueOf(i), ValueOf(v)) {
return
}
}
}
case Map:
return func(yield func(Value, Value) bool) {
i := v.MapRange()
for i.Next() {
if !yield(i.Key(), i.Value()) {
return
}
}
}
}
panic("reflect: " + v.Type().String() + " cannot produce iter.Seq2[Value, Value]")
}
+32
View File
@@ -329,6 +329,12 @@ type Type interface {
// OverflowUint reports whether the uint64 x cannot be represented by type t.
// It panics if t's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
OverflowUint(x uint64) bool
// CanSeq reports whether a [Value] with this type can be iterated over using [Value.Seq].
CanSeq() bool
// CanSeq2 reports whether a [Value] with this type can be iterated over using [Value.Seq2].
CanSeq2() bool
}
type rawType struct {
@@ -359,6 +365,32 @@ func (t *rawType) AssignableTo(u Type) bool {
return t.RawType.AssignableTo(&(u.(*rawType).RawType))
}
func (t *rawType) CanSeq() bool {
switch t.Kind() {
case Int8, Int16, Int32, Int64, Int, Uint8, Uint16, Uint32, Uint64, Uint, Uintptr, Array, Slice, Chan, String, Map:
return true
case Func:
return false // TODO: implement canRangeFunc
// return canRangeFunc(&t.)
case Pointer:
return t.Elem().Kind() == Array
}
return false
}
func (t *rawType) CanSeq2() bool {
switch t.Kind() {
case Array, Slice, String, Map:
return true
case Func:
return false // TODO: implement canRangeFunc2
// return canRangeFunc2(&t.t)
case Pointer:
return t.Elem().Kind() == Array
}
return false
}
func (t *rawType) ConvertibleTo(u Type) bool {
panic("unimplemented: (reflect.Type).ConvertibleTo()")
}