go-bot

Форк
0
438 строк · 12.8 Кб
1
// 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

5
package protoreflect
6

7
import (
8
	"fmt"
9
	"math"
10
)
11

12
// Value is a union where only one Go type may be set at a time.
13
// The Value is used to represent all possible values a field may take.
14
// The following shows which Go type is used to represent each proto Kind:
15
//
16
//	╔════════════╤═════════════════════════════════════╗
17
//	║ Go type    │ Protobuf kind                       ║
18
//	╠════════════╪═════════════════════════════════════╣
19
//	║ bool       │ BoolKind                            ║
20
//	║ int32      │ Int32Kind, Sint32Kind, Sfixed32Kind ║
21
//	║ int64      │ Int64Kind, Sint64Kind, Sfixed64Kind ║
22
//	║ uint32     │ Uint32Kind, Fixed32Kind             ║
23
//	║ uint64     │ Uint64Kind, Fixed64Kind             ║
24
//	║ float32    │ FloatKind                           ║
25
//	║ float64    │ DoubleKind                          ║
26
//	║ string     │ StringKind                          ║
27
//	║ []byte     │ BytesKind                           ║
28
//	║ EnumNumber │ EnumKind                            ║
29
//	║ Message    │ MessageKind, GroupKind              ║
30
//	╚════════════╧═════════════════════════════════════╝
31
//
32
// Multiple protobuf Kinds may be represented by a single Go type if the type
33
// can losslessly represent the information for the proto kind. For example,
34
// Int64Kind, Sint64Kind, and Sfixed64Kind are all represented by int64,
35
// but use different integer encoding methods.
36
//
37
// The List or Map types are used if the field cardinality is repeated.
38
// A field is a List if FieldDescriptor.IsList reports true.
39
// A field is a Map if FieldDescriptor.IsMap reports true.
40
//
41
// Converting to/from a Value and a concrete Go value panics on type mismatch.
42
// For example, ValueOf("hello").Int() panics because this attempts to
43
// retrieve an int64 from a string.
44
//
45
// List, Map, and Message Values are called "composite" values.
46
//
47
// A composite Value may alias (reference) memory at some location,
48
// such that changes to the Value updates the that location.
49
// A composite value acquired with a Mutable method, such as Message.Mutable,
50
// always references the source object.
51
//
52
// For example:
53
//
54
//	// Append a 0 to a "repeated int32" field.
55
//	// Since the Value returned by Mutable is guaranteed to alias
56
//	// the source message, modifying the Value modifies the message.
57
//	message.Mutable(fieldDesc).List().Append(protoreflect.ValueOfInt32(0))
58
//
59
//	// Assign [0] to a "repeated int32" field by creating a new Value,
60
//	// modifying it, and assigning it.
61
//	list := message.NewField(fieldDesc).List()
62
//	list.Append(protoreflect.ValueOfInt32(0))
63
//	message.Set(fieldDesc, list)
64
//	// ERROR: Since it is not defined whether Set aliases the source,
65
//	// appending to the List here may or may not modify the message.
66
//	list.Append(protoreflect.ValueOfInt32(0))
67
//
68
// Some operations, such as Message.Get, may return an "empty, read-only"
69
// composite Value. Modifying an empty, read-only value panics.
70
type Value value
71

72
// The protoreflect API uses a custom Value union type instead of interface{}
73
// to keep the future open for performance optimizations. Using an interface{}
74
// always incurs an allocation for primitives (e.g., int64) since it needs to
75
// be boxed on the heap (as interfaces can only contain pointers natively).
76
// Instead, we represent the Value union as a flat struct that internally keeps
77
// track of which type is set. Using unsafe, the Value union can be reduced
78
// down to 24B, which is identical in size to a slice.
79
//
80
// The latest compiler (Go1.11) currently suffers from some limitations:
81
//	• With inlining, the compiler should be able to statically prove that
82
//	only one of these switch cases are taken and inline one specific case.
83
//	See https://golang.org/issue/22310.
84

85
// ValueOf returns a Value initialized with the concrete value stored in v.
86
// This panics if the type does not match one of the allowed types in the
87
// Value union.
88
func ValueOf(v interface{}) Value {
89
	switch v := v.(type) {
90
	case nil:
91
		return Value{}
92
	case bool:
93
		return ValueOfBool(v)
94
	case int32:
95
		return ValueOfInt32(v)
96
	case int64:
97
		return ValueOfInt64(v)
98
	case uint32:
99
		return ValueOfUint32(v)
100
	case uint64:
101
		return ValueOfUint64(v)
102
	case float32:
103
		return ValueOfFloat32(v)
104
	case float64:
105
		return ValueOfFloat64(v)
106
	case string:
107
		return ValueOfString(v)
108
	case []byte:
109
		return ValueOfBytes(v)
110
	case EnumNumber:
111
		return ValueOfEnum(v)
112
	case Message, List, Map:
113
		return valueOfIface(v)
114
	case ProtoMessage:
115
		panic(fmt.Sprintf("invalid proto.Message(%T) type, expected a protoreflect.Message type", v))
116
	default:
117
		panic(fmt.Sprintf("invalid type: %T", v))
118
	}
119
}
120

