blob: 7ee73eeea08fd2342ff8489deaf35f07484d6c75 [file] [log] [blame]
Herbie Ong800c9902018-12-06 15:28:53 -08001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package textpb
6
7import (
8 "fmt"
9
10 "github.com/golang/protobuf/v2/internal/encoding/text"
11 "github.com/golang/protobuf/v2/internal/errors"
12 "github.com/golang/protobuf/v2/internal/pragma"
13 "github.com/golang/protobuf/v2/internal/set"
14 "github.com/golang/protobuf/v2/proto"
15 pref "github.com/golang/protobuf/v2/reflect/protoreflect"
16)
17
18// Unmarshal reads the given []byte into the given proto.Message.
19// TODO: may want to describe when Unmarshal returns error.
20func Unmarshal(m proto.Message, b []byte) error {
21 return UnmarshalOptions{}.Unmarshal(m, b)
22}
23
24// UnmarshalOptions is a configurable textproto format parser.
25type UnmarshalOptions struct {
26 pragma.NoUnkeyedLiterals
27}
28
29// Unmarshal reads the given []byte and populates the given proto.Message using options in
30// UnmarshalOptions object.
31func (o UnmarshalOptions) Unmarshal(m proto.Message, b []byte) error {
32 var nerr errors.NonFatal
33
34 mr := m.ProtoReflect()
35 // Clear all fields before populating it.
36 // TODO: Determine if this needs to be consistent with jsonpb and binary unmarshal where
37 // behavior is to merge values into existing message. If decision is to not clear the fields
38 // ahead, code will need to be updated properly when merging nested messages.
39 resetMessage(mr)
40
41 // Parse into text.Value of message type.
42 val, err := text.Unmarshal(b)
43 if !nerr.Merge(err) {
44 return err
45 }
46
47 err = o.unmarshalMessage(val.Message(), mr)
48 if !nerr.Merge(err) {
49 return err
50 }
51
52 return nerr.E
53}
54
55// resetMessage clears all fields of given protoreflect.Message.
56// TODO: This should go into the proto package.
57func resetMessage(m pref.Message) {
58 knownFields := m.KnownFields()
59 knownFields.Range(func(num pref.FieldNumber, _ pref.Value) bool {
60 knownFields.Clear(num)
61 return true
62 })
63 unknownFields := m.UnknownFields()
64 unknownFields.Range(func(num pref.FieldNumber, _ pref.RawFields) bool {
65 unknownFields.Set(num, nil)
66 return true
67 })
68
69 extTypes := knownFields.ExtensionTypes()
70 extTypes.Range(func(xt pref.ExtensionType) bool {
71 extTypes.Remove(xt)
72 return true
73 })
74}
75
76// unmarshalMessage unmarshals a [][2]text.Value message into the given protoreflect.Message.
77func (o UnmarshalOptions) unmarshalMessage(tmsg [][2]text.Value, m pref.Message) error {
78 var nerr errors.NonFatal
79
80 msgType := m.Type()
81 fieldDescs := msgType.Fields()
Herbie Ong7c624e22018-12-13 14:41:22 -080082 reservedNames := msgType.ReservedNames()
Herbie Ong800c9902018-12-06 15:28:53 -080083 knownFields := m.KnownFields()
84 var reqNums set.Ints
85 var seenNums set.Ints
86
87 for _, tfield := range tmsg {
88 tkey := tfield[0]
89 tval := tfield[1]
90
91 var fd pref.FieldDescriptor
Herbie Ong7c624e22018-12-13 14:41:22 -080092 name, ok := tkey.Name()
93 if ok {
Herbie Ong800c9902018-12-06 15:28:53 -080094 fd = fieldDescs.ByName(name)
95 }
96 if fd == nil {
Herbie Ong7c624e22018-12-13 14:41:22 -080097 // Ignore reserved names.
98 if reservedNames.Has(name) {
99 continue
100 }
Herbie Ong800c9902018-12-06 15:28:53 -0800101 // TODO: Can provide option to ignore unknown message fields.
Herbie Ong800c9902018-12-06 15:28:53 -0800102 return errors.New("%v contains unknown field: %v", msgType.FullName(), tkey)
103 }
104
105 if cardinality := fd.Cardinality(); cardinality == pref.Repeated {
106 // Map or list fields have cardinality of repeated.
107 if err := o.unmarshalRepeated(tval, fd, knownFields); !nerr.Merge(err) {
108 return err
109 }
110 } else {
111 // Required or optional fields.
112 num := uint64(fd.Number())
113 if seenNums.Has(num) {
114 return errors.New("non-repeated field %v is repeated", fd.FullName())
115 }
116 if err := o.unmarshalSingular(tval, fd, knownFields); !nerr.Merge(err) {
117 return err
118 }
119 if cardinality == pref.Required {
120 reqNums.Set(num)
121 }
122 seenNums.Set(num)
123 }
124 }
125
126 // Check for any missing required fields.
127 allReqNums := msgType.RequiredNumbers()
128 if reqNums.Len() != allReqNums.Len() {
129 for i := 0; i < allReqNums.Len(); i++ {
130 if num := allReqNums.Get(i); !reqNums.Has(uint64(num)) {
131 nerr.AppendRequiredNotSet(string(fieldDescs.ByNumber(num).FullName()))
132 }
133 }
134 }
135
136 return nerr.E
137}
138
139// unmarshalSingular unmarshals given text.Value into the non-repeated field.
140func (o UnmarshalOptions) unmarshalSingular(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
141 num := fd.Number()
142
143 var nerr errors.NonFatal
144 var val pref.Value
145 switch fd.Kind() {
146 case pref.MessageKind, pref.GroupKind:
147 if input.Type() != text.Message {
148 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
149 }
150 m := knownFields.NewMessage(num).ProtoReflect()
151 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
152 return err
153 }
154 val = pref.ValueOf(m)
155 default:
156 var err error
157 val, err = unmarshalScalar(input, fd)
158 if !nerr.Merge(err) {
159 return err
160 }
161 }
162 knownFields.Set(num, val)
163
164 return nerr.E
165}
166
167// unmarshalRepeated unmarshals given text.Value into a repeated field. Caller should only
168// call this for cardinality=repeated.
169func (o UnmarshalOptions) unmarshalRepeated(input text.Value, fd pref.FieldDescriptor, knownFields pref.KnownFields) error {
170 var items []text.Value
171 // If input is not a list, turn it into a list.
172 if input.Type() != text.List {
173 items = []text.Value{input}
174 } else {
175 items = input.List()
176 }
177
178 var nerr errors.NonFatal
179 num := fd.Number()
180 val := knownFields.Get(num)
181 if !fd.IsMap() {
182 if err := o.unmarshalList(items, fd, val.List()); !nerr.Merge(err) {
183 return err
184 }
185 } else {
186 if err := o.unmarshalMap(items, fd, val.Map()); !nerr.Merge(err) {
187 return err
188 }
189 }
190
191 return nerr.E
192}
193
194// unmarshalScalar converts the given text.Value to a scalar/enum protoreflect.Value specified in
195// the given FieldDescriptor. Caller should not pass in a FieldDescriptor for a message/group kind.
196func unmarshalScalar(input text.Value, fd pref.FieldDescriptor) (pref.Value, error) {
197 const b32 = false
198 const b64 = true
199
200 switch kind := fd.Kind(); kind {
201 case pref.BoolKind:
202 if b, ok := input.Bool(); ok {
203 return pref.ValueOf(bool(b)), nil
204 }
205 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
206 if n, ok := input.Int(b32); ok {
207 return pref.ValueOf(int32(n)), nil
208 }
209 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
210 if n, ok := input.Int(b64); ok {
211 return pref.ValueOf(int64(n)), nil
212 }
213 case pref.Uint32Kind, pref.Fixed32Kind:
214 if n, ok := input.Uint(b32); ok {
215 return pref.ValueOf(uint32(n)), nil
216 }
217 case pref.Uint64Kind, pref.Fixed64Kind:
218 if n, ok := input.Uint(b64); ok {
219 return pref.ValueOf(uint64(n)), nil
220 }
221 case pref.FloatKind:
222 if n, ok := input.Float(b32); ok {
223 return pref.ValueOf(float32(n)), nil
224 }
225 case pref.DoubleKind:
226 if n, ok := input.Float(b64); ok {
227 return pref.ValueOf(float64(n)), nil
228 }
229 case pref.StringKind:
230 if input.Type() == text.String {
231 return pref.ValueOf(string(input.String())), nil
232 }
233 case pref.BytesKind:
234 if input.Type() == text.String {
235 return pref.ValueOf([]byte(input.String())), nil
236 }
237 case pref.EnumKind:
238 // If input is int32, use directly.
239 if n, ok := input.Int(b32); ok {
240 return pref.ValueOf(pref.EnumNumber(n)), nil
241 } else {
242 if name, ok := input.Name(); ok {
243 // Lookup EnumNumber based on name.
244 if enumVal := fd.EnumType().Values().ByName(name); enumVal != nil {
245 return pref.ValueOf(enumVal.Number()), nil
246 }
247 }
248 }
249 default:
250 panic(fmt.Sprintf("invalid scalar kind %v", kind))
251 }
252
253 return pref.Value{}, errors.New("%v contains invalid scalar value: %v", fd.FullName(), input)
254}
255
256// unmarshalList unmarshals given []text.Value into given protoreflect.List.
257func (o UnmarshalOptions) unmarshalList(inputList []text.Value, fd pref.FieldDescriptor, list pref.List) error {
258 var nerr errors.NonFatal
259
260 switch fd.Kind() {
261 case pref.MessageKind, pref.GroupKind:
262 for _, input := range inputList {
263 if input.Type() != text.Message {
264 return errors.New("%v contains invalid message/group value: %v", fd.FullName(), input)
265 }
266 m := list.NewMessage().ProtoReflect()
267 if err := o.unmarshalMessage(input.Message(), m); !nerr.Merge(err) {
268 return err
269 }
270 list.Append(pref.ValueOf(m))
271 }
272 default:
273 for _, input := range inputList {
274 val, err := unmarshalScalar(input, fd)
275 if !nerr.Merge(err) {
276 return err
277 }
278 list.Append(val)
279 }
280 }
281
282 return nerr.E
283}
284
285// unmarshalMap unmarshals given []text.Value into given protoreflect.Map.
286func (o UnmarshalOptions) unmarshalMap(input []text.Value, fd pref.FieldDescriptor, mmap pref.Map) error {
287 var nerr errors.NonFatal
288 fields := fd.MessageType().Fields()
289 keyDesc := fields.ByNumber(1)
290 valDesc := fields.ByNumber(2)
291
292 // Determine ahead whether map entry is a scalar type or a message type in order to call the
293 // appropriate unmarshalMapValue func inside the for loop below.
294 unmarshalMapValue := o.unmarshalMapScalarValue
295 switch valDesc.Kind() {
296 case pref.MessageKind, pref.GroupKind:
297 unmarshalMapValue = o.unmarshalMapMessageValue
298 }
299
300 for _, entry := range input {
301 if entry.Type() != text.Message {
302 return errors.New("%v contains invalid map entry: %v", fd.FullName(), entry)
303 }
304 tkey, tval, err := parseMapEntry(entry.Message(), fd.FullName())
305 if !nerr.Merge(err) {
306 return err
307 }
308 pkey, err := unmarshalMapKey(tkey, keyDesc)
309 if !nerr.Merge(err) {
310 return err
311 }
312 err = unmarshalMapValue(tval, pkey, valDesc, mmap)
313 if !nerr.Merge(err) {
314 return err
315 }
316 }
317
318 return nerr.E
319}
320
321// parseMapEntry parses [][2]text.Value for field names key and value, and return corresponding
322// field values. If there are duplicate field names, the value for the last field is returned. If
323// the field name does not exist, it will return the zero value of text.Value. It will return an
324// error if there are unknown field names.
325func parseMapEntry(mapEntry [][2]text.Value, name pref.FullName) (key text.Value, value text.Value, err error) {
326 for _, field := range mapEntry {
327 keyStr, ok := field[0].Name()
328 if ok {
329 switch keyStr {
330 case "key":
331 if key.Type() != 0 {
332 return key, value, errors.New("%v contains duplicate key field", name)
333 }
334 key = field[1]
335 case "value":
336 if value.Type() != 0 {
337 return key, value, errors.New("%v contains duplicate value field", name)
338 }
339 value = field[1]
340 default:
341 ok = false
342 }
343 }
344 if !ok {
345 // TODO: Do not return error if ignore unknown option is added and enabled.
346 return key, value, errors.New("%v contains unknown map entry name: %v", name, field[0])
347 }
348 }
349 return key, value, nil
350}
351
352// unmarshalMapKey converts given text.Value into a protoreflect.MapKey. A map key type is any
353// integral or string type.
354func unmarshalMapKey(input text.Value, fd pref.FieldDescriptor) (pref.MapKey, error) {
355 // If input is not set, use the zero value.
356 if input.Type() == 0 {
357 return fd.Default().MapKey(), nil
358 }
359
360 val, err := unmarshalScalar(input, fd)
361 if err != nil {
362 return pref.MapKey{}, errors.New("%v contains invalid key: %v", fd.FullName(), input)
363 }
364 return val.MapKey(), nil
365}
366
367// unmarshalMapMessageValue unmarshals given message-type text.Value into a protoreflect.Map for
368// the given MapKey.
369func (o UnmarshalOptions) unmarshalMapMessageValue(input text.Value, pkey pref.MapKey, _ pref.FieldDescriptor, mmap pref.Map) error {
370 var nerr errors.NonFatal
371 var value [][2]text.Value
372 if input.Type() != 0 {
373 value = input.Message()
374 }
375 m := mmap.NewMessage().ProtoReflect()
376 if err := o.unmarshalMessage(value, m); !nerr.Merge(err) {
377 return err
378 }
379 mmap.Set(pkey, pref.ValueOf(m))
380 return nerr.E
381}
382
383// unmarshalMapScalarValue unmarshals given scalar-type text.Value into a protoreflect.Map
384// for the given MapKey.
385func (o UnmarshalOptions) unmarshalMapScalarValue(input text.Value, pkey pref.MapKey, fd pref.FieldDescriptor, mmap pref.Map) error {
386 var val pref.Value
387 if input.Type() == 0 {
388 val = fd.Default()
389 } else {
390 var err error
391 val, err = unmarshalScalar(input, fd)
392 if err != nil {
393 return err
394 }
395 }
396 mmap.Set(pkey, val)
397 return nil
398}