github.com/hxx258456/fabric-ca-gm@v0.0.3-0.20221111064038-a268ad7e3a37/internal/pkg/util/struct.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package util 8 9 import ( 10 "fmt" 11 "reflect" 12 "strings" 13 "time" 14 15 "github.com/pkg/errors" 16 ) 17 18 // Field is a field of an arbitrary struct 19 type Field struct { 20 Name string 21 Path string 22 Type reflect.Type 23 Kind reflect.Kind 24 Leaf bool 25 Depth int 26 Tag reflect.StructTag 27 Value interface{} 28 Addr interface{} 29 Hide string 30 } 31 32 // ParseObj parses an object structure, calling back with field info 33 // for each field 34 func ParseObj(obj interface{}, cb func(*Field) error, tags map[string]string) error { 35 if cb == nil { 36 return errors.New("nil callback") 37 } 38 return parse(obj, cb, nil, tags) 39 } 40 41 func parse(ptr interface{}, cb func(*Field) error, parent *Field, tags map[string]string) error { 42 v := reflect.ValueOf(ptr) 43 err := parse2(v, cb, parent, tags) 44 if err != nil { 45 return err 46 } 47 return nil 48 } 49 50 func parse2(val reflect.Value, cb func(*Field) error, parent *Field, tags map[string]string) error { 51 var path string 52 var depth int 53 v := val.Elem() 54 t := v.Type() 55 for i := 0; i < v.NumField(); i++ { 56 vf := v.Field(i) 57 tf := t.Field(i) 58 name := strings.ToLower(tf.Name) 59 if tf.Name[0] == name[0] { 60 continue // skip unexported fields 61 } 62 if parent != nil { 63 path = fmt.Sprintf("%s.%s", parent.Path, name) 64 depth = parent.Depth + 1 65 } else { 66 path = name 67 } 68 kind := vf.Kind() 69 leaf := kind != reflect.Struct && kind != reflect.Ptr 70 field := &Field{ 71 Name: name, 72 Path: path, 73 Type: tf.Type, 74 Kind: kind, 75 Leaf: leaf, 76 Depth: depth, 77 Tag: tf.Tag, 78 Value: vf.Interface(), 79 Addr: vf.Addr().Interface(), 80 } 81 if parent == nil || parent.Hide == "" { 82 getHideTag(field, tags) 83 } else { 84 field.Hide = parent.Hide 85 } 86 err := cb(field) 87 if err != nil { 88 return err 89 } 90 if kind == reflect.Ptr { 91 // Skip parsing the entire struct if "skip" tag is present on a struct field 92 if tf.Tag.Get(TagSkip) == "true" { 93 continue 94 } 95 rf := reflect.New(vf.Type().Elem()) 96 err := parse2(rf, cb, field, tags) 97 if err != nil { 98 return err 99 } 100 } else if kind == reflect.Struct { 101 // Skip parsing the entire struct if "skip" tag is present on a struct field 102 if tf.Tag.Get(TagSkip) == "true" { 103 continue 104 } 105 err := parse(field.Addr, cb, field, tags) 106 if err != nil { 107 return err 108 } 109 } 110 } 111 return nil 112 } 113 114 // CopyMissingValues checks the dst interface for missing values and 115 // replaces them with value from src config struct. 116 // This does a deep copy of pointers. 117 func CopyMissingValues(src, dst interface{}) { 118 s := reflect.ValueOf(src).Elem() 119 d := reflect.ValueOf(dst).Elem() 120 copyMissingValues(s, d) 121 } 122 123 func copyMissingValues(src, dst reflect.Value) { 124 if !src.IsValid() { 125 return 126 } 127 switch src.Kind() { 128 case reflect.Ptr: 129 src = src.Elem() 130 if !src.IsValid() { 131 return 132 } 133 if dst.IsNil() { 134 dst.Set(reflect.New(src.Type())) 135 } 136 copyMissingValues(src, dst.Elem()) 137 case reflect.Interface: 138 if src.IsNil() { 139 return 140 } 141 src = src.Elem() 142 if dst.IsNil() { 143 newVal := reflect.New(src.Type()).Elem() 144 copyMissingValues(src, newVal) 145 dst.Set(newVal) 146 } else { 147 copyMissingValues(src, dst.Elem()) 148 } 149 case reflect.Struct: 150 if !src.IsValid() { 151 return 152 } 153 t, ok := src.Interface().(time.Time) 154 if ok { 155 dst.Set(reflect.ValueOf(t)) 156 } 157 for i := 0; i < src.NumField(); i++ { 158 copyMissingValues(src.Field(i), dst.Field(i)) 159 } 160 case reflect.Slice: 161 if !dst.IsNil() { 162 return 163 } 164 dst.Set(reflect.MakeSlice(src.Type(), src.Len(), src.Cap())) 165 for i := 0; i < src.Len(); i++ { 166 copyMissingValues(src.Index(i), dst.Index(i)) 167 } 168 case reflect.Map: 169 if dst.IsNil() { 170 dst.Set(reflect.MakeMap(src.Type())) 171 } 172 for _, key := range src.MapKeys() { 173 sval := src.MapIndex(key) 174 dval := dst.MapIndex(key) 175 copy := !dval.IsValid() 176 if copy { 177 dval = reflect.New(sval.Type()).Elem() 178 } 179 copyMissingValues(sval, dval) 180 if copy { 181 dst.SetMapIndex(key, dval) 182 } 183 } 184 default: 185 if !dst.CanInterface() { 186 return 187 } 188 dval := dst.Interface() 189 zval := reflect.Zero(dst.Type()).Interface() 190 if reflect.DeepEqual(dval, zval) { 191 dst.Set(src) 192 } 193 } 194 } 195 196 func getHideTag(f *Field, tags map[string]string) { 197 var key, val string 198 key = fmt.Sprintf("%s.%s", "hide", f.Path) 199 if tags != nil { 200 val = tags[key] 201 } 202 if val == "" { 203 val = f.Tag.Get("hide") 204 } 205 f.Hide = val 206 }