github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/setstruct/setstruct.go (about) 1 package setstruct 2 3 import ( 4 "log" 5 "reflect" 6 "strconv" 7 "strings" 8 "time" 9 ) 10 11 // Set set struct fields by valueGenerator. 12 func Set(dstStructPtr interface{}, valueGenerator func(reflect.StructField) string) { 13 vv := reflect.ValueOf(dstStructPtr).Elem() 14 vt := vv.Type() 15 for i := 0; i < vv.NumField(); i++ { 16 f := vv.Field(i) 17 if !f.CanSet() { 18 continue 19 } 20 21 if v := valueGenerator(vt.Field(i)); v != "" { 22 SetField(f, v) 23 } 24 } 25 } 26 27 // SetField set struct field by its string representation. 28 func SetField(f reflect.Value, v string) { 29 t := f.Type() 30 if reflect.PtrTo(t).Implements(UpdaterType) { 31 if err := f.Addr().Interface().(Updater).ValueOf(v); err != nil { 32 log.Printf("W! failed to parse %s as %s, error:%v", v, t, err) 33 } 34 return 35 } 36 37 for typ, parser := range StringParserMap { 38 if t.AssignableTo(typ) { 39 if vv, err := parser(v); err != nil { 40 log.Printf("W! failed to parse %s as %s, error:%v", v, typ, err) 41 } else { 42 f.Set(vv.Convert(t)) 43 } 44 return 45 } 46 } 47 48 switch f.Kind() { 49 case reflect.String: 50 f.Set(reflect.ValueOf(v)) 51 case reflect.Bool: 52 f.SetBool(ParseBool(v)) 53 case reflect.Int, 54 reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 55 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint64: 56 if j, ok := ParseInt64(v); ok { 57 f.SetInt(j) 58 } 59 case reflect.Float32, reflect.Float64: 60 if j, ok := ParseFloat64(v); ok { 61 f.SetFloat(j) 62 } 63 } 64 } 65 66 // StringParserMap is the map from reflect type to a string parser. 67 var StringParserMap = map[reflect.Type]StringParser{} 68 69 // RegisterStringParser registers a string parser to a reflect type. 70 func RegisterStringParser(typ reflect.Type, parser StringParser) { 71 StringParserMap[typ] = parser 72 } 73 74 func init() { 75 RegisterStringParser(reflect.TypeOf(time.Duration(0)), func(s string) (reflect.Value, error) { 76 if d, err := time.ParseDuration(s); err != nil { 77 return reflect.Value{}, err 78 } else { 79 return reflect.ValueOf(d), nil 80 } 81 }) 82 RegisterStringParser(reflect.TypeOf([]string{}), func(s string) (reflect.Value, error) { 83 ss := strings.Split(s, ",") 84 sd := make([]string, 0, len(ss)) 85 for _, si := range ss { 86 if si = strings.TrimSpace(si); si != "" { 87 sd = append(sd, si) 88 } 89 } 90 91 return reflect.ValueOf(sd), nil 92 }) 93 RegisterStringParser(reflect.TypeOf(map[string]string{}), func(s string) (reflect.Value, error) { 94 return reflect.ValueOf(ParseStringToStringMap(s, ",", "=")), nil 95 }) 96 } 97 98 // StringParser is the func prototype to parse a string s to a reflect value. 99 type StringParser func(s string) (reflect.Value, error) 100 101 // Updater is the interface for a struct pointer receiver to be assigned a value by string s. 102 type Updater interface { 103 // ValueOf assigned by string s to the pointer receiver. 104 ValueOf(s string) error 105 } 106 107 // UpdaterType is the reflect type of Assigner interface. 108 var UpdaterType = reflect.TypeOf((*Updater)(nil)).Elem() 109 110 // ParseStringToStringMap parses a string to string map from a string. 111 func ParseStringToStringMap(val string, kkSep, kvSep string) map[string]string { 112 m := make(map[string]string) 113 for _, pair := range strings.Split(val, kkSep) { 114 kv := strings.SplitN(pair, kvSep, 2) 115 k := strings.TrimSpace(kv[0]) 116 if k == "" { 117 continue 118 } 119 if len(kv) == 2 { 120 m[k] = strings.TrimSpace(kv[1]) 121 } else { 122 m[k] = "" 123 } 124 } 125 return m 126 } 127 128 // ParseFloat64 parses string s as float64. 129 func ParseFloat64(s string) (float64, bool) { 130 if j, err := strconv.ParseFloat(s, 64); err == nil { 131 return j, true 132 } else { 133 log.Printf("W! failed to parse float64 %s, error: %v", s, err) 134 return 0, false 135 } 136 } 137 138 // ParseInt64 parses string s as int64. 139 func ParseInt64(s string) (int64, bool) { 140 if j, err := strconv.ParseInt(s, 10, 64); err == nil { 141 return j, true 142 } else { 143 log.Printf("W! failed to parse int64 %s, error: %v", s, err) 144 return 0, false 145 } 146 } 147 148 // ParseBool parses string s as a bool. 149 func ParseBool(s string) bool { 150 switch u := strings.ToLower(s); u { 151 case "1", "true", "t", "on", "yes", "y": 152 return true 153 } 154 155 return false 156 }