2025-08-27 21:03:25 +02:00
|
|
|
package bind
|
|
|
|
|
|
|
|
|
|
import (
|
2025-08-31 01:23:21 +02:00
|
|
|
"errors"
|
2025-08-27 21:03:25 +02:00
|
|
|
"fmt"
|
2025-09-05 23:33:19 +02:00
|
|
|
"math"
|
2025-08-27 21:03:25 +02:00
|
|
|
"reflect"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
2025-08-31 01:23:21 +02:00
|
|
|
"time"
|
2025-08-27 21:03:25 +02:00
|
|
|
)
|
|
|
|
|
|
2025-08-31 01:23:21 +02:00
|
|
|
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,
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-27 21:03:25 +02:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-05 23:33:19 +02:00
|
|
|
func floatToTime(f float64) time.Time {
|
|
|
|
|
s := int64(f)
|
|
|
|
|
ns := int64((f - float64(s)) * 1_000_000_000)
|
|
|
|
|
return time.Unix(s, ns)
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-27 21:03:25 +02:00
|
|
|
func scanConvert(t reflect.Type, v any) (any, bool) {
|
2025-08-31 17:11:09 +02:00
|
|
|
if isAny(t) {
|
|
|
|
|
return v, true
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-27 21:03:25 +02:00
|
|
|
r := reflect.ValueOf(v)
|
2025-09-05 23:33:19 +02:00
|
|
|
if r.CanConvert(t) {
|
|
|
|
|
return r.Convert(t).Interface(), true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t != reflect.TypeFor[time.Time]() {
|
|
|
|
|
return nil, false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fi := reflect.TypeFor[float64]()
|
|
|
|
|
if !r.CanConvert(fi) {
|
2025-08-27 21:03:25 +02:00
|
|
|
return nil, false
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-05 23:33:19 +02:00
|
|
|
f := r.Convert(fi).Interface().(float64)
|
|
|
|
|
return floatToTime(f), true
|
2025-08-27 21:03:25 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-31 01:23:21 +02:00
|
|
|
func parseTime(s string) (any, error) {
|
2025-09-05 23:33:19 +02:00
|
|
|
const errMsg = "failed to parse time"
|
2025-08-31 01:23:21 +02:00
|
|
|
for _, l := range timeLayouts {
|
|
|
|
|
if t, err := time.Parse(l, s); err == nil {
|
|
|
|
|
return t, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-05 23:33:19 +02:00
|
|
|
ss := strings.Split(s, ".")
|
|
|
|
|
if len(ss) > 2 {
|
|
|
|
|
return nil, errors.New(errMsg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(ss) == 1 {
|
|
|
|
|
i, err := parseInt(ss[0], 8)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.New(errMsg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return time.Unix(i, 0), nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sec, err := parseInt(ss[0], 8)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.New(errMsg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dec := strings.TrimLeft(ss[1], "0")
|
|
|
|
|
i, err := parseInt(dec, 8)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, errors.New(errMsg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
zeros := len(ss[1]) - len(dec)
|
|
|
|
|
nanosec := int64(float64(i) * math.Pow10(9-zeros-len(dec)))
|
|
|
|
|
return time.Unix(sec, nanosec), nil
|
2025-08-31 01:23:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-08-27 21:03:25 +02:00
|
|
|
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:
|
2025-08-31 01:23:21 +02:00
|
|
|
if isDuration(t) {
|
|
|
|
|
v, err = time.ParseDuration(s)
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-03 22:12:13 +02:00
|
|
|
if !isDuration(t) || err != nil {
|
2025-08-31 01:23:21 +02:00
|
|
|
v, err = parseInt(s, int(t.Size()))
|
|
|
|
|
}
|
2025-08-27 21:03:25 +02:00
|
|
|
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:
|
2025-08-31 01:23:21 +02:00
|
|
|
if isTime(t) {
|
|
|
|
|
v, err = parseTime(s)
|
|
|
|
|
} else {
|
|
|
|
|
return nil, false
|
|
|
|
|
}
|
2025-08-27 21:03:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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))
|
|
|
|
|
}
|