1 package proto
2
3 import (
4 "encoding"
5 "fmt"
6 "net"
7 "reflect"
8 "time"
9
10 "github.com/redis/go-redis/v9/internal/util"
11 )
12
13
14
15
16 func Scan(b []byte, v interface{}) error {
17 switch v := v.(type) {
18 case nil:
19 return fmt.Errorf("redis: Scan(nil)")
20 case *string:
21 *v = util.BytesToString(b)
22 return nil
23 case *[]byte:
24 *v = b
25 return nil
26 case *int:
27 var err error
28 *v, err = util.Atoi(b)
29 return err
30 case *int8:
31 n, err := util.ParseInt(b, 10, 8)
32 if err != nil {
33 return err
34 }
35 *v = int8(n)
36 return nil
37 case *int16:
38 n, err := util.ParseInt(b, 10, 16)
39 if err != nil {
40 return err
41 }
42 *v = int16(n)
43 return nil
44 case *int32:
45 n, err := util.ParseInt(b, 10, 32)
46 if err != nil {
47 return err
48 }
49 *v = int32(n)
50 return nil
51 case *int64:
52 n, err := util.ParseInt(b, 10, 64)
53 if err != nil {
54 return err
55 }
56 *v = n
57 return nil
58 case *uint:
59 n, err := util.ParseUint(b, 10, 64)
60 if err != nil {
61 return err
62 }
63 *v = uint(n)
64 return nil
65 case *uint8:
66 n, err := util.ParseUint(b, 10, 8)
67 if err != nil {
68 return err
69 }
70 *v = uint8(n)
71 return nil
72 case *uint16:
73 n, err := util.ParseUint(b, 10, 16)
74 if err != nil {
75 return err
76 }
77 *v = uint16(n)
78 return nil
79 case *uint32:
80 n, err := util.ParseUint(b, 10, 32)
81 if err != nil {
82 return err
83 }
84 *v = uint32(n)
85 return nil
86 case *uint64:
87 n, err := util.ParseUint(b, 10, 64)
88 if err != nil {
89 return err
90 }
91 *v = n
92 return nil
93 case *float32:
94 n, err := util.ParseFloat(b, 32)
95 if err != nil {
96 return err
97 }
98 *v = float32(n)
99 return err
100 case *float64:
101 var err error
102 *v, err = util.ParseFloat(b, 64)
103 return err
104 case *bool:
105 *v = len(b) == 1 && b[0] == '1'
106 return nil
107 case *time.Time:
108 var err error
109 *v, err = time.Parse(time.RFC3339Nano, util.BytesToString(b))
110 return err
111 case *time.Duration:
112 n, err := util.ParseInt(b, 10, 64)
113 if err != nil {
114 return err
115 }
116 *v = time.Duration(n)
117 return nil
118 case encoding.BinaryUnmarshaler:
119 return v.UnmarshalBinary(b)
120 case *net.IP:
121 *v = b
122 return nil
123 default:
124 return fmt.Errorf(
125 "redis: can't unmarshal %T (consider implementing BinaryUnmarshaler)", v)
126 }
127 }
128
129 func ScanSlice(data []string, slice interface{}) error {
130 v := reflect.ValueOf(slice)
131 if !v.IsValid() {
132 return fmt.Errorf("redis: ScanSlice(nil)")
133 }
134 if v.Kind() != reflect.Ptr {
135 return fmt.Errorf("redis: ScanSlice(non-pointer %T)", slice)
136 }
137 v = v.Elem()
138 if v.Kind() != reflect.Slice {
139 return fmt.Errorf("redis: ScanSlice(non-slice %T)", slice)
140 }
141
142 next := makeSliceNextElemFunc(v)
143 for i, s := range data {
144 elem := next()
145 if err := Scan([]byte(s), elem.Addr().Interface()); err != nil {
146 err = fmt.Errorf("redis: ScanSlice index=%d value=%q failed: %w", i, s, err)
147 return err
148 }
149 }
150
151 return nil
152 }
153
154 func makeSliceNextElemFunc(v reflect.Value) func() reflect.Value {
155 elemType := v.Type().Elem()
156
157 if elemType.Kind() == reflect.Ptr {
158 elemType = elemType.Elem()
159 return func() reflect.Value {
160 if v.Len() < v.Cap() {
161 v.Set(v.Slice(0, v.Len()+1))
162 elem := v.Index(v.Len() - 1)
163 if elem.IsNil() {
164 elem.Set(reflect.New(elemType))
165 }
166 return elem.Elem()
167 }
168
169 elem := reflect.New(elemType)
170 v.Set(reflect.Append(v, elem))
171 return elem.Elem()
172 }
173 }
174
175 zero := reflect.Zero(elemType)
176 return func() reflect.Value {
177 if v.Len() < v.Cap() {
178 v.Set(v.Slice(0, v.Len()+1))
179 return v.Index(v.Len() - 1)
180 }
181
182 v.Set(reflect.Append(v, zero))
183 return v.Index(v.Len() - 1)
184 }
185 }
186
View as plain text