...

Source file src/reflect/visiblefields.go

Documentation: reflect

		 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() == Ptr {
		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  }
	 106  

View as plain text