podman

Форк
0
378 строк · 12.5 Кб
1
// Copyright 2019 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

5
package protojson
6

7
import (
8
	"encoding/base64"
9
	"fmt"
10

11
	"google.golang.org/protobuf/internal/encoding/json"
12
	"google.golang.org/protobuf/internal/encoding/messageset"
13
	"google.golang.org/protobuf/internal/errors"
14
	"google.golang.org/protobuf/internal/filedesc"
15
	"google.golang.org/protobuf/internal/flags"
16
	"google.golang.org/protobuf/internal/genid"
17
	"google.golang.org/protobuf/internal/order"
18
	"google.golang.org/protobuf/internal/pragma"
19
	"google.golang.org/protobuf/proto"
20
	"google.golang.org/protobuf/reflect/protoreflect"
21
	"google.golang.org/protobuf/reflect/protoregistry"
22
)
23

24
const defaultIndent = "  "
25

26
// Format formats the message as a multiline string.
27
// This function is only intended for human consumption and ignores errors.
28
// Do not depend on the output being stable. It may change over time across
29
// different versions of the program.
30
func Format(m proto.Message) string {
31
	return MarshalOptions{Multiline: true}.Format(m)
32
}
33

34
// Marshal writes the given [proto.Message] in JSON format using default options.
35
// Do not depend on the output being stable. It may change over time across
36
// different versions of the program.
37
func Marshal(m proto.Message) ([]byte, error) {
38
	return MarshalOptions{}.Marshal(m)
39
}
40

41
// MarshalOptions is a configurable JSON format marshaler.
42
type MarshalOptions struct {
43
	pragma.NoUnkeyedLiterals
44

45
	// Multiline specifies whether the marshaler should format the output in
46
	// indented-form with every textual element on a new line.
47
	// If Indent is an empty string, then an arbitrary indent is chosen.
48
	Multiline bool
49

50
	// Indent specifies the set of indentation characters to use in a multiline
51
	// formatted output such that every entry is preceded by Indent and
52
	// terminated by a newline. If non-empty, then Multiline is treated as true.
53
	// Indent can only be composed of space or tab characters.
54
	Indent string
55

56
	// AllowPartial allows messages that have missing required fields to marshal
57
	// without returning an error. If AllowPartial is false (the default),
58
	// Marshal will return error if there are any missing required fields.
59
	AllowPartial bool
60

61
	// UseProtoNames uses proto field name instead of lowerCamelCase name in JSON
62
	// field names.
63
	UseProtoNames bool
64

65
	// UseEnumNumbers emits enum values as numbers.
66
	UseEnumNumbers bool
67

68
	// EmitUnpopulated specifies whether to emit unpopulated fields. It does not
69
	// emit unpopulated oneof fields or unpopulated extension fields.
70
	// The JSON value emitted for unpopulated fields are as follows:
71
	//  ╔═══════╤════════════════════════════╗
72
	//  ║ JSON  │ Protobuf field             ║
73
	//  ╠═══════╪════════════════════════════╣
74
	//  ║ false │ proto3 boolean fields      ║
75
	//  ║ 0     │ proto3 numeric fields      ║
76
	//  ║ ""    │ proto3 string/bytes fields ║
77
	//  ║ null  │ proto2 scalar fields       ║
78
	//  ║ null  │ message fields             ║
79
	//  ║ []    │ list fields                ║
80
	//  ║ {}    │ map fields                 ║
81
	//  ╚═══════╧════════════════════════════╝
82
	EmitUnpopulated bool
83

84
	// EmitDefaultValues specifies whether to emit default-valued primitive fields,
85
	// empty lists, and empty maps. The fields affected are as follows:
86
	//  ╔═══════╤════════════════════════════════════════╗
87
	//  ║ JSON  │ Protobuf field                         ║
88
	//  ╠═══════╪════════════════════════════════════════╣
89
	//  ║ false │ non-optional scalar boolean fields     ║
90
	//  ║ 0     │ non-optional scalar numeric fields     ║
91
	//  ║ ""    │ non-optional scalar string/byte fields ║
92
	//  ║ []    │ empty repeated fields                  ║
93
	//  ║ {}    │ empty map fields                       ║
94
	//  ╚═══════╧════════════════════════════════════════╝
95
	//
96
	// Behaves similarly to EmitUnpopulated, but does not emit "null"-value fields,
97
	// i.e. presence-sensing fields that are omitted will remain omitted to preserve
98
	// presence-sensing.
99
	// EmitUnpopulated takes precedence over EmitDefaultValues since the former generates
100
	// a strict superset of the latter.
101
	EmitDefaultValues bool
102

103
	// Resolver is used for looking up types when expanding google.protobuf.Any
104
	// messages. If nil, this defaults to using protoregistry.GlobalTypes.
105
	Resolver interface {
106
		protoregistry.ExtensionTypeResolver
107
		protoregistry.MessageTypeResolver
108
	}
109
}
110

