Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions src/reflect/iter.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,31 @@ import (
"iter"
)

// Fields returns an iterator over each StructField of v along with its Value.
func (v Value) Fields() iter.Seq2[StructField, Value] {
if v.Kind() != Struct {
panic(&ValueError{Method: "reflect.Value.Fields", Kind: v.Kind()})
}
return func(yield func(StructField, Value) bool) {
for i, n := 0, v.NumField(); i < n; i++ {
if !yield(v.Type().Field(i), v.Field(i)) {
return
}
}
}
}

// Methods returns an iterator over each Method of v along with its Value.
func (v Value) Methods() iter.Seq2[Method, Value] {
return func(yield func(Method, Value) bool) {
for i, n := 0, v.NumMethod(); i < n; i++ {
if !yield(v.Type().Method(i), v.Method(i)) {
return
}
}
}
}

func rangeNum[T int8 | int16 | int32 | int64 | int |
uint8 | uint16 | uint32 | uint64 | uint |
uintptr, N int64 | uint64](num N, t Type) iter.Seq[Value] {
Expand Down
39 changes: 39 additions & 0 deletions src/reflect/iter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,45 @@ func TestValueSeq2(t *testing.T) {
}
}

func TestValueFields(t *testing.T) {
type T struct {
First int
Second string
Third bool
}
v := ValueOf(T{First: 10, Second: "visible", Third: true})

names := []string{"First", "Second", "Third"}
values := []any{10, "visible", true}
var count int
for field, value := range v.Fields() {
if field.Name != names[count] {
t.Fatalf("field %d name = %q, want %q", count, field.Name, names[count])
}
if field.Index[0] != count {
t.Fatalf("field %d index = %v, want [%d]", count, field.Index, count)
}
if got := value.Interface(); got != values[count] {
t.Fatalf("field %d value = %v, want %v", count, got, values[count])
}
count++
}
if count != len(names) {
t.Fatalf("field count = %d, want %d", count, len(names))
}

count = 0
for field := range v.Type().Fields() {
if field.Name != names[count] {
t.Fatalf("type field %d name = %q, want %q", count, field.Name, names[count])
}
count++
}
if count != len(names) {
t.Fatalf("type field count = %d, want %d", count, len(names))
}
}

// methodIter is a type from which we can derive a method
// value that is an iter.Seq.
type methodIter struct{}
Expand Down
56 changes: 56 additions & 0 deletions src/reflect/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ package reflect

import (
"internal/reflectlite"
"iter"
"unsafe"
)

Expand Down Expand Up @@ -265,6 +266,10 @@ type Type interface {
// It panics if i is not in the range [0, NumField()).
Field(i int) StructField

// Fields returns an iterator over each struct field for struct type t.
// It panics if the type's Kind is not Struct.
Fields() iter.Seq[StructField]

// FieldByIndex returns the nested field corresponding
// to the index sequence. It is equivalent to calling Field
// successively for each index i.
Expand Down Expand Up @@ -294,6 +299,10 @@ type Type interface {
// It panics if i is not in the range [0, NumIn()).
In(i int) Type

// Ins returns an iterator over each input parameter of function type t.
// It panics if the type's Kind is not Func.
Ins() iter.Seq[Type]

// Key returns a map type's key type.
// It panics if the type's Kind is not Map.
Key() Type
Expand All @@ -319,6 +328,10 @@ type Type interface {
// It panics if i is not in the range [0, NumOut()).
Out(i int) Type

// Outs returns an iterator over each output parameter of function type t.
// It panics if the type's Kind is not Func.
Outs() iter.Seq[Type]

// OverflowComplex reports whether the complex128 x cannot be represented by type t.
// It panics if t's Kind is not Complex64 or Complex128.
OverflowComplex(x complex128) bool
Expand All @@ -340,6 +353,9 @@ type Type interface {

// CanSeq2 reports whether a [Value] with this type can be iterated over using [Value.Seq2].
CanSeq2() bool

// Methods returns an iterator over each method in the type's method set.
Methods() iter.Seq[Method]
}

type rawType struct {
Expand Down Expand Up @@ -414,6 +430,16 @@ func (t *rawType) Field(i int) StructField {
return toStructField(f)
}

func (t *rawType) Fields() iter.Seq[StructField] {
return func(yield func(StructField) bool) {
for i, n := 0, t.NumField(); i < n; i++ {
if !yield(t.Field(i)) {
return
}
}
}
}

func (t *rawType) FieldByIndex(index []int) StructField {
f := t.RawType.FieldByIndex(index)
return toStructField(f)
Expand All @@ -437,6 +463,16 @@ func (t *rawType) In(i int) Type {
panic("unimplemented: (reflect.Type).In()")
}

func (t *rawType) Ins() iter.Seq[Type] {
return func(yield func(Type) bool) {
for i, n := 0, t.NumIn(); i < n; i++ {
if !yield(t.In(i)) {
return
}
}
}
}

func (t *rawType) IsVariadic() bool {
panic("unimplemented: (reflect.Type).IsVariadic()")
}
Expand All @@ -453,6 +489,16 @@ func (t *rawType) MethodByName(name string) (Method, bool) {
panic("unimplemented: (reflect.Type).MethodByName()")
}

func (t *rawType) Methods() iter.Seq[Method] {
return func(yield func(Method) bool) {
for i, n := 0, t.NumMethod(); i < n; i++ {
if !yield(t.Method(i)) {
return
}
}
}
}

func (t *rawType) NumIn() int {
panic("unimplemented: (reflect.Type).NumIn()")
}
Expand All @@ -465,6 +511,16 @@ func (t *rawType) Out(i int) Type {
panic("unimplemented: (reflect.Type).Out()")
}

func (t *rawType) Outs() iter.Seq[Type] {
return func(yield func(Type) bool) {
for i, n := 0, t.NumOut(); i < n; i++ {
if !yield(t.Out(i)) {
return
}
}
}
}

// A StructField describes a single field in a struct.
// This must be kept in sync with [reflectlite.StructField].
type StructField struct {
Expand Down
Loading