forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/redis/go-redis/v9/internal/hscan/hscan.go

338 lines
4.9 KiB
Go
Raw Normal View History

2024-02-18 10:42:21 +00:00
package hscan
import (
"errors"
"fmt"
"reflect"
"strconv"
)
// decoderFunc represents decoding functions for default built-in types.
2024-02-18 10:42:21 +00:00
type decoderFunc func(reflect.Value, string) error
// Scanner is the interface implemented by themselves,
2024-02-18 10:42:21 +00:00
// which will override the decoding behavior of decoderFunc.
2024-02-18 10:42:21 +00:00
type Scanner interface {
ScanRedis(s string) error
}
var (
2024-02-18 10:42:21 +00:00
// List of built-in decoders indexed by their numeric constant values (eg: reflect.Bool = 1).
2024-02-18 10:42:21 +00:00
decoders = []decoderFunc{
reflect.Bool: decodeBool,
reflect.Int: decodeInt,
reflect.Int8: decodeInt8,
reflect.Int16: decodeInt16,
reflect.Int32: decodeInt32,
reflect.Int64: decodeInt64,
reflect.Uint: decodeUint,
reflect.Uint8: decodeUint8,
reflect.Uint16: decodeUint16,
reflect.Uint32: decodeUint32,
reflect.Uint64: decodeUint64,
reflect.Float32: decodeFloat32,
reflect.Float64: decodeFloat64,
reflect.Complex64: decodeUnsupported,
reflect.Complex128: decodeUnsupported,
reflect.Array: decodeUnsupported,
reflect.Chan: decodeUnsupported,
reflect.Func: decodeUnsupported,
reflect.Interface: decodeUnsupported,
reflect.Map: decodeUnsupported,
reflect.Ptr: decodeUnsupported,
reflect.Slice: decodeSlice,
reflect.String: decodeString,
reflect.Struct: decodeUnsupported,
2024-02-18 10:42:21 +00:00
reflect.UnsafePointer: decodeUnsupported,
}
// Global map of struct field specs that is populated once for every new
2024-02-18 10:42:21 +00:00
// struct type that is scanned. This caches the field types and the corresponding
2024-02-18 10:42:21 +00:00
// decoder functions to avoid iterating through struct fields on subsequent scans.
2024-02-18 10:42:21 +00:00
globalStructMap = newStructMap()
)
func Struct(dst interface{}) (StructValue, error) {
2024-02-18 10:42:21 +00:00
v := reflect.ValueOf(dst)
// The destination to scan into should be a struct pointer.
2024-02-18 10:42:21 +00:00
if v.Kind() != reflect.Ptr || v.IsNil() {
2024-02-18 10:42:21 +00:00
return StructValue{}, fmt.Errorf("redis.Scan(non-pointer %T)", dst)
2024-02-18 10:42:21 +00:00
}
v = v.Elem()
2024-02-18 10:42:21 +00:00
if v.Kind() != reflect.Struct {
2024-02-18 10:42:21 +00:00
return StructValue{}, fmt.Errorf("redis.Scan(non-struct %T)", dst)
2024-02-18 10:42:21 +00:00
}
return StructValue{
spec: globalStructMap.get(v.Type()),
2024-02-18 10:42:21 +00:00
value: v,
}, nil
2024-02-18 10:42:21 +00:00
}
// Scan scans the results from a key-value Redis map result set to a destination struct.
2024-02-18 10:42:21 +00:00
// The Redis keys are matched to the struct's field with the `redis` tag.
2024-02-18 10:42:21 +00:00
func Scan(dst interface{}, keys []interface{}, vals []interface{}) error {
2024-02-18 10:42:21 +00:00
if len(keys) != len(vals) {
2024-02-18 10:42:21 +00:00
return errors.New("args should have the same number of keys and vals")
2024-02-18 10:42:21 +00:00
}
strct, err := Struct(dst)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
// Iterate through the (key, value) sequence.
2024-02-18 10:42:21 +00:00
for i := 0; i < len(vals); i++ {
2024-02-18 10:42:21 +00:00
key, ok := keys[i].(string)
2024-02-18 10:42:21 +00:00
if !ok {
2024-02-18 10:42:21 +00:00
continue
2024-02-18 10:42:21 +00:00
}
val, ok := vals[i].(string)
2024-02-18 10:42:21 +00:00
if !ok {
2024-02-18 10:42:21 +00:00
continue
2024-02-18 10:42:21 +00:00
}
if err := strct.Scan(key, val); err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
return nil
2024-02-18 10:42:21 +00:00
}
func decodeBool(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
b, err := strconv.ParseBool(s)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
f.SetBool(b)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func decodeInt8(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return decodeNumber(f, s, 8)
2024-02-18 10:42:21 +00:00
}
func decodeInt16(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return decodeNumber(f, s, 16)
2024-02-18 10:42:21 +00:00
}
func decodeInt32(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return decodeNumber(f, s, 32)
2024-02-18 10:42:21 +00:00
}
func decodeInt64(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return decodeNumber(f, s, 64)
2024-02-18 10:42:21 +00:00
}
func decodeInt(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return decodeNumber(f, s, 0)
2024-02-18 10:42:21 +00:00
}
func decodeNumber(f reflect.Value, s string, bitSize int) error {
2024-02-18 10:42:21 +00:00
v, err := strconv.ParseInt(s, 10, bitSize)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
f.SetInt(v)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func decodeUint8(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return decodeUnsignedNumber(f, s, 8)
2024-02-18 10:42:21 +00:00
}
func decodeUint16(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return decodeUnsignedNumber(f, s, 16)
2024-02-18 10:42:21 +00:00
}
func decodeUint32(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return decodeUnsignedNumber(f, s, 32)
2024-02-18 10:42:21 +00:00
}
func decodeUint64(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return decodeUnsignedNumber(f, s, 64)
2024-02-18 10:42:21 +00:00
}
func decodeUint(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return decodeUnsignedNumber(f, s, 0)
2024-02-18 10:42:21 +00:00
}
func decodeUnsignedNumber(f reflect.Value, s string, bitSize int) error {
2024-02-18 10:42:21 +00:00
v, err := strconv.ParseUint(s, 10, bitSize)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
f.SetUint(v)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func decodeFloat32(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
v, err := strconv.ParseFloat(s, 32)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
f.SetFloat(v)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
// although the default is float64, but we better define it.
2024-02-18 10:42:21 +00:00
func decodeFloat64(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
v, err := strconv.ParseFloat(s, 64)
2024-02-18 10:42:21 +00:00
if err != nil {
2024-02-18 10:42:21 +00:00
return err
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
f.SetFloat(v)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func decodeString(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
f.SetString(s)
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func decodeSlice(f reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
// []byte slice ([]uint8).
2024-02-18 10:42:21 +00:00
if f.Type().Elem().Kind() == reflect.Uint8 {
2024-02-18 10:42:21 +00:00
f.SetBytes([]byte(s))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
func decodeUnsupported(v reflect.Value, s string) error {
2024-02-18 10:42:21 +00:00
return fmt.Errorf("redis.Scan(unsupported %s)", v.Type())
2024-02-18 10:42:21 +00:00
}