111
// Format formats the message as a string.
112
// This method is only intended for human consumption and ignores errors.
113
// Do not depend on the output being stable. It may change over time across
114
// different versions of the program.
115
func (o MarshalOptions) Format(m proto.Message) string {
116
	if m == nil || !m.ProtoReflect().IsValid() {
117
		return "<nil>" // invalid syntax, but okay since this is for debugging
118
	}
119
	o.AllowPartial = true
120
	b, _ := o.Marshal(m)
121
	return string(b)
122
}
123

124
// Marshal marshals the given [proto.Message] in the JSON format using options in
125
// MarshalOptions. Do not depend on the output being stable. It may change over
126
// time across different versions of the program.
127
func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
128
	return o.marshal(nil, m)
129
}
130

131
// MarshalAppend appends the JSON format encoding of m to b,
132
// returning the result.
133
func (o MarshalOptions) MarshalAppend(b []byte, m proto.Message) ([]byte, error) {
134
	return o.marshal(b, m)
135
}
136

137
// marshal is a centralized function that all marshal operations go through.
138
// For profiling purposes, avoid changing the name of this function or
139
// introducing other code paths for marshal that do not go through this.
140
func (o MarshalOptions) marshal(b []byte, m proto.Message) ([]byte, error) {
141
	if o.Multiline && o.Indent == "" {
142
		o.Indent = defaultIndent
143
	}
144
	if o.Resolver == nil {
145
		o.Resolver = protoregistry.GlobalTypes
146
	}
147

148
	internalEnc, err := json.NewEncoder(b, o.Indent)
149
	if err != nil {
150
		return nil, err
151
	}
152

153
	// Treat nil message interface as an empty message,
154
	// in which case the output in an empty JSON object.
155
	if m == nil {
156
		return append(b, '{', '}'), nil
157
	}
158

159
	enc := encoder{internalEnc, o}
160
	if err := enc.marshalMessage(m.ProtoReflect(), ""); err != nil {
161
		return nil, err
162
	}
163
	if o.AllowPartial {
164
		return enc.Bytes(), nil
165
	}
166
	return enc.Bytes(), proto.CheckInitialized(m)
167
}
168

169
type encoder struct {
170
	*json.Encoder
171
	opts MarshalOptions
172
}
173

174
// typeFieldDesc is a synthetic field descriptor used for the "@type" field.
175
var typeFieldDesc = func() protoreflect.FieldDescriptor {
176
	var fd filedesc.Field
177
	fd.L0.FullName = "@type"
178
	fd.L0.Index = -1
179
	fd.L1.Cardinality = protoreflect.Optional
180
	fd.L1.Kind = protoreflect.StringKind
181
	return &fd
182
}()
183

184
// typeURLFieldRanger wraps a protoreflect.Message and modifies its Range method
185
// to additionally iterate over a synthetic field for the type URL.
186
type typeURLFieldRanger struct {
187
	order.FieldRanger
188
	typeURL string
189
}
190

191
func (m typeURLFieldRanger) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
192
	if !f(typeFieldDesc, protoreflect.ValueOfString(m.typeURL)) {
193
		return
194
	}
195
	m.FieldRanger.Range(f)
196
}
197

198
// unpopulatedFieldRanger wraps a protoreflect.Message and modifies its Range
199
// method to additionally iterate over unpopulated fields.
200
type unpopulatedFieldRanger struct {
201
	protoreflect.Message
202

203
	skipNull bool
204
}
205

206
func (m unpopulatedFieldRanger) Range(f func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {
207
	fds := m.Descriptor().Fields()
208
	for i := 0; i < fds.Len(); i++ {
209
		fd := fds.Get(i)
210
		if m.Has(fd) || fd.ContainingOneof() != nil {
211
			continue // ignore populated fields and fields within a oneofs
212
		}
213

214
		v := m.Get(fd)
215
		isProto2Scalar := fd.Syntax() == protoreflect.Proto2 && fd.Default().IsValid()
216
		isSingularMessage := fd.Cardinality() != protoreflect.Repeated && fd.Message() != nil
217
		if isProto2Scalar || isSingularMessage {
218
			if m.skipNull {
219
				continue
220
			}
221
			v = protoreflect.Value{} // use invalid value to emit null
222
		}
223
		if !f(fd, v) {
224
			return
225
		}
226
	}
227
	m.Message.Range(f)
228
}
229

230
// marshalMessage marshals the fields in the given protoreflect.Message.
231
// If the typeURL is non-empty, then a synthetic "@type" field is injected
232
// containing the URL as the value.
233
func (e encoder) marshalMessage(m protoreflect.Message, typeURL string) error {
234
	if !flags.ProtoLegacy && messageset.IsMessageSet(m.Descriptor()) {
235
		return errors.New("no support for proto1 MessageSets")
236
	}
237

238
	if marshal := wellKnownTypeMarshaler(m.Descriptor().FullName()); marshal != nil {
239
		return marshal(e, m)
240
	}
241

242
	e.StartObject()
243
	defer e.EndObject()
244

245
	var fields order.FieldRanger = m
246
	switch {
247
	case e.opts.EmitUnpopulated:
248
		fields = unpopulatedFieldRanger{Message: m, skipNull: false}
249
	case e.opts.EmitDefaultValues:
250
		fields = unpopulatedFieldRanger{Message: m, skipNull: true}
251
	}
252
	if typeURL != "" {
253
		fields = typeURLFieldRanger{fields, typeURL}
254
	}
255

256
	var err error
257
	order.RangeFields(fields, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
258
		name := fd.JSONName()
259
		if e.opts.UseProtoNames {
260
			name = fd.TextName()
261
		}
262

263
		if err = e.WriteName(name); err != nil {
264
			return false
265
		}
266
		if err = e.marshalValue(v, fd); err != nil {
267
			return false
268
		}
269
		return true
270
	})
271
	return err
272
}
273

