blob: 81b09b8e4f70906ef2b046c75c058e075a062d49 [file] [log] [blame]
Joey Armstrong5f51f2e2023-01-17 17:06:26 -05001package 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 encoding.BinaryMarshaler:
102 b, err := v.MarshalBinary()
103 if err != nil {
104 return err
105 }
106 return w.bytes(b)
107 default:
108 return fmt.Errorf(
109 "redis: can't marshal %T (implement encoding.BinaryMarshaler)", v)
110 }
111}
112
113func (w *Writer) bytes(b []byte) error {
114 if err := w.WriteByte(StringReply); err != nil {
115 return err
116 }
117
118 if err := w.writeLen(len(b)); err != nil {
119 return err
120 }
121
122 if _, err := w.Write(b); err != nil {
123 return err
124 }
125
126 return w.crlf()
127}
128
129func (w *Writer) string(s string) error {
130 return w.bytes(util.StringToBytes(s))
131}
132
133func (w *Writer) uint(n uint64) error {
134 w.numBuf = strconv.AppendUint(w.numBuf[:0], n, 10)
135 return w.bytes(w.numBuf)
136}
137
138func (w *Writer) int(n int64) error {
139 w.numBuf = strconv.AppendInt(w.numBuf[:0], n, 10)
140 return w.bytes(w.numBuf)
141}
142
143func (w *Writer) float(f float64) error {
144 w.numBuf = strconv.AppendFloat(w.numBuf[:0], f, 'f', -1, 64)
145 return w.bytes(w.numBuf)
146}
147
148func (w *Writer) crlf() error {
149 if err := w.WriteByte('\r'); err != nil {
150 return err
151 }
152 return w.WriteByte('\n')
153}