-
Notifications
You must be signed in to change notification settings - Fork 40
/
Copy pathscan.go
118 lines (105 loc) · 2.48 KB
/
scan.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package excel
import (
"encoding"
"fmt"
"reflect"
"github.com/szyhf/go-convert"
)
// ref: gopkg.in/redis.v5
func scanByDefault(s string, ptr interface{}, def string) error {
err := scan(s, ptr)
if err != nil {
err = scan(def, ptr)
}
return err
}
func scan(s string, ptr interface{}) error {
var err error
switch p := ptr.(type) {
case nil:
return ErrScanNil
case *string:
*p = s
case *[]byte:
*p = []byte(s)
case *[]rune:
*p = []rune(s)
case *int:
*p, err = convert.ToInt(s)
case *int8:
*p, err = convert.ToInt8(s)
case *int16:
*p, err = convert.ToInt16(s)
case *int32:
*p, err = convert.ToInt32(s)
case *int64:
*p, err = convert.ToInt64(s)
case *uint:
*p, err = convert.ToUint(s)
case *uint8:
*p, err = convert.ToUint8(s)
case *uint16:
*p, err = convert.ToUint16(s)
case *uint32:
*p, err = convert.ToUint32(s)
case *uint64:
*p, err = convert.ToUint64(s)
case *float32:
*p, err = convert.ToFloat32(s)
case *float64:
*p, err = convert.ToFloat64(s)
case *bool:
*p, err = convert.ToBool(s)
case encoding.BinaryUnmarshaler:
if err = p.UnmarshalBinary([]byte(s)); err != nil {
err = fmt.Errorf("can't unmarshar by encoding.BinaryUnmarshaler: %s", err)
}
default:
err = fmt.Errorf("can't unmarshal %T (consider implementing encoding.BinaryUnmarshaler)", p)
}
return err
}
func scanSlice(data []string, sliceValue reflect.Value) error {
if !sliceValue.IsValid() {
return fmt.Errorf("ScanSlice(nil)")
}
if sliceValue.Kind() != reflect.Ptr {
return fmt.Errorf("ScanSlice(non-pointer %s)", sliceValue.Kind())
}
sliceValue = sliceValue.Elem()
if sliceValue.Kind() != reflect.Slice {
return fmt.Errorf("ScanSlice(non-slice %s)", sliceValue.Kind())
}
for i, s := range data {
elem := sliceNextElem(sliceValue)
if err := scan(s, elem.Addr().Interface()); err != nil {
return fmt.Errorf("ScanSlice(index=%d value=%q) failed: %s", i, s, err)
}
}
return nil
}
func sliceNextElem(v reflect.Value) reflect.Value {
elemType := v.Type().Elem()
if v.Len() < v.Cap() {
v.Set(v.Slice(0, v.Len()+1))
elem := v.Index(v.Len() - 1)
if elem.Kind() == reflect.Ptr {
if elem.IsNil() {
elem.Set(reflect.New(elemType.Elem()))
}
elem = elem.Elem()
}
return elem
}
if elemType.Kind() == reflect.Ptr {
elem := reflect.New(elemType.Elem())
v.Set(reflect.Append(v, elem))
return elem.Elem()
}
v.Set(reflect.Append(v, reflect.Zero(elemType)))
return v.Index(v.Len() - 1)
}
// keep to ignore lint warning
var (
_ = scanByDefault
)