-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathutil.go
More file actions
239 lines (214 loc) · 5.78 KB
/
util.go
File metadata and controls
239 lines (214 loc) · 5.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
package nu
import (
"errors"
"fmt"
"log/slog"
"reflect"
"github.com/vmihailenco/msgpack/v5"
)
func attrError(err error) slog.Attr {
return slog.Any("error", err)
}
func attrMsg(msg any) slog.Attr {
if mt := reflect.TypeOf(msg); mt != nil {
switch mt.Kind() {
case reflect.Struct:
return slog.Any("message", fmt.Sprintf("%#v", msg))
}
}
return slog.Any("message", msg)
}
func attrStreamID(id int) slog.Attr {
return slog.Int("stream_id", id)
}
func attrCallID(id int) slog.Attr {
return slog.Int("call_id", id)
}
/*
encodeMapStart outputs a map with single key named "key", caller
must output the value:
{ key: | }
*/
func encodeMapStart(enc *msgpack.Encoder, key string) error {
if err := enc.EncodeMapLen(1); err != nil {
return err
}
if err := enc.EncodeString(key); err != nil {
return err
}
return nil
}
/*
encodeTupleInMap outputs map with single key "key" whose value is tuple
[id, ? ], the caller must output tuple's second item.
{ key: [ id, | ] }
*/
func encodeTupleInMap(enc *msgpack.Encoder, key string, id int) error {
if err := enc.EncodeMapLen(1); err != nil {
return err
}
if err := enc.EncodeString(key); err != nil {
return err
}
if err := enc.EncodeArrayLen(2); err != nil {
return err
}
if err := enc.EncodeInt(int64(id)); err != nil {
return err
}
return nil
}
/*
decodeTupleStart reads the start of a "2-tuple (array): [id, <something>]" and
returns the ID part, the decoder is in the start of <something> when nil error
is returned.
*/
func decodeTupleStart(d *msgpack.Decoder) (int, error) {
n, err := d.DecodeArrayLen()
if err != nil {
return 0, fmt.Errorf("reading tuple array length: %w", err)
}
if n != 2 {
return 0, fmt.Errorf("unexpected tuple array length %d", n)
}
id, err := d.DecodeInt()
if err != nil {
return 0, fmt.Errorf("reading data stream ID: %w", err)
}
return id, nil
}
/*
decodeWrapperMap reads the "single item map" whose key is string - the
key name is returned and decoder is ready to read the value.
*/
func decodeWrapperMap(dec *msgpack.Decoder) (string, error) {
cnt, err := dec.DecodeMapLen()
if err != nil {
return "", fmt.Errorf("reading map length: %w", err)
}
if cnt != 1 {
return "", fmt.Errorf("wrapper map is expected to contain one item, got %d", cnt)
}
keyName, err := dec.DecodeString()
if err != nil {
return "", fmt.Errorf("reading map key: %w", err)
}
return keyName, nil
}
var errUnknownField = errors.New("unknown field")
func decodeMap(name string, dec *msgpack.Decoder, decodeKey func(dec *msgpack.Decoder, key string) error) error {
cnt, err := dec.DecodeMapLen()
if err != nil {
return fmt.Errorf("reading %s map length: %w", name, err)
}
if cnt == -1 {
return nil
}
for i := range cnt {
key, err := dec.DecodeString()
if err != nil {
return fmt.Errorf("reading %s map key %d of %d: %w", name, i, cnt, err)
}
if err = decodeKey(dec, key); err != nil {
return fmt.Errorf("decoding %s map key %q: %w", name, key, err)
}
}
return nil
}
type msgpackEncFunc func(enc *msgpack.Encoder, p *Plugin) error
/*
encodeMap encodes fixed size map using the enc - it writes the number of items and
then calls each item to serialize the actual key - value pair.
*/
func encodeMap(p *Plugin, enc *msgpack.Encoder, items ...msgpackEncFunc) error {
if err := enc.EncodeMapLen(len(items)); err != nil {
return fmt.Errorf("encoding map length: %w", err)
}
for _, f := range items {
if err := f(enc, p); err != nil {
return err
}
}
return nil
}
/*
use with encodeMap to store string value
*/
func writeMapItemString(key, value string) msgpackEncFunc {
return func(enc *msgpack.Encoder, p *Plugin) (err error) {
if err = enc.EncodeString(key); err != nil {
return fmt.Errorf("encoding key %q: %w", key, err)
}
if err = enc.EncodeString(value); err != nil {
return fmt.Errorf("encoding value of the key %q: %w", key, err)
}
return nil
}
}
/*
use with encodeMap to store int value
*/
func writeMapItemInt(key string, value int) msgpackEncFunc {
return func(enc *msgpack.Encoder, p *Plugin) (err error) {
if err = enc.EncodeString(key); err != nil {
return fmt.Errorf("encoding key %q: %w", key, err)
}
if err = enc.EncodeInt(int64(value)); err != nil {
return fmt.Errorf("encoding value of the key %q: %w", key, err)
}
return nil
}
}
/*
use with encodeMap to store complex value which implements encodeMsgpack method.
*/
func writeMapItemFunc(key string, wf msgpackEncFunc) msgpackEncFunc {
return func(enc *msgpack.Encoder, p *Plugin) (err error) {
if err = enc.EncodeString(key); err != nil {
return fmt.Errorf("encoding key %q: %w", key, err)
}
if err = wf(enc, p); err != nil {
return fmt.Errorf("encoding value of the key %q: %w", key, err)
}
return nil
}
}
/*
Callback is the "standard marshaler" signature.
*/
func writeMapItemFuncMsgpack(key string, wf func(enc *msgpack.Encoder) error) msgpackEncFunc {
return func(enc *msgpack.Encoder, p *Plugin) (err error) {
if err = enc.EncodeString(key); err != nil {
return fmt.Errorf("encoding key %q: %w", key, err)
}
if err = wf(enc); err != nil {
return fmt.Errorf("encoding value of the key %q: %w", key, err)
}
return nil
}
}
func encodeString(enc *msgpack.Encoder, key, value string) (err error) {
if err = enc.EncodeString(key); err != nil {
return fmt.Errorf("encoding key %q: %w", key, err)
}
if err = enc.EncodeString(value); err != nil {
return fmt.Errorf("encoding value of the key %q: %w", key, err)
}
return nil
}
func encodeBoolean(enc *msgpack.Encoder, key string, value bool) (err error) {
if err = enc.EncodeString(key); err != nil {
return fmt.Errorf("encoding key %q: %w", key, err)
}
if err = enc.EncodeBool(value); err != nil {
return fmt.Errorf("encoding value of the key %q: %w", key, err)
}
return nil
}
func bval(b bool) int {
r := 0
if b {
r = 1
}
return r
}