package bind import ( "errors" "fmt" "reflect" "strconv" "strings" "time" ) var timeLayouts = []string{ time.RFC3339, time.RFC3339Nano, time.DateTime, time.DateOnly, time.TimeOnly, time.RFC822, time.RFC822Z, time.RFC850, time.RFC1123, time.RFC1123Z, time.ANSIC, time.UnixDate, time.RubyDate, time.Kitchen, time.Layout, time.Stamp, time.StampMilli, time.StampMicro, time.StampNano, } func intParse[T any](parse func(string, int, int) (T, error), s string, byteSize int) (T, error) { bitSize := byteSize * 8 switch { case strings.HasPrefix(s, "0b"): return parse(s[2:], 2, bitSize) case strings.HasPrefix(s, "0x"): return parse(s[2:], 16, bitSize) case strings.HasPrefix(s, "0"): return parse(s[1:], 8, bitSize) default: return parse(s, 10, bitSize) } } func parseInt(s string, byteSize int) (int64, error) { return intParse(strconv.ParseInt, s, byteSize) } func parseUint(s string, byteSize int) (uint64, error) { return intParse(strconv.ParseUint, s, byteSize) } func scanConvert(t reflect.Type, v any) (any, bool) { if isAny(t) { return v, true } r := reflect.ValueOf(v) if !r.CanConvert(t) { return nil, false } return r.Convert(t).Interface(), true } func parseTime(s string) (any, error) { for _, l := range timeLayouts { if t, err := time.Parse(l, s); err == nil { return t, nil } } return time.Time{}, errors.New("failed to parse time") } func scanString(t reflect.Type, s string) (any, bool) { var ( v any err error ) switch t.Kind() { case reflect.Bool: v, err = strconv.ParseBool(s) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: if isDuration(t) { v, err = time.ParseDuration(s) } if !isDuration(t) || err != nil { v, err = parseInt(s, int(t.Size())) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: v, err = parseUint(s, int(t.Size())) case reflect.Float32, reflect.Float64: v, err = strconv.ParseFloat(s, int(t.Size())*8) case reflect.String: v = s default: if isTime(t) { v, err = parseTime(s) } else { return nil, false } } if err != nil { return nil, false } p := reflect.New(t) p.Elem().Set(reflect.ValueOf(v).Convert(t)) return p.Elem().Interface(), true } func scan(t reflect.Type, v any) (any, bool) { // time and duration support if vv, ok := scanConvert(t, v); ok { return vv, true } r := reflect.ValueOf(v) if r.Kind() != reflect.String { return nil, false } return scanString(t, fmt.Sprint(v)) }