1package redis
2
3import (
4	"context"
5	"fmt"
6	"net"
7	"strconv"
8	"time"
9
10	"github.com/go-redis/redis/v8/internal"
11	"github.com/go-redis/redis/v8/internal/proto"
12	"github.com/go-redis/redis/v8/internal/util"
13)
14
15type Cmder interface {
16	Name() string
17	FullName() string
18	Args() []interface{}
19	String() string
20	stringArg(int) string
21	firstKeyPos() int8
22	setFirstKeyPos(int8)
23
24	readTimeout() *time.Duration
25	readReply(rd *proto.Reader) error
26
27	SetErr(error)
28	Err() error
29}
30
31func setCmdsErr(cmds []Cmder, e error) {
32	for _, cmd := range cmds {
33		if cmd.Err() == nil {
34			cmd.SetErr(e)
35		}
36	}
37}
38
39func cmdsFirstErr(cmds []Cmder) error {
40	for _, cmd := range cmds {
41		if err := cmd.Err(); err != nil {
42			return err
43		}
44	}
45	return nil
46}
47
48func writeCmds(wr *proto.Writer, cmds []Cmder) error {
49	for _, cmd := range cmds {
50		if err := writeCmd(wr, cmd); err != nil {
51			return err
52		}
53	}
54	return nil
55}
56
57func writeCmd(wr *proto.Writer, cmd Cmder) error {
58	return wr.WriteArgs(cmd.Args())
59}
60
61func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int {
62	if pos := cmd.firstKeyPos(); pos != 0 {
63		return int(pos)
64	}
65
66	switch cmd.Name() {
67	case "eval", "evalsha":
68		if cmd.stringArg(2) != "0" {
69			return 3
70		}
71
72		return 0
73	case "publish":
74		return 1
75	case "memory":
76		// https://github.com/redis/redis/issues/7493
77		if cmd.stringArg(1) == "usage" {
78			return 2
79		}
80	}
81
82	if info != nil {
83		return int(info.FirstKeyPos)
84	}
85	return 0
86}
87
88func cmdString(cmd Cmder, val interface{}) string {
89	b := make([]byte, 0, 64)
90
91	for i, arg := range cmd.Args() {
92		if i > 0 {
93			b = append(b, ' ')
94		}
95		b = internal.AppendArg(b, arg)
96	}
97
98	if err := cmd.Err(); err != nil {
99		b = append(b, ": "...)
100		b = append(b, err.Error()...)
101	} else if val != nil {
102		b = append(b, ": "...)
103		b = internal.AppendArg(b, val)
104	}
105
106	return internal.String(b)
107}
108
109//------------------------------------------------------------------------------
110
111type baseCmd struct {
112	ctx    context.Context
113	args   []interface{}
114	err    error
115	keyPos int8
116
117	_readTimeout *time.Duration
118}
119
120var _ Cmder = (*Cmd)(nil)
121
122func (cmd *baseCmd) Name() string {
123	if len(cmd.args) == 0 {
124		return ""
125	}
126	// Cmd name must be lower cased.
127	return internal.ToLower(cmd.stringArg(0))
128}
129
130func (cmd *baseCmd) FullName() string {
131	switch name := cmd.Name(); name {
132	case "cluster", "command":
133		if len(cmd.args) == 1 {
134			return name
135		}
136		if s2, ok := cmd.args[1].(string); ok {
137			return name + " " + s2
138		}
139		return name
140	default:
141		return name
142	}
143}
144
145func (cmd *baseCmd) Args() []interface{} {
146	return cmd.args
147}
148
149func (cmd *baseCmd) stringArg(pos int) string {
150	if pos < 0 || pos >= len(cmd.args) {
151		return ""
152	}
153	s, _ := cmd.args[pos].(string)
154	return s
155}
156
157func (cmd *baseCmd) firstKeyPos() int8 {
158	return cmd.keyPos
159}
160
161func (cmd *baseCmd) setFirstKeyPos(keyPos int8) {
162	cmd.keyPos = keyPos
163}
164
165func (cmd *baseCmd) SetErr(e error) {
166	cmd.err = e
167}
168
169func (cmd *baseCmd) Err() error {
170	return cmd.err
171}
172
173func (cmd *baseCmd) readTimeout() *time.Duration {
174	return cmd._readTimeout
175}
176
177func (cmd *baseCmd) setReadTimeout(d time.Duration) {
178	cmd._readTimeout = &d
179}
180
181//------------------------------------------------------------------------------
182
183type Cmd struct {
184	baseCmd
185
186	val interface{}
187}
188
189func NewCmd(ctx context.Context, args ...interface{}) *Cmd {
190	return &Cmd{
191		baseCmd: baseCmd{
192			ctx:  ctx,
193			args: args,
194		},
195	}
196}
197
198func (cmd *Cmd) String() string {
199	return cmdString(cmd, cmd.val)
200}
201
202func (cmd *Cmd) Val() interface{} {
203	return cmd.val
204}
205
206func (cmd *Cmd) Result() (interface{}, error) {
207	return cmd.val, cmd.err
208}
209
210func (cmd *Cmd) Text() (string, error) {
211	if cmd.err != nil {
212		return "", cmd.err
213	}
214	switch val := cmd.val.(type) {
215	case string:
216		return val, nil
217	default:
218		err := fmt.Errorf("redis: unexpected type=%T for String", val)
219		return "", err
220	}
221}
222
223func (cmd *Cmd) Int() (int, error) {
224	if cmd.err != nil {
225		return 0, cmd.err
226	}
227	switch val := cmd.val.(type) {
228	case int64:
229		return int(val), nil
230	case string:
231		return strconv.Atoi(val)
232	default:
233		err := fmt.Errorf("redis: unexpected type=%T for Int", val)
234		return 0, err
235	}
236}
237
238func (cmd *Cmd) Int64() (int64, error) {
239	if cmd.err != nil {
240		return 0, cmd.err
241	}
242	switch val := cmd.val.(type) {
243	case int64:
244		return val, nil
245	case string:
246		return strconv.ParseInt(val, 10, 64)
247	default:
248		err := fmt.Errorf("redis: unexpected type=%T for Int64", val)
249		return 0, err
250	}
251}
252
253func (cmd *Cmd) Uint64() (uint64, error) {
254	if cmd.err != nil {
255		return 0, cmd.err
256	}
257	switch val := cmd.val.(type) {
258	case int64:
259		return uint64(val), nil
260	case string:
261		return strconv.ParseUint(val, 10, 64)
262	default:
263		err := fmt.Errorf("redis: unexpected type=%T for Uint64", val)
264		return 0, err
265	}
266}
267
268func (cmd *Cmd) Float32() (float32, error) {
269	if cmd.err != nil {
270		return 0, cmd.err
271	}
272	switch val := cmd.val.(type) {
273	case int64:
274		return float32(val), nil
275	case string:
276		f, err := strconv.ParseFloat(val, 32)
277		if err != nil {
278			return 0, err
279		}
280		return float32(f), nil
281	default:
282		err := fmt.Errorf("redis: unexpected type=%T for Float32", val)
283		return 0, err
284	}
285}
286
287func (cmd *Cmd) Float64() (float64, error) {
288	if cmd.err != nil {
289		return 0, cmd.err
290	}
291	switch val := cmd.val.(type) {
292	case int64:
293		return float64(val), nil
294	case string:
295		return strconv.ParseFloat(val, 64)
296	default:
297		err := fmt.Errorf("redis: unexpected type=%T for Float64", val)
298		return 0, err
299	}
300}
301
302func (cmd *Cmd) Bool() (bool, error) {
303	if cmd.err != nil {
304		return false, cmd.err
305	}
306	switch val := cmd.val.(type) {
307	case int64:
308		return val != 0, nil
309	case string:
310		return strconv.ParseBool(val)
311	default:
312		err := fmt.Errorf("redis: unexpected type=%T for Bool", val)
313		return false, err
314	}
315}
316
317func (cmd *Cmd) readReply(rd *proto.Reader) (err error) {
318	cmd.val, err = rd.ReadReply(sliceParser)
319	return err
320}
321
322// sliceParser implements proto.MultiBulkParse.
323func sliceParser(rd *proto.Reader, n int64) (interface{}, error) {
324	vals := make([]interface{}, n)
325	for i := 0; i < len(vals); i++ {
326		v, err := rd.ReadReply(sliceParser)
327		if err != nil {
328			if err == Nil {
329				vals[i] = nil
330				continue
331			}
332			if err, ok := err.(proto.RedisError); ok {
333				vals[i] = err
334				continue
335			}
336			return nil, err
337		}
338		vals[i] = v
339	}
340	return vals, nil
341}
342
343//------------------------------------------------------------------------------
344
345type SliceCmd struct {
346	baseCmd
347
348	val []interface{}
349}
350
351var _ Cmder = (*SliceCmd)(nil)
352
353func NewSliceCmd(ctx context.Context, args ...interface{}) *SliceCmd {
354	return &SliceCmd{
355		baseCmd: baseCmd{
356			ctx:  ctx,
357			args: args,
358		},
359	}
360}
361
362func (cmd *SliceCmd) Val() []interface{} {
363	return cmd.val
364}
365
366func (cmd *SliceCmd) Result() ([]interface{}, error) {
367	return cmd.val, cmd.err
368}
369
370func (cmd *SliceCmd) String() string {
371	return cmdString(cmd, cmd.val)
372}
373
374func (cmd *SliceCmd) readReply(rd *proto.Reader) error {
375	v, err := rd.ReadArrayReply(sliceParser)
376	if err != nil {
377		return err
378	}
379	cmd.val = v.([]interface{})
380	return nil
381}
382
383//------------------------------------------------------------------------------
384
385type StatusCmd struct {
386	baseCmd
387
388	val string
389}
390
391var _ Cmder = (*StatusCmd)(nil)
392
393func NewStatusCmd(ctx context.Context, args ...interface{}) *StatusCmd {
394	return &StatusCmd{
395		baseCmd: baseCmd{
396			ctx:  ctx,
397			args: args,
398		},
399	}
400}
401
402func (cmd *StatusCmd) Val() string {
403	return cmd.val
404}
405
406func (cmd *StatusCmd) Result() (string, error) {
407	return cmd.val, cmd.err
408}
409
410func (cmd *StatusCmd) String() string {
411	return cmdString(cmd, cmd.val)
412}
413
414func (cmd *StatusCmd) readReply(rd *proto.Reader) (err error) {
415	cmd.val, err = rd.ReadString()
416	return err
417}
418
419//------------------------------------------------------------------------------
420
421type IntCmd struct {
422	baseCmd
423
424	val int64
425}
426
427var _ Cmder = (*IntCmd)(nil)
428
429func NewIntCmd(ctx context.Context, args ...interface{}) *IntCmd {
430	return &IntCmd{
431		baseCmd: baseCmd{
432			ctx:  ctx,
433			args: args,
434		},
435	}
436}
437
438func (cmd *IntCmd) Val() int64 {
439	return cmd.val
440}
441
442func (cmd *IntCmd) Result() (int64, error) {
443	return cmd.val, cmd.err
444}
445
446func (cmd *IntCmd) Uint64() (uint64, error) {
447	return uint64(cmd.val), cmd.err
448}
449
450func (cmd *IntCmd) String() string {
451	return cmdString(cmd, cmd.val)
452}
453
454func (cmd *IntCmd) readReply(rd *proto.Reader) (err error) {
455	cmd.val, err = rd.ReadIntReply()
456	return err
457}
458
459//------------------------------------------------------------------------------
460
461type IntSliceCmd struct {
462	baseCmd
463
464	val []int64
465}
466
467var _ Cmder = (*IntSliceCmd)(nil)
468
469func NewIntSliceCmd(ctx context.Context, args ...interface{}) *IntSliceCmd {
470	return &IntSliceCmd{
471		baseCmd: baseCmd{
472			ctx:  ctx,
473			args: args,
474		},
475	}
476}
477
478func (cmd *IntSliceCmd) Val() []int64 {
479	return cmd.val
480}
481
482func (cmd *IntSliceCmd) Result() ([]int64, error) {
483	return cmd.val, cmd.err
484}
485
486func (cmd *IntSliceCmd) String() string {
487	return cmdString(cmd, cmd.val)
488}
489
490func (cmd *IntSliceCmd) readReply(rd *proto.Reader) error {
491	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
492		cmd.val = make([]int64, n)
493		for i := 0; i < len(cmd.val); i++ {
494			num, err := rd.ReadIntReply()
495			if err != nil {
496				return nil, err
497			}
498			cmd.val[i] = num
499		}
500		return nil, nil
501	})
502	return err
503}
504
505//------------------------------------------------------------------------------
506
507type DurationCmd struct {
508	baseCmd
509
510	val       time.Duration
511	precision time.Duration
512}
513
514var _ Cmder = (*DurationCmd)(nil)
515
516func NewDurationCmd(ctx context.Context, precision time.Duration, args ...interface{}) *DurationCmd {
517	return &DurationCmd{
518		baseCmd: baseCmd{
519			ctx:  ctx,
520			args: args,
521		},
522		precision: precision,
523	}
524}
525
526func (cmd *DurationCmd) Val() time.Duration {
527	return cmd.val
528}
529
530func (cmd *DurationCmd) Result() (time.Duration, error) {
531	return cmd.val, cmd.err
532}
533
534func (cmd *DurationCmd) String() string {
535	return cmdString(cmd, cmd.val)
536}
537
538func (cmd *DurationCmd) readReply(rd *proto.Reader) error {
539	n, err := rd.ReadIntReply()
540	if err != nil {
541		return err
542	}
543	switch n {
544	// -2 if the key does not exist
545	// -1 if the key exists but has no associated expire
546	case -2, -1:
547		cmd.val = time.Duration(n)
548	default:
549		cmd.val = time.Duration(n) * cmd.precision
550	}
551	return nil
552}
553
554//------------------------------------------------------------------------------
555
556type TimeCmd struct {
557	baseCmd
558
559	val time.Time
560}
561
562var _ Cmder = (*TimeCmd)(nil)
563
564func NewTimeCmd(ctx context.Context, args ...interface{}) *TimeCmd {
565	return &TimeCmd{
566		baseCmd: baseCmd{
567			ctx:  ctx,
568			args: args,
569		},
570	}
571}
572
573func (cmd *TimeCmd) Val() time.Time {
574	return cmd.val
575}
576
577func (cmd *TimeCmd) Result() (time.Time, error) {
578	return cmd.val, cmd.err
579}
580
581func (cmd *TimeCmd) String() string {
582	return cmdString(cmd, cmd.val)
583}
584
585func (cmd *TimeCmd) readReply(rd *proto.Reader) error {
586	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
587		if n != 2 {
588			return nil, fmt.Errorf("got %d elements, expected 2", n)
589		}
590
591		sec, err := rd.ReadInt()
592		if err != nil {
593			return nil, err
594		}
595
596		microsec, err := rd.ReadInt()
597		if err != nil {
598			return nil, err
599		}
600
601		cmd.val = time.Unix(sec, microsec*1000)
602		return nil, nil
603	})
604	return err
605}
606
607//------------------------------------------------------------------------------
608
609type BoolCmd struct {
610	baseCmd
611
612	val bool
613}
614
615var _ Cmder = (*BoolCmd)(nil)
616
617func NewBoolCmd(ctx context.Context, args ...interface{}) *BoolCmd {
618	return &BoolCmd{
619		baseCmd: baseCmd{
620			ctx:  ctx,
621			args: args,
622		},
623	}
624}
625
626func (cmd *BoolCmd) Val() bool {
627	return cmd.val
628}
629
630func (cmd *BoolCmd) Result() (bool, error) {
631	return cmd.val, cmd.err
632}
633
634func (cmd *BoolCmd) String() string {
635	return cmdString(cmd, cmd.val)
636}
637
638func (cmd *BoolCmd) readReply(rd *proto.Reader) error {
639	v, err := rd.ReadReply(nil)
640	// `SET key value NX` returns nil when key already exists. But
641	// `SETNX key value` returns bool (0/1). So convert nil to bool.
642	if err == Nil {
643		cmd.val = false
644		return nil
645	}
646	if err != nil {
647		return err
648	}
649	switch v := v.(type) {
650	case int64:
651		cmd.val = v == 1
652		return nil
653	case string:
654		cmd.val = v == "OK"
655		return nil
656	default:
657		return fmt.Errorf("got %T, wanted int64 or string", v)
658	}
659}
660
661//------------------------------------------------------------------------------
662
663type StringCmd struct {
664	baseCmd
665
666	val string
667}
668
669var _ Cmder = (*StringCmd)(nil)
670
671func NewStringCmd(ctx context.Context, args ...interface{}) *StringCmd {
672	return &StringCmd{
673		baseCmd: baseCmd{
674			ctx:  ctx,
675			args: args,
676		},
677	}
678}
679
680func (cmd *StringCmd) Val() string {
681	return cmd.val
682}
683
684func (cmd *StringCmd) Result() (string, error) {
685	return cmd.Val(), cmd.err
686}
687
688func (cmd *StringCmd) Bytes() ([]byte, error) {
689	return util.StringToBytes(cmd.val), cmd.err
690}
691
692func (cmd *StringCmd) Int() (int, error) {
693	if cmd.err != nil {
694		return 0, cmd.err
695	}
696	return strconv.Atoi(cmd.Val())
697}
698
699func (cmd *StringCmd) Int64() (int64, error) {
700	if cmd.err != nil {
701		return 0, cmd.err
702	}
703	return strconv.ParseInt(cmd.Val(), 10, 64)
704}
705
706func (cmd *StringCmd) Uint64() (uint64, error) {
707	if cmd.err != nil {
708		return 0, cmd.err
709	}
710	return strconv.ParseUint(cmd.Val(), 10, 64)
711}
712
713func (cmd *StringCmd) Float32() (float32, error) {
714	if cmd.err != nil {
715		return 0, cmd.err
716	}
717	f, err := strconv.ParseFloat(cmd.Val(), 32)
718	if err != nil {
719		return 0, err
720	}
721	return float32(f), nil
722}
723
724func (cmd *StringCmd) Float64() (float64, error) {
725	if cmd.err != nil {
726		return 0, cmd.err
727	}
728	return strconv.ParseFloat(cmd.Val(), 64)
729}
730
731func (cmd *StringCmd) Time() (time.Time, error) {
732	if cmd.err != nil {
733		return time.Time{}, cmd.err
734	}
735	return time.Parse(time.RFC3339Nano, cmd.Val())
736}
737
738func (cmd *StringCmd) Scan(val interface{}) error {
739	if cmd.err != nil {
740		return cmd.err
741	}
742	return proto.Scan([]byte(cmd.val), val)
743}
744
745func (cmd *StringCmd) String() string {
746	return cmdString(cmd, cmd.val)
747}
748
749func (cmd *StringCmd) readReply(rd *proto.Reader) (err error) {
750	cmd.val, err = rd.ReadString()
751	return err
752}
753
754//------------------------------------------------------------------------------
755
756type FloatCmd struct {
757	baseCmd
758
759	val float64
760}
761
762var _ Cmder = (*FloatCmd)(nil)
763
764func NewFloatCmd(ctx context.Context, args ...interface{}) *FloatCmd {
765	return &FloatCmd{
766		baseCmd: baseCmd{
767			ctx:  ctx,
768			args: args,
769		},
770	}
771}
772
773func (cmd *FloatCmd) Val() float64 {
774	return cmd.val
775}
776
777func (cmd *FloatCmd) Result() (float64, error) {
778	return cmd.Val(), cmd.Err()
779}
780
781func (cmd *FloatCmd) String() string {
782	return cmdString(cmd, cmd.val)
783}
784
785func (cmd *FloatCmd) readReply(rd *proto.Reader) (err error) {
786	cmd.val, err = rd.ReadFloatReply()
787	return err
788}
789
790//------------------------------------------------------------------------------
791
792type StringSliceCmd struct {
793	baseCmd
794
795	val []string
796}
797
798var _ Cmder = (*StringSliceCmd)(nil)
799
800func NewStringSliceCmd(ctx context.Context, args ...interface{}) *StringSliceCmd {
801	return &StringSliceCmd{
802		baseCmd: baseCmd{
803			ctx:  ctx,
804			args: args,
805		},
806	}
807}
808
809func (cmd *StringSliceCmd) Val() []string {
810	return cmd.val
811}
812
813func (cmd *StringSliceCmd) Result() ([]string, error) {
814	return cmd.Val(), cmd.Err()
815}
816
817func (cmd *StringSliceCmd) String() string {
818	return cmdString(cmd, cmd.val)
819}
820
821func (cmd *StringSliceCmd) ScanSlice(container interface{}) error {
822	return proto.ScanSlice(cmd.Val(), container)
823}
824
825func (cmd *StringSliceCmd) readReply(rd *proto.Reader) error {
826	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
827		cmd.val = make([]string, n)
828		for i := 0; i < len(cmd.val); i++ {
829			switch s, err := rd.ReadString(); {
830			case err == Nil:
831				cmd.val[i] = ""
832			case err != nil:
833				return nil, err
834			default:
835				cmd.val[i] = s
836			}
837		}
838		return nil, nil
839	})
840	return err
841}
842
843//------------------------------------------------------------------------------
844
845type BoolSliceCmd struct {
846	baseCmd
847
848	val []bool
849}
850
851var _ Cmder = (*BoolSliceCmd)(nil)
852
853func NewBoolSliceCmd(ctx context.Context, args ...interface{}) *BoolSliceCmd {
854	return &BoolSliceCmd{
855		baseCmd: baseCmd{
856			ctx:  ctx,
857			args: args,
858		},
859	}
860}
861
862func (cmd *BoolSliceCmd) Val() []bool {
863	return cmd.val
864}
865
866func (cmd *BoolSliceCmd) Result() ([]bool, error) {
867	return cmd.val, cmd.err
868}
869
870func (cmd *BoolSliceCmd) String() string {
871	return cmdString(cmd, cmd.val)
872}
873
874func (cmd *BoolSliceCmd) readReply(rd *proto.Reader) error {
875	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
876		cmd.val = make([]bool, n)
877		for i := 0; i < len(cmd.val); i++ {
878			n, err := rd.ReadIntReply()
879			if err != nil {
880				return nil, err
881			}
882			cmd.val[i] = n == 1
883		}
884		return nil, nil
885	})
886	return err
887}
888
889//------------------------------------------------------------------------------
890
891type StringStringMapCmd struct {
892	baseCmd
893
894	val map[string]string
895}
896
897var _ Cmder = (*StringStringMapCmd)(nil)
898
899func NewStringStringMapCmd(ctx context.Context, args ...interface{}) *StringStringMapCmd {
900	return &StringStringMapCmd{
901		baseCmd: baseCmd{
902			ctx:  ctx,
903			args: args,
904		},
905	}
906}
907
908func (cmd *StringStringMapCmd) Val() map[string]string {
909	return cmd.val
910}
911
912func (cmd *StringStringMapCmd) Result() (map[string]string, error) {
913	return cmd.val, cmd.err
914}
915
916func (cmd *StringStringMapCmd) String() string {
917	return cmdString(cmd, cmd.val)
918}
919
920func (cmd *StringStringMapCmd) readReply(rd *proto.Reader) error {
921	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
922		cmd.val = make(map[string]string, n/2)
923		for i := int64(0); i < n; i += 2 {
924			key, err := rd.ReadString()
925			if err != nil {
926				return nil, err
927			}
928
929			value, err := rd.ReadString()
930			if err != nil {
931				return nil, err
932			}
933
934			cmd.val[key] = value
935		}
936		return nil, nil
937	})
938	return err
939}
940
941//------------------------------------------------------------------------------
942
943type StringIntMapCmd struct {
944	baseCmd
945
946	val map[string]int64
947}
948
949var _ Cmder = (*StringIntMapCmd)(nil)
950
951func NewStringIntMapCmd(ctx context.Context, args ...interface{}) *StringIntMapCmd {
952	return &StringIntMapCmd{
953		baseCmd: baseCmd{
954			ctx:  ctx,
955			args: args,
956		},
957	}
958}
959
960func (cmd *StringIntMapCmd) Val() map[string]int64 {
961	return cmd.val
962}
963
964func (cmd *StringIntMapCmd) Result() (map[string]int64, error) {
965	return cmd.val, cmd.err
966}
967
968func (cmd *StringIntMapCmd) String() string {
969	return cmdString(cmd, cmd.val)
970}
971
972func (cmd *StringIntMapCmd) readReply(rd *proto.Reader) error {
973	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
974		cmd.val = make(map[string]int64, n/2)
975		for i := int64(0); i < n; i += 2 {
976			key, err := rd.ReadString()
977			if err != nil {
978				return nil, err
979			}
980
981			n, err := rd.ReadIntReply()
982			if err != nil {
983				return nil, err
984			}
985
986			cmd.val[key] = n
987		}
988		return nil, nil
989	})
990	return err
991}
992
993//------------------------------------------------------------------------------
994
995type StringStructMapCmd struct {
996	baseCmd
997
998	val map[string]struct{}
999}
1000
1001var _ Cmder = (*StringStructMapCmd)(nil)
1002
1003func NewStringStructMapCmd(ctx context.Context, args ...interface{}) *StringStructMapCmd {
1004	return &StringStructMapCmd{
1005		baseCmd: baseCmd{
1006			ctx:  ctx,
1007			args: args,
1008		},
1009	}
1010}
1011
1012func (cmd *StringStructMapCmd) Val() map[string]struct{} {
1013	return cmd.val
1014}
1015
1016func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) {
1017	return cmd.val, cmd.err
1018}
1019
1020func (cmd *StringStructMapCmd) String() string {
1021	return cmdString(cmd, cmd.val)
1022}
1023
1024func (cmd *StringStructMapCmd) readReply(rd *proto.Reader) error {
1025	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1026		cmd.val = make(map[string]struct{}, n)
1027		for i := int64(0); i < n; i++ {
1028			key, err := rd.ReadString()
1029			if err != nil {
1030				return nil, err
1031			}
1032			cmd.val[key] = struct{}{}
1033		}
1034		return nil, nil
1035	})
1036	return err
1037}
1038
1039//------------------------------------------------------------------------------
1040
1041type XMessage struct {
1042	ID     string
1043	Values map[string]interface{}
1044}
1045
1046type XMessageSliceCmd struct {
1047	baseCmd
1048
1049	val []XMessage
1050}
1051
1052var _ Cmder = (*XMessageSliceCmd)(nil)
1053
1054func NewXMessageSliceCmd(ctx context.Context, args ...interface{}) *XMessageSliceCmd {
1055	return &XMessageSliceCmd{
1056		baseCmd: baseCmd{
1057			ctx:  ctx,
1058			args: args,
1059		},
1060	}
1061}
1062
1063func (cmd *XMessageSliceCmd) Val() []XMessage {
1064	return cmd.val
1065}
1066
1067func (cmd *XMessageSliceCmd) Result() ([]XMessage, error) {
1068	return cmd.val, cmd.err
1069}
1070
1071func (cmd *XMessageSliceCmd) String() string {
1072	return cmdString(cmd, cmd.val)
1073}
1074
1075func (cmd *XMessageSliceCmd) readReply(rd *proto.Reader) error {
1076	var err error
1077	cmd.val, err = readXMessageSlice(rd)
1078	return err
1079}
1080
1081func readXMessageSlice(rd *proto.Reader) ([]XMessage, error) {
1082	n, err := rd.ReadArrayLen()
1083	if err != nil {
1084		return nil, err
1085	}
1086
1087	msgs := make([]XMessage, n)
1088	for i := 0; i < n; i++ {
1089		var err error
1090		msgs[i], err = readXMessage(rd)
1091		if err != nil {
1092			return nil, err
1093		}
1094	}
1095	return msgs, nil
1096}
1097
1098func readXMessage(rd *proto.Reader) (XMessage, error) {
1099	n, err := rd.ReadArrayLen()
1100	if err != nil {
1101		return XMessage{}, err
1102	}
1103	if n != 2 {
1104		return XMessage{}, fmt.Errorf("got %d, wanted 2", n)
1105	}
1106
1107	id, err := rd.ReadString()
1108	if err != nil {
1109		return XMessage{}, err
1110	}
1111
1112	var values map[string]interface{}
1113
1114	v, err := rd.ReadArrayReply(stringInterfaceMapParser)
1115	if err != nil {
1116		if err != proto.Nil {
1117			return XMessage{}, err
1118		}
1119	} else {
1120		values = v.(map[string]interface{})
1121	}
1122
1123	return XMessage{
1124		ID:     id,
1125		Values: values,
1126	}, nil
1127}
1128
1129// stringInterfaceMapParser implements proto.MultiBulkParse.
1130func stringInterfaceMapParser(rd *proto.Reader, n int64) (interface{}, error) {
1131	m := make(map[string]interface{}, n/2)
1132	for i := int64(0); i < n; i += 2 {
1133		key, err := rd.ReadString()
1134		if err != nil {
1135			return nil, err
1136		}
1137
1138		value, err := rd.ReadString()
1139		if err != nil {
1140			return nil, err
1141		}
1142
1143		m[key] = value
1144	}
1145	return m, nil
1146}
1147
1148//------------------------------------------------------------------------------
1149
1150type XStream struct {
1151	Stream   string
1152	Messages []XMessage
1153}
1154
1155type XStreamSliceCmd struct {
1156	baseCmd
1157
1158	val []XStream
1159}
1160
1161var _ Cmder = (*XStreamSliceCmd)(nil)
1162
1163func NewXStreamSliceCmd(ctx context.Context, args ...interface{}) *XStreamSliceCmd {
1164	return &XStreamSliceCmd{
1165		baseCmd: baseCmd{
1166			ctx:  ctx,
1167			args: args,
1168		},
1169	}
1170}
1171
1172func (cmd *XStreamSliceCmd) Val() []XStream {
1173	return cmd.val
1174}
1175
1176func (cmd *XStreamSliceCmd) Result() ([]XStream, error) {
1177	return cmd.val, cmd.err
1178}
1179
1180func (cmd *XStreamSliceCmd) String() string {
1181	return cmdString(cmd, cmd.val)
1182}
1183
1184func (cmd *XStreamSliceCmd) readReply(rd *proto.Reader) error {
1185	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1186		cmd.val = make([]XStream, n)
1187		for i := 0; i < len(cmd.val); i++ {
1188			i := i
1189			_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1190				if n != 2 {
1191					return nil, fmt.Errorf("got %d, wanted 2", n)
1192				}
1193
1194				stream, err := rd.ReadString()
1195				if err != nil {
1196					return nil, err
1197				}
1198
1199				msgs, err := readXMessageSlice(rd)
1200				if err != nil {
1201					return nil, err
1202				}
1203
1204				cmd.val[i] = XStream{
1205					Stream:   stream,
1206					Messages: msgs,
1207				}
1208				return nil, nil
1209			})
1210			if err != nil {
1211				return nil, err
1212			}
1213		}
1214		return nil, nil
1215	})
1216	return err
1217}
1218
1219//------------------------------------------------------------------------------
1220
1221type XPending struct {
1222	Count     int64
1223	Lower     string
1224	Higher    string
1225	Consumers map[string]int64
1226}
1227
1228type XPendingCmd struct {
1229	baseCmd
1230	val *XPending
1231}
1232
1233var _ Cmder = (*XPendingCmd)(nil)
1234
1235func NewXPendingCmd(ctx context.Context, args ...interface{}) *XPendingCmd {
1236	return &XPendingCmd{
1237		baseCmd: baseCmd{
1238			ctx:  ctx,
1239			args: args,
1240		},
1241	}
1242}
1243
1244func (cmd *XPendingCmd) Val() *XPending {
1245	return cmd.val
1246}
1247
1248func (cmd *XPendingCmd) Result() (*XPending, error) {
1249	return cmd.val, cmd.err
1250}
1251
1252func (cmd *XPendingCmd) String() string {
1253	return cmdString(cmd, cmd.val)
1254}
1255
1256func (cmd *XPendingCmd) readReply(rd *proto.Reader) error {
1257	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1258		if n != 4 {
1259			return nil, fmt.Errorf("got %d, wanted 4", n)
1260		}
1261
1262		count, err := rd.ReadIntReply()
1263		if err != nil {
1264			return nil, err
1265		}
1266
1267		lower, err := rd.ReadString()
1268		if err != nil && err != Nil {
1269			return nil, err
1270		}
1271
1272		higher, err := rd.ReadString()
1273		if err != nil && err != Nil {
1274			return nil, err
1275		}
1276
1277		cmd.val = &XPending{
1278			Count:  count,
1279			Lower:  lower,
1280			Higher: higher,
1281		}
1282		_, err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1283			for i := int64(0); i < n; i++ {
1284				_, err = rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1285					if n != 2 {
1286						return nil, fmt.Errorf("got %d, wanted 2", n)
1287					}
1288
1289					consumerName, err := rd.ReadString()
1290					if err != nil {
1291						return nil, err
1292					}
1293
1294					consumerPending, err := rd.ReadInt()
1295					if err != nil {
1296						return nil, err
1297					}
1298
1299					if cmd.val.Consumers == nil {
1300						cmd.val.Consumers = make(map[string]int64)
1301					}
1302					cmd.val.Consumers[consumerName] = consumerPending
1303
1304					return nil, nil
1305				})
1306				if err != nil {
1307					return nil, err
1308				}
1309			}
1310			return nil, nil
1311		})
1312		if err != nil && err != Nil {
1313			return nil, err
1314		}
1315
1316		return nil, nil
1317	})
1318	return err
1319}
1320
1321//------------------------------------------------------------------------------
1322
1323type XPendingExt struct {
1324	ID         string
1325	Consumer   string
1326	Idle       time.Duration
1327	RetryCount int64
1328}
1329
1330type XPendingExtCmd struct {
1331	baseCmd
1332	val []XPendingExt
1333}
1334
1335var _ Cmder = (*XPendingExtCmd)(nil)
1336
1337func NewXPendingExtCmd(ctx context.Context, args ...interface{}) *XPendingExtCmd {
1338	return &XPendingExtCmd{
1339		baseCmd: baseCmd{
1340			ctx:  ctx,
1341			args: args,
1342		},
1343	}
1344}
1345
1346func (cmd *XPendingExtCmd) Val() []XPendingExt {
1347	return cmd.val
1348}
1349
1350func (cmd *XPendingExtCmd) Result() ([]XPendingExt, error) {
1351	return cmd.val, cmd.err
1352}
1353
1354func (cmd *XPendingExtCmd) String() string {
1355	return cmdString(cmd, cmd.val)
1356}
1357
1358func (cmd *XPendingExtCmd) readReply(rd *proto.Reader) error {
1359	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1360		cmd.val = make([]XPendingExt, 0, n)
1361		for i := int64(0); i < n; i++ {
1362			_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1363				if n != 4 {
1364					return nil, fmt.Errorf("got %d, wanted 4", n)
1365				}
1366
1367				id, err := rd.ReadString()
1368				if err != nil {
1369					return nil, err
1370				}
1371
1372				consumer, err := rd.ReadString()
1373				if err != nil && err != Nil {
1374					return nil, err
1375				}
1376
1377				idle, err := rd.ReadIntReply()
1378				if err != nil && err != Nil {
1379					return nil, err
1380				}
1381
1382				retryCount, err := rd.ReadIntReply()
1383				if err != nil && err != Nil {
1384					return nil, err
1385				}
1386
1387				cmd.val = append(cmd.val, XPendingExt{
1388					ID:         id,
1389					Consumer:   consumer,
1390					Idle:       time.Duration(idle) * time.Millisecond,
1391					RetryCount: retryCount,
1392				})
1393				return nil, nil
1394			})
1395			if err != nil {
1396				return nil, err
1397			}
1398		}
1399		return nil, nil
1400	})
1401	return err
1402}
1403
1404//------------------------------------------------------------------------------
1405
1406type XInfoGroupsCmd struct {
1407	baseCmd
1408	val []XInfoGroup
1409}
1410
1411type XInfoGroup struct {
1412	Name            string
1413	Consumers       int64
1414	Pending         int64
1415	LastDeliveredID string
1416}
1417
1418var _ Cmder = (*XInfoGroupsCmd)(nil)
1419
1420func NewXInfoGroupsCmd(ctx context.Context, stream string) *XInfoGroupsCmd {
1421	return &XInfoGroupsCmd{
1422		baseCmd: baseCmd{
1423			ctx:  ctx,
1424			args: []interface{}{"xinfo", "groups", stream},
1425		},
1426	}
1427}
1428
1429func (cmd *XInfoGroupsCmd) Val() []XInfoGroup {
1430	return cmd.val
1431}
1432
1433func (cmd *XInfoGroupsCmd) Result() ([]XInfoGroup, error) {
1434	return cmd.val, cmd.err
1435}
1436
1437func (cmd *XInfoGroupsCmd) String() string {
1438	return cmdString(cmd, cmd.val)
1439}
1440
1441func (cmd *XInfoGroupsCmd) readReply(rd *proto.Reader) error {
1442	n, err := rd.ReadArrayLen()
1443	if err != nil {
1444		return err
1445	}
1446
1447	cmd.val = make([]XInfoGroup, n)
1448
1449	for i := 0; i < n; i++ {
1450		cmd.val[i], err = readXGroupInfo(rd)
1451		if err != nil {
1452			return err
1453		}
1454	}
1455
1456	return nil
1457}
1458
1459func readXGroupInfo(rd *proto.Reader) (XInfoGroup, error) {
1460	var group XInfoGroup
1461
1462	n, err := rd.ReadArrayLen()
1463	if err != nil {
1464		return group, err
1465	}
1466	if n != 8 {
1467		return group, fmt.Errorf("redis: got %d elements in XINFO GROUPS reply, wanted 8", n)
1468	}
1469
1470	for i := 0; i < 4; i++ {
1471		key, err := rd.ReadString()
1472		if err != nil {
1473			return group, err
1474		}
1475
1476		val, err := rd.ReadString()
1477		if err != nil {
1478			return group, err
1479		}
1480
1481		switch key {
1482		case "name":
1483			group.Name = val
1484		case "consumers":
1485			group.Consumers, err = strconv.ParseInt(val, 0, 64)
1486			if err != nil {
1487				return group, err
1488			}
1489		case "pending":
1490			group.Pending, err = strconv.ParseInt(val, 0, 64)
1491			if err != nil {
1492				return group, err
1493			}
1494		case "last-delivered-id":
1495			group.LastDeliveredID = val
1496		default:
1497			return group, fmt.Errorf("redis: unexpected content %s in XINFO GROUPS reply", key)
1498		}
1499	}
1500
1501	return group, nil
1502}
1503
1504//------------------------------------------------------------------------------
1505
1506type XInfoStreamCmd struct {
1507	baseCmd
1508	val *XInfoStream
1509}
1510
1511type XInfoStream struct {
1512	Length          int64
1513	RadixTreeKeys   int64
1514	RadixTreeNodes  int64
1515	Groups          int64
1516	LastGeneratedID string
1517	FirstEntry      XMessage
1518	LastEntry       XMessage
1519}
1520
1521var _ Cmder = (*XInfoStreamCmd)(nil)
1522
1523func NewXInfoStreamCmd(ctx context.Context, stream string) *XInfoStreamCmd {
1524	return &XInfoStreamCmd{
1525		baseCmd: baseCmd{
1526			ctx:  ctx,
1527			args: []interface{}{"xinfo", "stream", stream},
1528		},
1529	}
1530}
1531
1532func (cmd *XInfoStreamCmd) Val() *XInfoStream {
1533	return cmd.val
1534}
1535
1536func (cmd *XInfoStreamCmd) Result() (*XInfoStream, error) {
1537	return cmd.val, cmd.err
1538}
1539
1540func (cmd *XInfoStreamCmd) String() string {
1541	return cmdString(cmd, cmd.val)
1542}
1543
1544func (cmd *XInfoStreamCmd) readReply(rd *proto.Reader) error {
1545	v, err := rd.ReadReply(xStreamInfoParser)
1546	if err != nil {
1547		return err
1548	}
1549	cmd.val = v.(*XInfoStream)
1550	return nil
1551}
1552
1553func xStreamInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
1554	if n != 14 {
1555		return nil, fmt.Errorf("redis: got %d elements in XINFO STREAM reply,"+
1556			"wanted 14", n)
1557	}
1558	var info XInfoStream
1559	for i := 0; i < 7; i++ {
1560		key, err := rd.ReadString()
1561		if err != nil {
1562			return nil, err
1563		}
1564		switch key {
1565		case "length":
1566			info.Length, err = rd.ReadIntReply()
1567		case "radix-tree-keys":
1568			info.RadixTreeKeys, err = rd.ReadIntReply()
1569		case "radix-tree-nodes":
1570			info.RadixTreeNodes, err = rd.ReadIntReply()
1571		case "groups":
1572			info.Groups, err = rd.ReadIntReply()
1573		case "last-generated-id":
1574			info.LastGeneratedID, err = rd.ReadString()
1575		case "first-entry":
1576			info.FirstEntry, err = readXMessage(rd)
1577		case "last-entry":
1578			info.LastEntry, err = readXMessage(rd)
1579		default:
1580			return nil, fmt.Errorf("redis: unexpected content %s "+
1581				"in XINFO STREAM reply", key)
1582		}
1583		if err != nil {
1584			return nil, err
1585		}
1586	}
1587	return &info, nil
1588}
1589
1590//------------------------------------------------------------------------------
1591
1592type ZSliceCmd struct {
1593	baseCmd
1594
1595	val []Z
1596}
1597
1598var _ Cmder = (*ZSliceCmd)(nil)
1599
1600func NewZSliceCmd(ctx context.Context, args ...interface{}) *ZSliceCmd {
1601	return &ZSliceCmd{
1602		baseCmd: baseCmd{
1603			ctx:  ctx,
1604			args: args,
1605		},
1606	}
1607}
1608
1609func (cmd *ZSliceCmd) Val() []Z {
1610	return cmd.val
1611}
1612
1613func (cmd *ZSliceCmd) Result() ([]Z, error) {
1614	return cmd.val, cmd.err
1615}
1616
1617func (cmd *ZSliceCmd) String() string {
1618	return cmdString(cmd, cmd.val)
1619}
1620
1621func (cmd *ZSliceCmd) readReply(rd *proto.Reader) error {
1622	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1623		cmd.val = make([]Z, n/2)
1624		for i := 0; i < len(cmd.val); i++ {
1625			member, err := rd.ReadString()
1626			if err != nil {
1627				return nil, err
1628			}
1629
1630			score, err := rd.ReadFloatReply()
1631			if err != nil {
1632				return nil, err
1633			}
1634
1635			cmd.val[i] = Z{
1636				Member: member,
1637				Score:  score,
1638			}
1639		}
1640		return nil, nil
1641	})
1642	return err
1643}
1644
1645//------------------------------------------------------------------------------
1646
1647type ZWithKeyCmd struct {
1648	baseCmd
1649
1650	val *ZWithKey
1651}
1652
1653var _ Cmder = (*ZWithKeyCmd)(nil)
1654
1655func NewZWithKeyCmd(ctx context.Context, args ...interface{}) *ZWithKeyCmd {
1656	return &ZWithKeyCmd{
1657		baseCmd: baseCmd{
1658			ctx:  ctx,
1659			args: args,
1660		},
1661	}
1662}
1663
1664func (cmd *ZWithKeyCmd) Val() *ZWithKey {
1665	return cmd.val
1666}
1667
1668func (cmd *ZWithKeyCmd) Result() (*ZWithKey, error) {
1669	return cmd.Val(), cmd.Err()
1670}
1671
1672func (cmd *ZWithKeyCmd) String() string {
1673	return cmdString(cmd, cmd.val)
1674}
1675
1676func (cmd *ZWithKeyCmd) readReply(rd *proto.Reader) error {
1677	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1678		if n != 3 {
1679			return nil, fmt.Errorf("got %d elements, expected 3", n)
1680		}
1681
1682		cmd.val = &ZWithKey{}
1683		var err error
1684
1685		cmd.val.Key, err = rd.ReadString()
1686		if err != nil {
1687			return nil, err
1688		}
1689
1690		cmd.val.Member, err = rd.ReadString()
1691		if err != nil {
1692			return nil, err
1693		}
1694
1695		cmd.val.Score, err = rd.ReadFloatReply()
1696		if err != nil {
1697			return nil, err
1698		}
1699
1700		return nil, nil
1701	})
1702	return err
1703}
1704
1705//------------------------------------------------------------------------------
1706
1707type ScanCmd struct {
1708	baseCmd
1709
1710	page   []string
1711	cursor uint64
1712
1713	process cmdable
1714}
1715
1716var _ Cmder = (*ScanCmd)(nil)
1717
1718func NewScanCmd(ctx context.Context, process cmdable, args ...interface{}) *ScanCmd {
1719	return &ScanCmd{
1720		baseCmd: baseCmd{
1721			ctx:  ctx,
1722			args: args,
1723		},
1724		process: process,
1725	}
1726}
1727
1728func (cmd *ScanCmd) Val() (keys []string, cursor uint64) {
1729	return cmd.page, cmd.cursor
1730}
1731
1732func (cmd *ScanCmd) Result() (keys []string, cursor uint64, err error) {
1733	return cmd.page, cmd.cursor, cmd.err
1734}
1735
1736func (cmd *ScanCmd) String() string {
1737	return cmdString(cmd, cmd.page)
1738}
1739
1740func (cmd *ScanCmd) readReply(rd *proto.Reader) (err error) {
1741	cmd.page, cmd.cursor, err = rd.ReadScanReply()
1742	return err
1743}
1744
1745// Iterator creates a new ScanIterator.
1746func (cmd *ScanCmd) Iterator() *ScanIterator {
1747	return &ScanIterator{
1748		cmd: cmd,
1749	}
1750}
1751
1752//------------------------------------------------------------------------------
1753
1754type ClusterNode struct {
1755	ID   string
1756	Addr string
1757}
1758
1759type ClusterSlot struct {
1760	Start int
1761	End   int
1762	Nodes []ClusterNode
1763}
1764
1765type ClusterSlotsCmd struct {
1766	baseCmd
1767
1768	val []ClusterSlot
1769}
1770
1771var _ Cmder = (*ClusterSlotsCmd)(nil)
1772
1773func NewClusterSlotsCmd(ctx context.Context, args ...interface{}) *ClusterSlotsCmd {
1774	return &ClusterSlotsCmd{
1775		baseCmd: baseCmd{
1776			ctx:  ctx,
1777			args: args,
1778		},
1779	}
1780}
1781
1782func (cmd *ClusterSlotsCmd) Val() []ClusterSlot {
1783	return cmd.val
1784}
1785
1786func (cmd *ClusterSlotsCmd) Result() ([]ClusterSlot, error) {
1787	return cmd.Val(), cmd.Err()
1788}
1789
1790func (cmd *ClusterSlotsCmd) String() string {
1791	return cmdString(cmd, cmd.val)
1792}
1793
1794func (cmd *ClusterSlotsCmd) readReply(rd *proto.Reader) error {
1795	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
1796		cmd.val = make([]ClusterSlot, n)
1797		for i := 0; i < len(cmd.val); i++ {
1798			n, err := rd.ReadArrayLen()
1799			if err != nil {
1800				return nil, err
1801			}
1802			if n < 2 {
1803				err := fmt.Errorf("redis: got %d elements in cluster info, expected at least 2", n)
1804				return nil, err
1805			}
1806
1807			start, err := rd.ReadIntReply()
1808			if err != nil {
1809				return nil, err
1810			}
1811
1812			end, err := rd.ReadIntReply()
1813			if err != nil {
1814				return nil, err
1815			}
1816
1817			nodes := make([]ClusterNode, n-2)
1818			for j := 0; j < len(nodes); j++ {
1819				n, err := rd.ReadArrayLen()
1820				if err != nil {
1821					return nil, err
1822				}
1823				if n != 2 && n != 3 {
1824					err := fmt.Errorf("got %d elements in cluster info address, expected 2 or 3", n)
1825					return nil, err
1826				}
1827
1828				ip, err := rd.ReadString()
1829				if err != nil {
1830					return nil, err
1831				}
1832
1833				port, err := rd.ReadString()
1834				if err != nil {
1835					return nil, err
1836				}
1837
1838				nodes[j].Addr = net.JoinHostPort(ip, port)
1839
1840				if n == 3 {
1841					id, err := rd.ReadString()
1842					if err != nil {
1843						return nil, err
1844					}
1845					nodes[j].ID = id
1846				}
1847			}
1848
1849			cmd.val[i] = ClusterSlot{
1850				Start: int(start),
1851				End:   int(end),
1852				Nodes: nodes,
1853			}
1854		}
1855		return nil, nil
1856	})
1857	return err
1858}
1859
1860//------------------------------------------------------------------------------
1861
1862// GeoLocation is used with GeoAdd to add geospatial location.
1863type GeoLocation struct {
1864	Name                      string
1865	Longitude, Latitude, Dist float64
1866	GeoHash                   int64
1867}
1868
1869// GeoRadiusQuery is used with GeoRadius to query geospatial index.
1870type GeoRadiusQuery struct {
1871	Radius float64
1872	// Can be m, km, ft, or mi. Default is km.
1873	Unit        string
1874	WithCoord   bool
1875	WithDist    bool
1876	WithGeoHash bool
1877	Count       int
1878	// Can be ASC or DESC. Default is no sort order.
1879	Sort      string
1880	Store     string
1881	StoreDist string
1882}
1883
1884type GeoLocationCmd struct {
1885	baseCmd
1886
1887	q         *GeoRadiusQuery
1888	locations []GeoLocation
1889}
1890
1891var _ Cmder = (*GeoLocationCmd)(nil)
1892
1893func NewGeoLocationCmd(ctx context.Context, q *GeoRadiusQuery, args ...interface{}) *GeoLocationCmd {
1894	return &GeoLocationCmd{
1895		baseCmd: baseCmd{
1896			ctx:  ctx,
1897			args: geoLocationArgs(q, args...),
1898		},
1899		q: q,
1900	}
1901}
1902
1903func geoLocationArgs(q *GeoRadiusQuery, args ...interface{}) []interface{} {
1904	args = append(args, q.Radius)
1905	if q.Unit != "" {
1906		args = append(args, q.Unit)
1907	} else {
1908		args = append(args, "km")
1909	}
1910	if q.WithCoord {
1911		args = append(args, "withcoord")
1912	}
1913	if q.WithDist {
1914		args = append(args, "withdist")
1915	}
1916	if q.WithGeoHash {
1917		args = append(args, "withhash")
1918	}
1919	if q.Count > 0 {
1920		args = append(args, "count", q.Count)
1921	}
1922	if q.Sort != "" {
1923		args = append(args, q.Sort)
1924	}
1925	if q.Store != "" {
1926		args = append(args, "store")
1927		args = append(args, q.Store)
1928	}
1929	if q.StoreDist != "" {
1930		args = append(args, "storedist")
1931		args = append(args, q.StoreDist)
1932	}
1933	return args
1934}
1935
1936func (cmd *GeoLocationCmd) Val() []GeoLocation {
1937	return cmd.locations
1938}
1939
1940func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) {
1941	return cmd.locations, cmd.err
1942}
1943
1944func (cmd *GeoLocationCmd) String() string {
1945	return cmdString(cmd, cmd.locations)
1946}
1947
1948func (cmd *GeoLocationCmd) readReply(rd *proto.Reader) error {
1949	v, err := rd.ReadArrayReply(newGeoLocationSliceParser(cmd.q))
1950	if err != nil {
1951		return err
1952	}
1953	cmd.locations = v.([]GeoLocation)
1954	return nil
1955}
1956
1957func newGeoLocationSliceParser(q *GeoRadiusQuery) proto.MultiBulkParse {
1958	return func(rd *proto.Reader, n int64) (interface{}, error) {
1959		locs := make([]GeoLocation, 0, n)
1960		for i := int64(0); i < n; i++ {
1961			v, err := rd.ReadReply(newGeoLocationParser(q))
1962			if err != nil {
1963				return nil, err
1964			}
1965			switch vv := v.(type) {
1966			case string:
1967				locs = append(locs, GeoLocation{
1968					Name: vv,
1969				})
1970			case *GeoLocation:
1971				// TODO: avoid copying
1972				locs = append(locs, *vv)
1973			default:
1974				return nil, fmt.Errorf("got %T, expected string or *GeoLocation", v)
1975			}
1976		}
1977		return locs, nil
1978	}
1979}
1980
1981func newGeoLocationParser(q *GeoRadiusQuery) proto.MultiBulkParse {
1982	return func(rd *proto.Reader, n int64) (interface{}, error) {
1983		var loc GeoLocation
1984		var err error
1985
1986		loc.Name, err = rd.ReadString()
1987		if err != nil {
1988			return nil, err
1989		}
1990		if q.WithDist {
1991			loc.Dist, err = rd.ReadFloatReply()
1992			if err != nil {
1993				return nil, err
1994			}
1995		}
1996		if q.WithGeoHash {
1997			loc.GeoHash, err = rd.ReadIntReply()
1998			if err != nil {
1999				return nil, err
2000			}
2001		}
2002		if q.WithCoord {
2003			n, err := rd.ReadArrayLen()
2004			if err != nil {
2005				return nil, err
2006			}
2007			if n != 2 {
2008				return nil, fmt.Errorf("got %d coordinates, expected 2", n)
2009			}
2010
2011			loc.Longitude, err = rd.ReadFloatReply()
2012			if err != nil {
2013				return nil, err
2014			}
2015			loc.Latitude, err = rd.ReadFloatReply()
2016			if err != nil {
2017				return nil, err
2018			}
2019		}
2020
2021		return &loc, nil
2022	}
2023}
2024
2025//------------------------------------------------------------------------------
2026
2027type GeoPos struct {
2028	Longitude, Latitude float64
2029}
2030
2031type GeoPosCmd struct {
2032	baseCmd
2033
2034	val []*GeoPos
2035}
2036
2037var _ Cmder = (*GeoPosCmd)(nil)
2038
2039func NewGeoPosCmd(ctx context.Context, args ...interface{}) *GeoPosCmd {
2040	return &GeoPosCmd{
2041		baseCmd: baseCmd{
2042			ctx:  ctx,
2043			args: args,
2044		},
2045	}
2046}
2047
2048func (cmd *GeoPosCmd) Val() []*GeoPos {
2049	return cmd.val
2050}
2051
2052func (cmd *GeoPosCmd) Result() ([]*GeoPos, error) {
2053	return cmd.Val(), cmd.Err()
2054}
2055
2056func (cmd *GeoPosCmd) String() string {
2057	return cmdString(cmd, cmd.val)
2058}
2059
2060func (cmd *GeoPosCmd) readReply(rd *proto.Reader) error {
2061	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
2062		cmd.val = make([]*GeoPos, n)
2063		for i := 0; i < len(cmd.val); i++ {
2064			i := i
2065			_, err := rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
2066				longitude, err := rd.ReadFloatReply()
2067				if err != nil {
2068					return nil, err
2069				}
2070
2071				latitude, err := rd.ReadFloatReply()
2072				if err != nil {
2073					return nil, err
2074				}
2075
2076				cmd.val[i] = &GeoPos{
2077					Longitude: longitude,
2078					Latitude:  latitude,
2079				}
2080				return nil, nil
2081			})
2082			if err != nil {
2083				if err == Nil {
2084					cmd.val[i] = nil
2085					continue
2086				}
2087				return nil, err
2088			}
2089		}
2090		return nil, nil
2091	})
2092	return err
2093}
2094
2095//------------------------------------------------------------------------------
2096
2097type CommandInfo struct {
2098	Name        string
2099	Arity       int8
2100	Flags       []string
2101	ACLFlags    []string
2102	FirstKeyPos int8
2103	LastKeyPos  int8
2104	StepCount   int8
2105	ReadOnly    bool
2106}
2107
2108type CommandsInfoCmd struct {
2109	baseCmd
2110
2111	val map[string]*CommandInfo
2112}
2113
2114var _ Cmder = (*CommandsInfoCmd)(nil)
2115
2116func NewCommandsInfoCmd(ctx context.Context, args ...interface{}) *CommandsInfoCmd {
2117	return &CommandsInfoCmd{
2118		baseCmd: baseCmd{
2119			ctx:  ctx,
2120			args: args,
2121		},
2122	}
2123}
2124
2125func (cmd *CommandsInfoCmd) Val() map[string]*CommandInfo {
2126	return cmd.val
2127}
2128
2129func (cmd *CommandsInfoCmd) Result() (map[string]*CommandInfo, error) {
2130	return cmd.Val(), cmd.Err()
2131}
2132
2133func (cmd *CommandsInfoCmd) String() string {
2134	return cmdString(cmd, cmd.val)
2135}
2136
2137func (cmd *CommandsInfoCmd) readReply(rd *proto.Reader) error {
2138	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
2139		cmd.val = make(map[string]*CommandInfo, n)
2140		for i := int64(0); i < n; i++ {
2141			v, err := rd.ReadReply(commandInfoParser)
2142			if err != nil {
2143				return nil, err
2144			}
2145			vv := v.(*CommandInfo)
2146			cmd.val[vv.Name] = vv
2147		}
2148		return nil, nil
2149	})
2150	return err
2151}
2152
2153func commandInfoParser(rd *proto.Reader, n int64) (interface{}, error) {
2154	const numArgRedis5 = 6
2155	const numArgRedis6 = 7
2156
2157	switch n {
2158	case numArgRedis5, numArgRedis6:
2159		// continue
2160	default:
2161		return nil, fmt.Errorf("redis: got %d elements in COMMAND reply, wanted 7", n)
2162	}
2163
2164	var cmd CommandInfo
2165	var err error
2166
2167	cmd.Name, err = rd.ReadString()
2168	if err != nil {
2169		return nil, err
2170	}
2171
2172	arity, err := rd.ReadIntReply()
2173	if err != nil {
2174		return nil, err
2175	}
2176	cmd.Arity = int8(arity)
2177
2178	_, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
2179		cmd.Flags = make([]string, n)
2180		for i := 0; i < len(cmd.Flags); i++ {
2181			switch s, err := rd.ReadString(); {
2182			case err == Nil:
2183				cmd.Flags[i] = ""
2184			case err != nil:
2185				return nil, err
2186			default:
2187				cmd.Flags[i] = s
2188			}
2189		}
2190		return nil, nil
2191	})
2192	if err != nil {
2193		return nil, err
2194	}
2195
2196	firstKeyPos, err := rd.ReadIntReply()
2197	if err != nil {
2198		return nil, err
2199	}
2200	cmd.FirstKeyPos = int8(firstKeyPos)
2201
2202	lastKeyPos, err := rd.ReadIntReply()
2203	if err != nil {
2204		return nil, err
2205	}
2206	cmd.LastKeyPos = int8(lastKeyPos)
2207
2208	stepCount, err := rd.ReadIntReply()
2209	if err != nil {
2210		return nil, err
2211	}
2212	cmd.StepCount = int8(stepCount)
2213
2214	for _, flag := range cmd.Flags {
2215		if flag == "readonly" {
2216			cmd.ReadOnly = true
2217			break
2218		}
2219	}
2220
2221	if n == numArgRedis5 {
2222		return &cmd, nil
2223	}
2224
2225	_, err = rd.ReadReply(func(rd *proto.Reader, n int64) (interface{}, error) {
2226		cmd.ACLFlags = make([]string, n)
2227		for i := 0; i < len(cmd.ACLFlags); i++ {
2228			switch s, err := rd.ReadString(); {
2229			case err == Nil:
2230				cmd.ACLFlags[i] = ""
2231			case err != nil:
2232				return nil, err
2233			default:
2234				cmd.ACLFlags[i] = s
2235			}
2236		}
2237		return nil, nil
2238	})
2239	if err != nil {
2240		return nil, err
2241	}
2242
2243	return &cmd, nil
2244}
2245
2246//------------------------------------------------------------------------------
2247
2248type cmdsInfoCache struct {
2249	fn func(ctx context.Context) (map[string]*CommandInfo, error)
2250
2251	once internal.Once
2252	cmds map[string]*CommandInfo
2253}
2254
2255func newCmdsInfoCache(fn func(ctx context.Context) (map[string]*CommandInfo, error)) *cmdsInfoCache {
2256	return &cmdsInfoCache{
2257		fn: fn,
2258	}
2259}
2260
2261func (c *cmdsInfoCache) Get(ctx context.Context) (map[string]*CommandInfo, error) {
2262	err := c.once.Do(func() error {
2263		cmds, err := c.fn(ctx)
2264		if err != nil {
2265			return err
2266		}
2267
2268		// Extensions have cmd names in upper case. Convert them to lower case.
2269		for k, v := range cmds {
2270			lower := internal.ToLower(k)
2271			if lower != k {
2272				cmds[lower] = v
2273			}
2274		}
2275
2276		c.cmds = cmds
2277		return nil
2278	})
2279	return c.cmds, err
2280}
2281
2282//------------------------------------------------------------------------------
2283
2284type SlowLog struct {
2285	ID       int64
2286	Time     time.Time
2287	Duration time.Duration
2288	Args     []string
2289	// These are also optional fields emitted only by Redis 4.0 or greater:
2290	// https://redis.io/commands/slowlog#output-format
2291	ClientAddr string
2292	ClientName string
2293}
2294
2295type SlowLogCmd struct {
2296	baseCmd
2297
2298	val []SlowLog
2299}
2300
2301var _ Cmder = (*SlowLogCmd)(nil)
2302
2303func NewSlowLogCmd(ctx context.Context, args ...interface{}) *SlowLogCmd {
2304	return &SlowLogCmd{
2305		baseCmd: baseCmd{
2306			ctx:  ctx,
2307			args: args,
2308		},
2309	}
2310}
2311
2312func (cmd *SlowLogCmd) Val() []SlowLog {
2313	return cmd.val
2314}
2315
2316func (cmd *SlowLogCmd) Result() ([]SlowLog, error) {
2317	return cmd.Val(), cmd.Err()
2318}
2319
2320func (cmd *SlowLogCmd) String() string {
2321	return cmdString(cmd, cmd.val)
2322}
2323
2324func (cmd *SlowLogCmd) readReply(rd *proto.Reader) error {
2325	_, err := rd.ReadArrayReply(func(rd *proto.Reader, n int64) (interface{}, error) {
2326		cmd.val = make([]SlowLog, n)
2327		for i := 0; i < len(cmd.val); i++ {
2328			n, err := rd.ReadArrayLen()
2329			if err != nil {
2330				return nil, err
2331			}
2332			if n < 4 {
2333				err := fmt.Errorf("redis: got %d elements in slowlog get, expected at least 4", n)
2334				return nil, err
2335			}
2336
2337			id, err := rd.ReadIntReply()
2338			if err != nil {
2339				return nil, err
2340			}
2341
2342			createdAt, err := rd.ReadIntReply()
2343			if err != nil {
2344				return nil, err
2345			}
2346			createdAtTime := time.Unix(createdAt, 0)
2347
2348			costs, err := rd.ReadIntReply()
2349			if err != nil {
2350				return nil, err
2351			}
2352			costsDuration := time.Duration(costs) * time.Microsecond
2353
2354			cmdLen, err := rd.ReadArrayLen()
2355			if err != nil {
2356				return nil, err
2357			}
2358			if cmdLen < 1 {
2359				err := fmt.Errorf("redis: got %d elements commands reply in slowlog get, expected at least 1", cmdLen)
2360				return nil, err
2361			}
2362
2363			cmdString := make([]string, cmdLen)
2364			for i := 0; i < cmdLen; i++ {
2365				cmdString[i], err = rd.ReadString()
2366				if err != nil {
2367					return nil, err
2368				}
2369			}
2370
2371			var address, name string
2372			for i := 4; i < n; i++ {
2373				str, err := rd.ReadString()
2374				if err != nil {
2375					return nil, err
2376				}
2377				if i == 4 {
2378					address = str
2379				} else if i == 5 {
2380					name = str
2381				}
2382			}
2383
2384			cmd.val[i] = SlowLog{
2385				ID:         id,
2386				Time:       createdAtTime,
2387				Duration:   costsDuration,
2388				Args:       cmdString,
2389				ClientAddr: address,
2390				ClientName: name,
2391			}
2392		}
2393		return nil, nil
2394	})
2395	return err
2396}
2397