1
0
bind/scan.go

83 lines
1.7 KiB
Go
Raw Normal View History

2025-08-27 21:03:25 +02:00
package bind
import (
"fmt"
"reflect"
"strconv"
"strings"
)
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) {
r := reflect.ValueOf(v)
if !r.CanConvert(t) {
return nil, false
}
return r.Convert(t).Interface(), true
}
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:
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:
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) {
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))
}