Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/proto2/message.js
2868 views
1
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview Protocol Buffer Message base class.
17
* @suppress {unusedPrivateMembers} For descriptor_ declaration.
18
*/
19
20
goog.provide('goog.proto2.Message');
21
22
goog.require('goog.asserts');
23
goog.require('goog.proto2.Descriptor');
24
goog.require('goog.proto2.FieldDescriptor');
25
26
goog.forwardDeclare('goog.proto2.LazyDeserializer'); // circular reference
27
28
29
30
/**
31
* Abstract base class for all Protocol Buffer 2 messages. It will be
32
* subclassed in the code generated by the Protocol Compiler. Any other
33
* subclasses are prohibited.
34
* @constructor
35
*/
36
goog.proto2.Message = function() {
37
/**
38
* Stores the field values in this message. Keyed by the tag of the fields.
39
* @type {!Object}
40
* @private
41
*/
42
this.values_ = {};
43
44
/**
45
* Stores the field information (i.e. metadata) about this message.
46
* @type {Object<number, !goog.proto2.FieldDescriptor>}
47
* @private
48
*/
49
this.fields_ = this.getDescriptor().getFieldsMap();
50
51
/**
52
* The lazy deserializer for this message instance, if any.
53
* @type {goog.proto2.LazyDeserializer}
54
* @private
55
*/
56
this.lazyDeserializer_ = null;
57
58
/**
59
* A map of those fields deserialized, from tag number to their deserialized
60
* value.
61
* @type {Object}
62
* @private
63
*/
64
this.deserializedFields_ = null;
65
};
66
67
68
/**
69
* An enumeration defining the possible field types.
70
* Should be a mirror of that defined in descriptor.h.
71
*
72
* TODO(user): Remove this alias. The code generator generates code that
73
* references this enum, so it needs to exist until the code generator is
74
* changed. The enum was moved to from Message to FieldDescriptor to avoid a
75
* dependency cycle.
76
*
77
* Use goog.proto2.FieldDescriptor.FieldType instead.
78
*
79
* @enum {number}
80
*/
81
goog.proto2.Message.FieldType = {
82
DOUBLE: 1,
83
FLOAT: 2,
84
INT64: 3,
85
UINT64: 4,
86
INT32: 5,
87
FIXED64: 6,
88
FIXED32: 7,
89
BOOL: 8,
90
STRING: 9,
91
GROUP: 10,
92
MESSAGE: 11,
93
BYTES: 12,
94
UINT32: 13,
95
ENUM: 14,
96
SFIXED32: 15,
97
SFIXED64: 16,
98
SINT32: 17,
99
SINT64: 18
100
};
101
102
103
/**
104
* All instances of goog.proto2.Message should have a static descriptor_
105
* property. The Descriptor will be deserialized lazily in the getDescriptor()
106
* method.
107
*
108
* This declaration is just here for documentation purposes.
109
* goog.proto2.Message does not have its own descriptor.
110
*
111
* @type {undefined}
112
* @private
113
*/
114
goog.proto2.Message.descriptor_;
115
116
117
/**
118
* Initializes the message with a lazy deserializer and its associated data.
119
* This method should be called by internal methods ONLY.
120
*
121
* @param {goog.proto2.LazyDeserializer} deserializer The lazy deserializer to
122
* use to decode the data on the fly.
123
*
124
* @param {?} data The data to decode/deserialize.
125
*/
126
goog.proto2.Message.prototype.initializeForLazyDeserializer = function(
127
deserializer, data) {
128
129
this.lazyDeserializer_ = deserializer;
130
this.values_ = data;
131
this.deserializedFields_ = {};
132
};
133
134
135
/**
136
* Sets the value of an unknown field, by tag.
137
*
138
* @param {number} tag The tag of an unknown field (must be >= 1).
139
* @param {*} value The value for that unknown field.
140
*/
141
goog.proto2.Message.prototype.setUnknown = function(tag, value) {
142
goog.asserts.assert(
143
!this.fields_[tag], 'Field is not unknown in this message');
144
goog.asserts.assert(
145
tag >= 1, 'Tag ' + tag + ' has value "' + value + '" in descriptor ' +
146
this.getDescriptor().getName());
147
148
goog.asserts.assert(value !== null, 'Value cannot be null');
149
150
this.values_[tag] = value;
151
if (this.deserializedFields_) {
152
delete this.deserializedFields_[tag];
153
}
154
};
155
156
157
/**
158
* Iterates over all the unknown fields in the message.
159
*
160
* @param {function(this:T, number, *)} callback A callback method
161
* which gets invoked for each unknown field.
162
* @param {T=} opt_scope The scope under which to execute the callback.
163
* If not given, the current message will be used.
164
* @template T
165
*/
166
goog.proto2.Message.prototype.forEachUnknown = function(callback, opt_scope) {
167
var scope = opt_scope || this;
168
for (var key in this.values_) {
169
var keyNum = Number(key);
170
if (!this.fields_[keyNum]) {
171
callback.call(scope, keyNum, this.values_[key]);
172
}
173
}
174
};
175
176
177
/**
178
* Returns the descriptor which describes the current message.
179
*
180
* This only works if we assume people never subclass protobufs.
181
*
182
* @return {!goog.proto2.Descriptor} The descriptor.
183
*/
184
goog.proto2.Message.prototype.getDescriptor = goog.abstractMethod;
185
186
187
/**
188
* Returns whether there is a value stored at the field specified by the
189
* given field descriptor.
190
*
191
* @param {goog.proto2.FieldDescriptor} field The field for which to check
192
* if there is a value.
193
*
194
* @return {boolean} True if a value was found.
195
*/
196
goog.proto2.Message.prototype.has = function(field) {
197
goog.asserts.assert(
198
field.getContainingType() == this.getDescriptor(),
199
'The current message does not contain the given field');
200
201
return this.has$Value(field.getTag());
202
};
203
204
205
/**
206
* Returns the array of values found for the given repeated field.
207
*
208
* @param {goog.proto2.FieldDescriptor} field The field for which to
209
* return the values.
210
*
211
* @return {!Array<?>} The values found.
212
*/
213
goog.proto2.Message.prototype.arrayOf = function(field) {
214
goog.asserts.assert(
215
field.getContainingType() == this.getDescriptor(),
216
'The current message does not contain the given field');
217
218
return this.array$Values(field.getTag());
219
};
220
221
222
/**
223
* Returns the number of values stored in the given field.
224
*
225
* @param {goog.proto2.FieldDescriptor} field The field for which to count
226
* the number of values.
227
*
228
* @return {number} The count of the values in the given field.
229
*/
230
goog.proto2.Message.prototype.countOf = function(field) {
231
goog.asserts.assert(
232
field.getContainingType() == this.getDescriptor(),
233
'The current message does not contain the given field');
234
235
return this.count$Values(field.getTag());
236
};
237
238
239
/**
240
* Returns the value stored at the field specified by the
241
* given field descriptor.
242
*
243
* @param {goog.proto2.FieldDescriptor} field The field for which to get the
244
* value.
245
* @param {number=} opt_index If the field is repeated, the index to use when
246
* looking up the value.
247
*
248
* @return {?} The value found or null if none.
249
*/
250
goog.proto2.Message.prototype.get = function(field, opt_index) {
251
goog.asserts.assert(
252
field.getContainingType() == this.getDescriptor(),
253
'The current message does not contain the given field');
254
255
return this.get$Value(field.getTag(), opt_index);
256
};
257
258
259
/**
260
* Returns the value stored at the field specified by the
261
* given field descriptor or the default value if none exists.
262
*
263
* @param {goog.proto2.FieldDescriptor} field The field for which to get the
264
* value.
265
* @param {number=} opt_index If the field is repeated, the index to use when
266
* looking up the value.
267
*
268
* @return {?} The value found or the default if none.
269
*/
270
goog.proto2.Message.prototype.getOrDefault = function(field, opt_index) {
271
goog.asserts.assert(
272
field.getContainingType() == this.getDescriptor(),
273
'The current message does not contain the given field');
274
275
return this.get$ValueOrDefault(field.getTag(), opt_index);
276
};
277
278
279
/**
280
* Stores the given value to the field specified by the
281
* given field descriptor. Note that the field must not be repeated.
282
*
283
* @param {goog.proto2.FieldDescriptor} field The field for which to set
284
* the value.
285
* @param {*} value The new value for the field.
286
*/
287
goog.proto2.Message.prototype.set = function(field, value) {
288
goog.asserts.assert(
289
field.getContainingType() == this.getDescriptor(),
290
'The current message does not contain the given field');
291
292
this.set$Value(field.getTag(), value);
293
};
294
295
296
/**
297
* Adds the given value to the field specified by the
298
* given field descriptor. Note that the field must be repeated.
299
*
300
* @param {goog.proto2.FieldDescriptor} field The field in which to add the
301
* the value.
302
* @param {*} value The new value to add to the field.
303
*/
304
goog.proto2.Message.prototype.add = function(field, value) {
305
goog.asserts.assert(
306
field.getContainingType() == this.getDescriptor(),
307
'The current message does not contain the given field');
308
309
this.add$Value(field.getTag(), value);
310
};
311
312
313
/**
314
* Clears the field specified.
315
*
316
* @param {goog.proto2.FieldDescriptor} field The field to clear.
317
*/
318
goog.proto2.Message.prototype.clear = function(field) {
319
goog.asserts.assert(
320
field.getContainingType() == this.getDescriptor(),
321
'The current message does not contain the given field');
322
323
this.clear$Field(field.getTag());
324
};
325
326
327
/**
328
* Compares this message with another one ignoring the unknown fields.
329
* @param {?} other The other message.
330
* @return {boolean} Whether they are equal. Returns false if the {@code other}
331
* argument is a different type of message or not a message.
332
*/
333
goog.proto2.Message.prototype.equals = function(other) {
334
if (!other || this.constructor != other.constructor) {
335
return false;
336
}
337
338
var fields = this.getDescriptor().getFields();
339
for (var i = 0; i < fields.length; i++) {
340
var field = fields[i];
341
var tag = field.getTag();
342
if (this.has$Value(tag) != other.has$Value(tag)) {
343
return false;
344
}
345
346
if (this.has$Value(tag)) {
347
var isComposite = field.isCompositeType();
348
349
var fieldsEqual = function(value1, value2) {
350
return isComposite ? value1.equals(value2) : value1 == value2;
351
};
352
353
var thisValue = this.getValueForTag_(tag);
354
var otherValue = other.getValueForTag_(tag);
355
356
if (field.isRepeated()) {
357
// In this case thisValue and otherValue are arrays.
358
if (thisValue.length != otherValue.length) {
359
return false;
360
}
361
for (var j = 0; j < thisValue.length; j++) {
362
if (!fieldsEqual(thisValue[j], otherValue[j])) {
363
return false;
364
}
365
}
366
} else if (!fieldsEqual(thisValue, otherValue)) {
367
return false;
368
}
369
}
370
}
371
372
return true;
373
};
374
375
376
/**
377
* Recursively copies the known fields from the given message to this message.
378
* Removes the fields which are not present in the source message.
379
* @param {!goog.proto2.Message} message The source message.
380
*/
381
goog.proto2.Message.prototype.copyFrom = function(message) {
382
goog.asserts.assert(
383
this.constructor == message.constructor,
384
'The source message must have the same type.');
385
386
if (this != message) {
387
this.values_ = {};
388
if (this.deserializedFields_) {
389
this.deserializedFields_ = {};
390
}
391
this.mergeFrom(message);
392
}
393
};
394
395
396
/**
397
* Merges the given message into this message.
398
*
399
* Singular fields will be overwritten, except for embedded messages which will
400
* be merged. Repeated fields will be concatenated.
401
* @param {!goog.proto2.Message} message The source message.
402
*/
403
goog.proto2.Message.prototype.mergeFrom = function(message) {
404
goog.asserts.assert(
405
this.constructor == message.constructor,
406
'The source message must have the same type.');
407
var fields = this.getDescriptor().getFields();
408
409
for (var i = 0; i < fields.length; i++) {
410
var field = fields[i];
411
var tag = field.getTag();
412
if (message.has$Value(tag)) {
413
if (this.deserializedFields_) {
414
delete this.deserializedFields_[field.getTag()];
415
}
416
417
var isComposite = field.isCompositeType();
418
if (field.isRepeated()) {
419
var values = message.array$Values(tag);
420
for (var j = 0; j < values.length; j++) {
421
this.add$Value(tag, isComposite ? values[j].clone() : values[j]);
422
}
423
} else {
424
var value = message.getValueForTag_(tag);
425
if (isComposite) {
426
var child = this.getValueForTag_(tag);
427
if (child) {
428
child.mergeFrom(value);
429
} else {
430
this.set$Value(tag, value.clone());
431
}
432
} else {
433
this.set$Value(tag, value);
434
}
435
}
436
}
437
}
438
};
439
440
441
/**
442
* @return {!goog.proto2.Message} Recursive clone of the message only including
443
* the known fields.
444
*/
445
goog.proto2.Message.prototype.clone = function() {
446
/** @type {!goog.proto2.Message} */
447
var clone = new this.constructor;
448
clone.copyFrom(this);
449
return clone;
450
};
451
452
453
/**
454
* Fills in the protocol buffer with default values. Any fields that are
455
* already set will not be overridden.
456
* @param {boolean} simpleFieldsToo If true, all fields will be initialized;
457
* if false, only the nested messages and groups.
458
*/
459
goog.proto2.Message.prototype.initDefaults = function(simpleFieldsToo) {
460
var fields = this.getDescriptor().getFields();
461
for (var i = 0; i < fields.length; i++) {
462
var field = fields[i];
463
var tag = field.getTag();
464
var isComposite = field.isCompositeType();
465
466
// Initialize missing fields.
467
if (!this.has$Value(tag) && !field.isRepeated()) {
468
if (isComposite) {
469
this.values_[tag] = new /** @type {Function} */ (field.getNativeType());
470
} else if (simpleFieldsToo) {
471
this.values_[tag] = field.getDefaultValue();
472
}
473
}
474
475
// Fill in the existing composite fields recursively.
476
if (isComposite) {
477
if (field.isRepeated()) {
478
var values = this.array$Values(tag);
479
for (var j = 0; j < values.length; j++) {
480
values[j].initDefaults(simpleFieldsToo);
481
}
482
} else {
483
this.get$Value(tag).initDefaults(simpleFieldsToo);
484
}
485
}
486
}
487
};
488
489
490
/**
491
* Returns the whether or not the field indicated by the given tag
492
* has a value.
493
*
494
* GENERATED CODE USE ONLY. Basis of the has{Field} methods.
495
*
496
* @param {number} tag The tag.
497
*
498
* @return {boolean} Whether the message has a value for the field.
499
*/
500
goog.proto2.Message.prototype.has$Value = function(tag) {
501
return this.values_[tag] != null;
502
};
503
504
505
/**
506
* Returns the value for the given tag number. If a lazy deserializer is
507
* instantiated, lazily deserializes the field if required before returning the
508
* value.
509
*
510
* @param {number} tag The tag number.
511
* @return {?} The corresponding value, if any.
512
* @private
513
*/
514
goog.proto2.Message.prototype.getValueForTag_ = function(tag) {
515
// Retrieve the current value, which may still be serialized.
516
var value = this.values_[tag];
517
if (!goog.isDefAndNotNull(value)) {
518
return null;
519
}
520
521
// If we have a lazy deserializer, then ensure that the field is
522
// properly deserialized.
523
if (this.lazyDeserializer_) {
524
// If the tag is not deserialized, then we must do so now. Deserialize
525
// the field's value via the deserializer.
526
if (!(tag in /** @type {!Object} */ (this.deserializedFields_))) {
527
var deserializedValue = this.lazyDeserializer_.deserializeField(
528
this, this.fields_[tag], value);
529
this.deserializedFields_[tag] = deserializedValue;
530
return deserializedValue;
531
}
532
533
return this.deserializedFields_[tag];
534
}
535
536
// Otherwise, just return the value.
537
return value;
538
};
539
540
541
/**
542
* Gets the value at the field indicated by the given tag.
543
*
544
* GENERATED CODE USE ONLY. Basis of the get{Field} methods.
545
*
546
* @param {number} tag The field's tag index.
547
* @param {number=} opt_index If the field is a repeated field, the index
548
* at which to get the value.
549
*
550
* @return {?} The value found or null for none.
551
* @protected
552
*/
553
goog.proto2.Message.prototype.get$Value = function(tag, opt_index) {
554
var value = this.getValueForTag_(tag);
555
556
if (this.fields_[tag].isRepeated()) {
557
var index = opt_index || 0;
558
goog.asserts.assert(
559
index >= 0 && index < value.length,
560
'Given index %s is out of bounds. Repeated field length: %s', index,
561
value.length);
562
return value[index];
563
}
564
565
return value;
566
};
567
568
569
/**
570
* Gets the value at the field indicated by the given tag or the default value
571
* if none.
572
*
573
* GENERATED CODE USE ONLY. Basis of the get{Field} methods.
574
*
575
* @param {number} tag The field's tag index.
576
* @param {number=} opt_index If the field is a repeated field, the index
577
* at which to get the value.
578
*
579
* @return {?} The value found or the default value if none set.
580
* @protected
581
*/
582
goog.proto2.Message.prototype.get$ValueOrDefault = function(tag, opt_index) {
583
if (!this.has$Value(tag)) {
584
// Return the default value.
585
var field = this.fields_[tag];
586
return field.getDefaultValue();
587
}
588
589
return this.get$Value(tag, opt_index);
590
};
591
592
593
/**
594
* Gets the values at the field indicated by the given tag.
595
*
596
* GENERATED CODE USE ONLY. Basis of the {field}Array methods.
597
*
598
* @param {number} tag The field's tag index.
599
*
600
* @return {!Array<?>} The values found. If none, returns an empty array.
601
* @protected
602
*/
603
goog.proto2.Message.prototype.array$Values = function(tag) {
604
var value = this.getValueForTag_(tag);
605
return value || [];
606
};
607
608
609
/**
610
* Returns the number of values stored in the field by the given tag.
611
*
612
* GENERATED CODE USE ONLY. Basis of the {field}Count methods.
613
*
614
* @param {number} tag The tag.
615
*
616
* @return {number} The number of values.
617
* @protected
618
*/
619
goog.proto2.Message.prototype.count$Values = function(tag) {
620
var field = this.fields_[tag];
621
if (field.isRepeated()) {
622
return this.has$Value(tag) ? this.values_[tag].length : 0;
623
} else {
624
return this.has$Value(tag) ? 1 : 0;
625
}
626
};
627
628
629
/**
630
* Sets the value of the *non-repeating* field indicated by the given tag.
631
*
632
* GENERATED CODE USE ONLY. Basis of the set{Field} methods.
633
*
634
* @param {number} tag The field's tag index.
635
* @param {*} value The field's value.
636
* @protected
637
*/
638
goog.proto2.Message.prototype.set$Value = function(tag, value) {
639
if (goog.asserts.ENABLE_ASSERTS) {
640
var field = this.fields_[tag];
641
this.checkFieldType_(field, value);
642
}
643
644
this.values_[tag] = value;
645
if (this.deserializedFields_) {
646
this.deserializedFields_[tag] = value;
647
}
648
};
649
650
651
/**
652
* Adds the value to the *repeating* field indicated by the given tag.
653
*
654
* GENERATED CODE USE ONLY. Basis of the add{Field} methods.
655
*
656
* @param {number} tag The field's tag index.
657
* @param {*} value The value to add.
658
* @protected
659
*/
660
goog.proto2.Message.prototype.add$Value = function(tag, value) {
661
if (goog.asserts.ENABLE_ASSERTS) {
662
var field = this.fields_[tag];
663
this.checkFieldType_(field, value);
664
}
665
666
if (!this.values_[tag]) {
667
this.values_[tag] = [];
668
}
669
670
this.values_[tag].push(value);
671
if (this.deserializedFields_) {
672
delete this.deserializedFields_[tag];
673
}
674
};
675
676
677
/**
678
* Ensures that the value being assigned to the given field
679
* is valid.
680
*
681
* @param {!goog.proto2.FieldDescriptor} field The field being assigned.
682
* @param {*} value The value being assigned.
683
* @private
684
*/
685
goog.proto2.Message.prototype.checkFieldType_ = function(field, value) {
686
if (field.getFieldType() == goog.proto2.FieldDescriptor.FieldType.ENUM) {
687
goog.asserts.assertNumber(value);
688
} else {
689
goog.asserts.assert(Object(value).constructor == field.getNativeType());
690
}
691
};
692
693
694
/**
695
* Clears the field specified by tag.
696
*
697
* GENERATED CODE USE ONLY. Basis of the clear{Field} methods.
698
*
699
* @param {number} tag The tag of the field to clear.
700
* @protected
701
*/
702
goog.proto2.Message.prototype.clear$Field = function(tag) {
703
delete this.values_[tag];
704
if (this.deserializedFields_) {
705
delete this.deserializedFields_[tag];
706
}
707
};
708
709
710
/**
711
* Creates the metadata descriptor representing the definition of this message.
712
*
713
* @param {function(new:goog.proto2.Message)} messageType Constructor for the
714
* message type to which this metadata applies.
715
* @param {!Object} metadataObj The object containing the metadata.
716
* @return {!goog.proto2.Descriptor} The new descriptor.
717
*/
718
goog.proto2.Message.createDescriptor = function(messageType, metadataObj) {
719
var fields = [];
720
var descriptorInfo = metadataObj[0];
721
722
for (var key in metadataObj) {
723
if (key != 0) {
724
// Create the field descriptor.
725
fields.push(
726
new goog.proto2.FieldDescriptor(messageType, key, metadataObj[key]));
727
}
728
}
729
730
return new goog.proto2.Descriptor(messageType, descriptorInfo, fields);
731
};
732
733