121
// ValueOfBool returns a new boolean value.
122
func ValueOfBool(v bool) Value {
123
	if v {
124
		return Value{typ: boolType, num: 1}
125
	} else {
126
		return Value{typ: boolType, num: 0}
127
	}
128
}
129

130
// ValueOfInt32 returns a new int32 value.
131
func ValueOfInt32(v int32) Value {
132
	return Value{typ: int32Type, num: uint64(v)}
133
}
134

135
// ValueOfInt64 returns a new int64 value.
136
func ValueOfInt64(v int64) Value {
137
	return Value{typ: int64Type, num: uint64(v)}
138
}
139

140
// ValueOfUint32 returns a new uint32 value.
141
func ValueOfUint32(v uint32) Value {
142
	return Value{typ: uint32Type, num: uint64(v)}
143
}
144

145
// ValueOfUint64 returns a new uint64 value.
146
func ValueOfUint64(v uint64) Value {
147
	return Value{typ: uint64Type, num: v}
148
}
149

150
// ValueOfFloat32 returns a new float32 value.
151
func ValueOfFloat32(v float32) Value {
152
	return Value{typ: float32Type, num: uint64(math.Float64bits(float64(v)))}
153
}
154

155
// ValueOfFloat64 returns a new float64 value.
156
func ValueOfFloat64(v float64) Value {
157
	return Value{typ: float64Type, num: uint64(math.Float64bits(float64(v)))}
158
}
159

160
// ValueOfString returns a new string value.
161
func ValueOfString(v string) Value {
162
	return valueOfString(v)
163
}
164

165
// ValueOfBytes returns a new bytes value.
166
func ValueOfBytes(v []byte) Value {
167
	return valueOfBytes(v[:len(v):len(v)])
168
}
169

170
// ValueOfEnum returns a new enum value.
171
func ValueOfEnum(v EnumNumber) Value {
172
	return Value{typ: enumType, num: uint64(v)}
173
}
174

175
// ValueOfMessage returns a new Message value.
176
func ValueOfMessage(v Message) Value {
177
	return valueOfIface(v)
178
}
179

180
// ValueOfList returns a new List value.
181
func ValueOfList(v List) Value {
182
	return valueOfIface(v)
183
}
184

185
// ValueOfMap returns a new Map value.
186
func ValueOfMap(v Map) Value {
187
	return valueOfIface(v)
188
}
189

190
// IsValid reports whether v is populated with a value.
191
func (v Value) IsValid() bool {
192
	return v.typ != nilType
193
}
194

195
// Interface returns v as an interface{}.
196
//
197
// Invariant: v == ValueOf(v).Interface()
198
func (v Value) Interface() interface{} {
199
	switch v.typ {
200
	case nilType:
201
		return nil
202
	case boolType:
203
		return v.Bool()
204
	case int32Type:
205
		return int32(v.Int())
206
	case int64Type:
207
		return int64(v.Int())
208
	case uint32Type:
209
		return uint32(v.Uint())
210
	case uint64Type:
211
		return uint64(v.Uint())
212
	case float32Type:
213
		return float32(v.Float())
214
	case float64Type:
215
		return float64(v.Float())
216
	case stringType:
217
		return v.String()
218
	case bytesType:
219
		return v.Bytes()
220
	case enumType:
221
		return v.Enum()
222
	default:
223
		return v.getIface()
224
	}
225
}
226

227
func (v Value) typeName() string {
228
	switch v.typ {
229
	case nilType:
230
		return "nil"
231
	case boolType:
232
		return "bool"
233
	case int32Type:
234
		return "int32"
235
	case int64Type:
236
		return "int64"
237
	case uint32Type:
238
		return "uint32"
239
	case uint64Type:
240
		return "uint64"
241
	case float32Type:
242
		return "float32"
243
	case float64Type:
244
		return "float64"
245
	case stringType:
246
		return "string"
247
	case bytesType:
248
		return "bytes"
249
	case enumType:
250
		return "enum"
251
	default:
252
		switch v := v.getIface().(type) {
253
		case Message:
254
			return "message"
255
		case List:
256
			return "list"
257
		case Map:
258
			return "map"
259
		default:
260
			return fmt.Sprintf("<unknown: %T>", v)
261
		}
262
	}
263
}
264

265
func (v Value) panicMessage(what string) string {
266
	return fmt.Sprintf("type mismatch: cannot convert %v to %s", v.typeName(), what)
267
}
268

269
// Bool returns v as a bool and panics if the type is not a bool.
270
func (v Value) Bool() bool {
271
	switch v.typ {
272
	case boolType:
273
		return v.num > 0
274
	default:
275
		panic(v.panicMessage("bool"))
276
	}
277
}
278

279
// Int returns v as a int64 and panics if the type is not a int32 or int64.
280
func (v Value) Int() int64 {
281
	switch v.typ {
282
	case int32Type, int64Type:
283
		return int64(v.num)
284
	default:
285
		panic(v.panicMessage("int"))
286
	}
287
}
288

