github.com/searKing/golang/go@v1.2.117/encoding/internal/tag/field.go (about)

     1  // Copyright 2020 The searKing Author. 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 tag
     6  
     7  import (
     8  	"reflect"
     9  	"sync"
    10  
    11  	reflect_ "github.com/searKing/golang/go/reflect"
    12  )
    13  
    14  // A field represents a single field found in a struct.
    15  type field struct {
    16  	name      string
    17  	structTag reflect.StructTag
    18  
    19  	index []int
    20  	typ   reflect.Type
    21  }
    22  
    23  var fieldCache fieldMap
    24  
    25  type fieldMap struct {
    26  	fields sync.Map // map[reflect.Type][]field
    27  }
    28  
    29  func (m *fieldMap) Store(type_ reflect.Type, fields []field) {
    30  	m.fields.Store(type_, fields)
    31  }
    32  
    33  func (m *fieldMap) LoadOrStore(type_ reflect.Type, fields []field) ([]field, bool) {
    34  	actual, loaded := m.fields.LoadOrStore(type_, fields)
    35  	if actual == nil {
    36  		return nil, loaded
    37  	}
    38  	return actual.([]field), loaded
    39  }
    40  
    41  func (m *fieldMap) Load(type_ reflect.Type) ([]field, bool) {
    42  	fields, ok := m.fields.Load(type_)
    43  	if fields == nil {
    44  		return nil, ok
    45  	}
    46  	return fields.([]field), ok
    47  }
    48  
    49  func (m *fieldMap) Delete(type_ reflect.Type) {
    50  	m.fields.Delete(type_)
    51  }
    52  
    53  func (m *fieldMap) Range(f func(type_ reflect.Type, fields []field) bool) {
    54  	m.fields.Range(func(type_, fields any) bool {
    55  		return f(type_.(reflect.Type), fields.([]field))
    56  	})
    57  }
    58  
    59  // cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
    60  func cachedTypeFields(t reflect.Type) []field {
    61  	if f, ok := fieldCache.Load(t); ok {
    62  		return f
    63  	}
    64  	var fields []field
    65  	reflect_.WalkTypeDFS(t, reflect_.FieldTypeInfoHandlerFunc(
    66  		func(info reflect_.FieldTypeInfo) (goon bool) {
    67  			// ignore struct's root
    68  			if info.Depth() == 0 {
    69  				return true
    70  			}
    71  
    72  			sf, ok := info.StructField()
    73  			if !ok {
    74  				return true
    75  			}
    76  
    77  			fields = append(fields, field{
    78  				name:      sf.Name,
    79  				structTag: sf.Tag,
    80  				index:     info.Index(),
    81  				typ:       sf.Type,
    82  			})
    83  			return true
    84  		}))
    85  	f, _ := fieldCache.LoadOrStore(t, fields)
    86  	return f
    87  }