github.com/nikandfor/tlog@v0.21.5-0.20231108111739-3ef89426a96d/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 }