tlog.app/go/tlog@v0.23.1/tlwire/struct.go (about)

     1  package tlwire
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"sync"
     7  )
     8  
     9  type (
    10  	rawStruct struct {
    11  		fs []rawField
    12  	}
    13  
    14  	rawField struct {
    15  		Name       string
    16  		TagName    string
    17  		Idx        int
    18  		OmitEmpty  bool
    19  		Unexported bool
    20  		Embed      bool
    21  		Hex        bool
    22  	}
    23  )
    24  
    25  var (
    26  	structsMu    sync.Mutex
    27  	structsCache = map[reflect.Type]*rawStruct{}
    28  )
    29  
    30  func parseStruct(tp reflect.Type) (s *rawStruct) { //nolint:gocognit
    31  	defer structsMu.Unlock()
    32  	structsMu.Lock()
    33  
    34  	s = structsCache[tp]
    35  	if s != nil {
    36  		return s
    37  	}
    38  
    39  	s = &rawStruct{}
    40  	structsCache[tp] = s
    41  
    42  	ff := tp.NumField()
    43  
    44  	for i := 0; i < ff; i++ {
    45  		f := tp.Field(i)
    46  
    47  		sf := rawField{
    48  			Idx:        i,
    49  			Unexported: f.PkgPath != "",
    50  		}
    51  
    52  		tag, ok := f.Tag.Lookup("tlog")
    53  
    54  		if !ok {
    55  			switch f.Type.Kind() {
    56  			case reflect.Chan, reflect.Func, reflect.UnsafePointer:
    57  				continue
    58  			}
    59  
    60  			if f.PkgPath != "" {
    61  				continue
    62  			}
    63  		}
    64  
    65  		if tag == "" {
    66  			tag = f.Tag.Get("yaml")
    67  		}
    68  		if tag == "" {
    69  			tag = f.Tag.Get("json")
    70  		}
    71  
    72  		ss := strings.Split(tag, ",")
    73  
    74  		if len(ss) != 0 {
    75  			if ss[0] == "-" {
    76  				continue
    77  			}
    78  
    79  			if ss[0] != "" {
    80  				sf.Name = ss[0]
    81  				sf.TagName = ss[0]
    82  			}
    83  		}
    84  
    85  		if len(ss) > 1 {
    86  			for _, s := range ss[1:] {
    87  				switch s {
    88  				case "omitempty":
    89  					sf.OmitEmpty = true
    90  				case "embed":
    91  					sf.Embed = true
    92  				case "hex":
    93  					sf.Hex = true
    94  				}
    95  			}
    96  		}
    97  
    98  		if sf.Name == "" {
    99  			sf.Name = f.Name
   100  		}
   101  
   102  		s.fs = append(s.fs, sf)
   103  	}
   104  
   105  	return s
   106  }