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