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  }