github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/reflect/visiblefields.go (about) 1 // Copyright 2021 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 // VisibleFields returns all the visible fields in t, which must be a 8 // struct type. A field is defined as visible if it's accessible 9 // directly with a FieldByName call. The returned fields include fields 10 // inside anonymous struct members and unexported fields. They follow 11 // the same order found in the struct, with anonymous fields followed 12 // immediately by their promoted fields. 13 // 14 // For each element e of the returned slice, the corresponding field 15 // can be retrieved from a value v of type t by calling v.FieldByIndex(e.Index). 16 func VisibleFields(t Type) []StructField { 17 if t == nil { 18 panic("reflect: VisibleFields(nil)") 19 } 20 if t.Kind() != Struct { 21 panic("reflect.VisibleFields of non-struct type") 22 } 23 w := &visibleFieldsWalker{ 24 byName: make(map[string]int), 25 visiting: make(map[Type]bool), 26 fields: make([]StructField, 0, t.NumField()), 27 index: make([]int, 0, 2), 28 } 29 w.walk(t) 30 // Remove all the fields that have been hidden. 31 // Use an in-place removal that avoids copying in 32 // the common case that there are no hidden fields. 33 j := 0 34 for i := range w.fields { 35 f := &w.fields[i] 36 if f.Name == "" { 37 continue 38 } 39 if i != j { 40 // A field has been removed. We need to shuffle 41 // all the subsequent elements up. 42 w.fields[j] = *f 43 } 44 j++ 45 } 46 return w.fields[:j] 47 } 48 49 type visibleFieldsWalker struct { 50 byName map[string]int 51 visiting map[Type]bool 52 fields []StructField 53 index []int 54 } 55 56 // walk walks all the fields in the struct type t, visiting 57 // fields in index preorder and appending them to w.fields 58 // (this maintains the required ordering). 59 // Fields that have been overridden have their 60 // Name field cleared. 61 func (w *visibleFieldsWalker) walk(t Type) { 62 if w.visiting[t] { 63 return 64 } 65 w.visiting[t] = true 66 for i := 0; i < t.NumField(); i++ { 67 f := t.Field(i) 68 w.index = append(w.index, i) 69 add := true 70 if oldIndex, ok := w.byName[f.Name]; ok { 71 old := &w.fields[oldIndex] 72 if len(w.index) == len(old.Index) { 73 // Fields with the same name at the same depth 74 // cancel one another out. Set the field name 75 // to empty to signify that has happened, and 76 // there's no need to add this field. 77 old.Name = "" 78 add = false 79 } else if len(w.index) < len(old.Index) { 80 // The old field loses because it's deeper than the new one. 81 old.Name = "" 82 } else { 83 // The old field wins because it's shallower than the new one. 84 add = false 85 } 86 } 87 if add { 88 // Copy the index so that it's not overwritten 89 // by the other appends. 90 f.Index = append([]int(nil), w.index...) 91 w.byName[f.Name] = len(w.fields) 92 w.fields = append(w.fields, f) 93 } 94 if f.Anonymous { 95 if f.Type.Kind() == Pointer { 96 f.Type = f.Type.Elem() 97 } 98 if f.Type.Kind() == Struct { 99 w.walk(f.Type) 100 } 101 } 102 w.index = w.index[:len(w.index)-1] 103 } 104 delete(w.visiting, t) 105 }