274
// marshalValue marshals the given protoreflect.Value.
275
func (e encoder) marshalValue(val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
276
	switch {
277
	case fd.IsList():
278
		return e.marshalList(val.List(), fd)
279
	case fd.IsMap():
280
		return e.marshalMap(val.Map(), fd)
281
	default:
282
		return e.marshalSingular(val, fd)
283
	}
284
}
285

286
// marshalSingular marshals the given non-repeated field value. This includes
287
// all scalar types, enums, messages, and groups.
288
func (e encoder) marshalSingular(val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
289
	if !val.IsValid() {
290
		e.WriteNull()
291
		return nil
292
	}
293

294
	switch kind := fd.Kind(); kind {
295
	case protoreflect.BoolKind:
296
		e.WriteBool(val.Bool())
297

298
	case protoreflect.StringKind:
299
		if e.WriteString(val.String()) != nil {
300
			return errors.InvalidUTF8(string(fd.FullName()))
301
		}
302

303
	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
304
		e.WriteInt(val.Int())
305

306
	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
307
		e.WriteUint(val.Uint())
308

309
	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind,
310
		protoreflect.Sfixed64Kind, protoreflect.Fixed64Kind:
311
		// 64-bit integers are written out as JSON string.
312
		e.WriteString(val.String())
313

314
	case protoreflect.FloatKind:
315
		// Encoder.WriteFloat handles the special numbers NaN and infinites.
316
		e.WriteFloat(val.Float(), 32)
317

318
	case protoreflect.DoubleKind:
319
		// Encoder.WriteFloat handles the special numbers NaN and infinites.
320
		e.WriteFloat(val.Float(), 64)
321

322
	case protoreflect.BytesKind:
323
		e.WriteString(base64.StdEncoding.EncodeToString(val.Bytes()))
324

325
	case protoreflect.EnumKind:
326
		if fd.Enum().FullName() == genid.NullValue_enum_fullname {
327
			e.WriteNull()
328
		} else {
329
			desc := fd.Enum().Values().ByNumber(val.Enum())
330
			if e.opts.UseEnumNumbers || desc == nil {
331
				e.WriteInt(int64(val.Enum()))
332
			} else {
333
				e.WriteString(string(desc.Name()))
334
			}
335
		}
336

337
	case protoreflect.MessageKind, protoreflect.GroupKind:
338
		if err := e.marshalMessage(val.Message(), ""); err != nil {
339
			return err
340
		}
341

342
	default:
343
		panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
344
	}
345
	return nil
346
}
347

348
// marshalList marshals the given protoreflect.List.
349
func (e encoder) marshalList(list protoreflect.List, fd protoreflect.FieldDescriptor) error {
350
	e.StartArray()
351
	defer e.EndArray()
352

353
	for i := 0; i < list.Len(); i++ {
354
		item := list.Get(i)
355
		if err := e.marshalSingular(item, fd); err != nil {
356
			return err
357
		}
358
	}
359
	return nil
360
}
361

362
// marshalMap marshals given protoreflect.Map.
363
func (e encoder) marshalMap(mmap protoreflect.Map, fd protoreflect.FieldDescriptor) error {
364
	e.StartObject()
365
	defer e.EndObject()
366

367
	var err error
368
	order.RangeEntries(mmap, order.GenericKeyOrder, func(k protoreflect.MapKey, v protoreflect.Value) bool {
369
		if err = e.WriteName(k.String()); err != nil {
370
			return false
371
		}
372
		if err = e.marshalSingular(v, fd.MapValue()); err != nil {
373
			return false
374
		}
375
		return true
376
	})
377
	return err
378
}
379

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.