github.com/fluhus/gostuff@v0.4.1-0.20240331134726-be71864f2b5d/csvdec/fill.go (about) 1 package csvdec 2 3 import ( 4 "fmt" 5 "reflect" 6 "strconv" 7 ) 8 9 //go:generate go run github.com/fluhus/goat -i fillslice.got -o fillslice.go 10 11 // TODO(amit): Support bool slices. 12 13 // Populates a value's fields with the values in slice s. 14 // Value is assumed to be a struct. 15 func fillStruct(value reflect.Value, s []string) error { 16 // Check number of fields. 17 expectedLength := value.NumField() 18 if value.Field(value.NumField()-1).Kind() == reflect.Slice { 19 expectedLength-- 20 } 21 if len(s) < expectedLength { 22 return fmt.Errorf("not enough values to populate all fields (%d/%d)", 23 len(s), value.NumField()) 24 } 25 26 // Go over fields. 27 for i := 0; i < value.NumField(); i++ { 28 field := value.Field(i) 29 kind := field.Kind() 30 31 if !field.CanSet() { 32 panic(fmt.Errorf("Field %d cannot be set. Is it unexported?", i)) 33 } 34 35 // Assign value according to type. 36 switch { 37 case kind == reflect.String: 38 field.SetString(s[i]) 39 40 case kind >= reflect.Int && kind <= reflect.Int64: 41 v, err := strconv.ParseInt(s[i], 0, 64) 42 if err != nil { 43 return fmt.Errorf("field %d: %v", i, err) 44 } 45 field.SetInt(v) 46 47 case kind >= reflect.Uint && kind <= reflect.Uint64: 48 v, err := strconv.ParseUint(s[i], 0, 64) 49 if err != nil { 50 return fmt.Errorf("field %d: %v", i, err) 51 } 52 field.SetUint(v) 53 54 case kind == reflect.Float64 || kind == reflect.Float32: 55 v, err := strconv.ParseFloat(s[i], 64) 56 if err != nil { 57 return fmt.Errorf("field %d: %v", i, err) 58 } 59 field.SetFloat(v) 60 61 case kind == reflect.Bool: 62 v, err := strconv.ParseBool(s[i]) 63 if err != nil { 64 return fmt.Errorf("field %d: %v", i, err) 65 } 66 field.SetBool(v) 67 68 case kind == reflect.Slice: 69 if i != value.NumField()-1 { 70 panic(fmt.Sprintf("Field %v is a slice. A slice may only be"+ 71 " the last field.", i)) 72 } 73 if err := fillSlice(field, s[i:]); err != nil { 74 return fmt.Errorf("field %v: %v", i, err) 75 } 76 77 default: 78 panic(fmt.Sprintf("Field %d is of an unsupported type: %v", 79 i, kind)) 80 } 81 } 82 83 return nil 84 }