blob: c4260981ed14bea997b86f18d51825ef2c60e89a [file] [log] [blame]
Naveen Sampath04696f72022-06-13 15:19:14 +05301package proto
2
3import (
4 "encoding"
5 "fmt"
6 "io"
7 "strconv"
8 "time"
9
10 "github.com/go-redis/redis/v8/internal/util"
11)
12
13type writer interface {
14 io.Writer
15 io.ByteWriter
16 // io.StringWriter
17 WriteString(s string) (n int, err error)
18}
19
20type Writer struct {
21 writer
22
23 lenBuf []byte
24 numBuf []byte
25}
26
27func NewWriter(wr writer) *Writer {
28 return &Writer{
29 writer: wr,
30
31 lenBuf: make([]byte, 64),
32 numBuf: make([]byte, 64),
33 }
34}
35
36func (w *Writer) WriteArgs(args []interface{}) error {
37 if err := w.WriteByte(ArrayReply); err != nil {
38 return err
39 }
40
41 if err := w.writeLen(len(args)); err != nil {
42 return err
43 }
44
45 for _, arg := range args {
46 if err := w.WriteArg(arg); err != nil {
47 return err
48 }
49 }
50
51 return nil
52}
53
54func (w *Writer) writeLen(n int) error {
55 w.lenBuf = strconv.AppendUint(w.lenBuf[:0], uint64(n), 10)
56 w.lenBuf = append(w.lenBuf, '\r', '\n')
57 _, err := w.Write(w.lenBuf)
58 return err
59}
60
61func (w *Writer) WriteArg(v interface{}) error {
62 switch v := v.(type) {
63 case nil:
64 return w.string("")
65 case string:
66 return w.string(v)
67 case []byte:
68 return w.bytes(v)
69 case int:
70 return w.int(int64(v))
71 case int8:
72 return w.int(int64(v))
73 case int16:
74 return w.int(int64(v))
75 case int32:
76 return w.int(int64(v))
77 case int64:
78 return w.int(v)
79 case uint:
80 return w.uint(uint64(v))
81 case uint8:
82 return w.uint(uint64(v))
83 case uint16:
84 return w.uint(uint64(v))
85 case uint32:
86 return w.uint(uint64(v))
87 case uint64:
88 return w.uint(v)
89 case float32:
90 return w.float(float64(v))
91 case float64:
92 return w.float(v)
93 case bool:
94 if v {
95 return w.int(1)
96 }
97 return w.int(0)
98 case time.Time:
99 w.numBuf = v.AppendFormat(w.numBuf[:0], time.RFC3339Nano)
100 return w.bytes(w.numBuf)
101 case time.Duration:
102 return w.int(v.Nanoseconds())
103 case encoding.BinaryMarshaler:
104 b, err := v.MarshalBinary()
105 if err != nil {
106 return err
107 }
108 return w.bytes(b)
109 default:
110 return fmt.Errorf(
111 "redis: can't marshal %T (implement encoding.BinaryMarshaler)", v)
112 }
113}
114
115func (w *Writer) bytes(b []byte) error {
116 if err := w.WriteByte(StringReply); err != nil {
117 return err
118 }
119
120 if err := w.writeLen(len(b)); err != nil {
121 return err
122 }
123
124 if _, err := w.Write(b); err != nil {
125 return err
126 }
127
128 return w.crlf()
129}
130
131func (w *Writer) string(s string) error {
132 return w.bytes(util.StringToBytes(s))
133}
134
135func (w *Writer) uint(n uint64) error {
136 w.numBuf = strconv.AppendUint(w.numBuf[:0], n, 10)
137 return w.bytes(w.numBuf)
138}
139
140func (w *Writer) int(n int64) error {
141 w.numBuf = strconv.AppendInt(w.numBuf[:0], n, 10)
142 return w.bytes(w.numBuf)
143}
144
145func (w *Writer) float(f float64) error {
146 w.numBuf = strconv.AppendFloat(w.numBuf[:0], f, 'f', -1, 64)
147 return w.bytes(w.numBuf)
148}
149
150func (w *Writer) crlf() error {
151 if err := w.WriteByte('\r'); err != nil {
152 return err
153 }
154 return w.WriteByte('\n')
155}