289
// Uint returns v as a uint64 and panics if the type is not a uint32 or uint64.
290
func (v Value) Uint() uint64 {
291
	switch v.typ {
292
	case uint32Type, uint64Type:
293
		return uint64(v.num)
294
	default:
295
		panic(v.panicMessage("uint"))
296
	}
297
}
298

299
// Float returns v as a float64 and panics if the type is not a float32 or float64.
300
func (v Value) Float() float64 {
301
	switch v.typ {
302
	case float32Type, float64Type:
303
		return math.Float64frombits(uint64(v.num))
304
	default:
305
		panic(v.panicMessage("float"))
306
	}
307
}
308

309
// String returns v as a string. Since this method implements fmt.Stringer,
310
// this returns the formatted string value for any non-string type.
311
func (v Value) String() string {
312
	switch v.typ {
313
	case stringType:
314
		return v.getString()
315
	default:
316
		return fmt.Sprint(v.Interface())
317
	}
318
}
319

320
// Bytes returns v as a []byte and panics if the type is not a []byte.
321
func (v Value) Bytes() []byte {
322
	switch v.typ {
323
	case bytesType:
324
		return v.getBytes()
325
	default:
326
		panic(v.panicMessage("bytes"))
327
	}
328
}
329

330
// Enum returns v as a EnumNumber and panics if the type is not a EnumNumber.
331
func (v Value) Enum() EnumNumber {
332
	switch v.typ {
333
	case enumType:
334
		return EnumNumber(v.num)
335
	default:
336
		panic(v.panicMessage("enum"))
337
	}
338
}
339

340
// Message returns v as a Message and panics if the type is not a Message.
341
func (v Value) Message() Message {
342
	switch vi := v.getIface().(type) {
343
	case Message:
344
		return vi
345
	default:
346
		panic(v.panicMessage("message"))
347
	}
348
}
349

350
// List returns v as a List and panics if the type is not a List.
351
func (v Value) List() List {
352
	switch vi := v.getIface().(type) {
353
	case List:
354
		return vi
355
	default:
356
		panic(v.panicMessage("list"))
357
	}
358
}
359

360
// Map returns v as a Map and panics if the type is not a Map.
361
func (v Value) Map() Map {
362
	switch vi := v.getIface().(type) {
363
	case Map:
364
		return vi
365
	default:
366
		panic(v.panicMessage("map"))
367
	}
368
}
369

370
// MapKey returns v as a MapKey and panics for invalid MapKey types.
371
func (v Value) MapKey() MapKey {
372
	switch v.typ {
373
	case boolType, int32Type, int64Type, uint32Type, uint64Type, stringType:
374
		return MapKey(v)
375
	default:
376
		panic(v.panicMessage("map key"))
377
	}
378
}
379

380
// MapKey is used to index maps, where the Go type of the MapKey must match
381
// the specified key Kind (see MessageDescriptor.IsMapEntry).
382
// The following shows what Go type is used to represent each proto Kind:
383
//
384
//	╔═════════╤═════════════════════════════════════╗
385
//	║ Go type │ Protobuf kind                       ║
386
//	╠═════════╪═════════════════════════════════════╣
387
//	║ bool    │ BoolKind                            ║
388
//	║ int32   │ Int32Kind, Sint32Kind, Sfixed32Kind ║
389
//	║ int64   │ Int64Kind, Sint64Kind, Sfixed64Kind ║
390
//	║ uint32  │ Uint32Kind, Fixed32Kind             ║
391
//	║ uint64  │ Uint64Kind, Fixed64Kind             ║
392
//	║ string  │ StringKind                          ║
393
//	╚═════════╧═════════════════════════════════════╝
394
//
395
// A MapKey is constructed and accessed through a Value:
396
//
397
//	k := ValueOf("hash").MapKey() // convert string to MapKey
398
//	s := k.String()               // convert MapKey to string
399
//
400
// The MapKey is a strict subset of valid types used in Value;
401
// converting a Value to a MapKey with an invalid type panics.
402
type MapKey value
403

404
// IsValid reports whether k is populated with a value.
405
func (k MapKey) IsValid() bool {
406
	return Value(k).IsValid()
407
}
408

409
// Interface returns k as an interface{}.
410
func (k MapKey) Interface() interface{} {
411
	return Value(k).Interface()
412
}
413

414
// Bool returns k as a bool and panics if the type is not a bool.
415
func (k MapKey) Bool() bool {
416
	return Value(k).Bool()
417
}
418

419
// Int returns k as a int64 and panics if the type is not a int32 or int64.
420
func (k MapKey) Int() int64 {
421
	return Value(k).Int()
422
}
423

424
// Uint returns k as a uint64 and panics if the type is not a uint32 or uint64.
425
func (k MapKey) Uint() uint64 {
426
	return Value(k).Uint()
427
}
428

429
// String returns k as a string. Since this method implements fmt.Stringer,
430
// this returns the formatted string value for any non-string type.
431
func (k MapKey) String() string {
432
	return Value(k).String()
433
}
434

435
// Value returns k as a Value.
436
func (k MapKey) Value() Value {
437
	return Value(k)
438
}
439

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

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

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

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