/
reader.go
229 lines (197 loc) · 6.88 KB
/
reader.go
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
package restlicodec
import (
"errors"
"fmt"
)
// Unmarshaler is the interface that should be implemented by objects that can be deserialized from JSON and ROR2
type Unmarshaler interface {
UnmarshalRestLi(Reader) error
}
// PointerUnmarshaler represents an interface implemented by records and other objects that use pointer receivers for
// all their methods (unlike enums that use direct receivers).
type PointerUnmarshaler[T any] interface {
Unmarshaler
NewInstance() T
}
// UnmarshalRestLi calls the corresponding PrimitiveReader method if T is a Primitive (or an int). If T implements
// Unmarshaler, it is expected to implement PointerUnmarshaler as well and its NewInstance method will be called, then
// Unmarshaler.UnmarshalRestLi is called on the new pointer. If *T implements Unmarshaler then
// Unmarshaler.UnmarshalRestLi is called directly on a pointer to a 0-value of T. Otherwise, this function panics.
func UnmarshalRestLi[T any](reader Reader) (t T, err error) {
if pt, ok := any(t).(PointerUnmarshaler[T]); ok {
t = pt.NewInstance()
return t, any(t).(Unmarshaler).UnmarshalRestLi(reader)
}
if u, ok := any(&t).(Unmarshaler); ok {
return t, u.UnmarshalRestLi(reader)
}
cast := func(v any, err error) (T, error) {
return v.(T), err
}
switch any(t).(type) {
case int:
return cast(reader.ReadInt())
case int32:
return cast(reader.ReadInt32())
case int64:
return cast(reader.ReadInt64())
case float32:
return cast(reader.ReadFloat32())
case float64:
return cast(reader.ReadFloat64())
case bool:
return cast(reader.ReadBool())
case string:
return cast(reader.ReadString())
case []byte:
return cast(reader.ReadBytes())
default:
return loadAdapter[T]().unmarshaler(reader)
}
}
// The UnmarshalerFunc type is an adapter to allow the use of ordinary functions as unmarshalers, useful for inlining
// marshalers instead of defining new types
type UnmarshalerFunc func(Reader) error
func (u UnmarshalerFunc) UnmarshalRestLi(reader Reader) error {
return u(reader)
}
// PrimitiveReader describes the set of functions that read the supported rest.li primitives from the input. Note that
// if the reader's next input is not a primitive (i.e. it is an object/map or an array), each of these methods will
// return errors. The encoding spec can be found here:
// https://linkedin.github.io/rest.li/how_data_is_serialized_for_transport
type PrimitiveReader interface {
ReadInt() (int, error)
ReadInt32() (int32, error)
ReadInt64() (int64, error)
ReadFloat32() (float32, error)
ReadFloat64() (float64, error)
ReadBool() (bool, error)
ReadString() (string, error)
ReadBytes() ([]byte, error)
}
type (
GenericUnmarshaler[T any] func(reader Reader) (T, error)
MapReader func(reader Reader, field string) (err error)
ArrayReader func(reader Reader) (err error)
)
// NoSuchFieldErr should be returned to signal that
var NoSuchFieldErr = errors.New("go-restli: No such field")
type Reader interface {
fmt.Stringer
PrimitiveReader
KeyChecker
// ReadMap tells the Reader that it should expect a map/object as its next input. If it is not (e.g. it is an array
// or a primitive) it will return an error.
// Note that not using the inner Reader passed to the MapReader may result in undefined behavior.
ReadMap(mapReader MapReader) error
// ReadRecord tells the Reader that it should expect an object as its next input and calls recordReader for each
// field of the object. If the next input is not an object, it will return an error.
// Note that not using the inner Reader passed to the MapReader may result in undefined behavior.
ReadRecord(requiredFields *RequiredFields, recordReader MapReader) error
// ReadArray tells the reader that it should expect an array as its next input. If it is not, it will return an
// error
// Note that not using the inner Reader passed to the ArrayReader may result in undefined behavior.
ReadArray(arrayReader ArrayReader) error
// ReadInterface reads an interface{} analogous to the 'encoding/json' package. It is a best-effort attempt to
// deserialize the underlying data into map[string]interface{}, []interface{} or raw primitive types accordingly.
// Note that for ROR2, because all primitives are encoded as strings, it is impossible to tell what the field's type
// is intended to be without its schema. Therefore all primitive values are interpreted as strings
ReadInterface() (interface{}, error)
// ReadRawBytes returns the next primitive/array/map as a raw, unvalidated byte slice.
ReadRawBytes() ([]byte, error)
// Skip skips the next primitive/array/map completely.
Skip() error
}
type rawReader interface {
ReadMap(mapReader MapReader) error
atInputStart() bool
recordMissingRequiredFields(missingRequiredFields map[string]struct{})
checkMissingFields() error
}
func readRecord(reader rawReader, requiredFields *RequiredFields, mapReader MapReader) (err error) {
atInputStart := reader.atInputStart()
requiredFieldsRemaining := requiredFields.toMap()
err = reader.ReadMap(func(reader Reader, field string) (err error) {
err = mapReader(reader, field)
if err != nil {
return err
}
delete(requiredFieldsRemaining, field)
return nil
})
if err != nil {
return err
}
reader.recordMissingRequiredFields(requiredFieldsRemaining)
if atInputStart {
return reader.checkMissingFields()
} else {
return nil
}
}
func ReadMap[V any](reader Reader, unmarshaler GenericUnmarshaler[V]) (result map[string]V, err error) {
result = make(map[string]V)
err = reader.ReadMap(func(reader Reader, field string) (err error) {
result[field], err = unmarshaler(reader)
return err
})
if err != nil {
return nil, err
}
return result, nil
}
func ReadArray[V any](reader Reader, unmarshaler GenericUnmarshaler[V]) (result []V, err error) {
err = reader.ReadArray(func(reader Reader) (err error) {
item, err := unmarshaler(reader)
if err != nil {
return err
}
result = append(result, item)
return nil
})
if err != nil {
return nil, err
}
return result, nil
}
type DeserializationError struct {
Scope string
Err error
}
func (d *DeserializationError) Error() string {
return fmt.Sprintf("go-restli: Failed to deserialize %q (%+v)", d.Scope, d.Err)
}
type RequiredFields struct {
fields []string
}
func NewRequiredFields(included ...*RequiredFields) (rf *RequiredFields) {
rf = new(RequiredFields)
for _, i := range included {
rf.fields = append(rf.fields, i.fields...)
}
return rf
}
func (rf *RequiredFields) Add(fields ...string) *RequiredFields {
rf.fields = append(rf.fields, fields...)
return rf
}
func (rf *RequiredFields) toMap() map[string]struct{} {
if rf == nil || len(rf.fields) == 0 {
return nil
}
fields := make(map[string]struct{}, len(rf.fields))
for _, f := range rf.fields {
fields[f] = struct{}{}
}
return fields
}
func readBytes(s string, err error) ([]byte, error) {
if err != nil {
return nil, err
}
if s == "" {
return nil, nil
} else {
return []byte(s), nil
}
}