1ffe3c632Sopenharmony_ci// Protocol Buffers - Google's data interchange format
2ffe3c632Sopenharmony_ci// Copyright 2008 Google Inc.  All rights reserved.
3ffe3c632Sopenharmony_ci// https://developers.google.com/protocol-buffers/
4ffe3c632Sopenharmony_ci//
5ffe3c632Sopenharmony_ci// Redistribution and use in source and binary forms, with or without
6ffe3c632Sopenharmony_ci// modification, are permitted provided that the following conditions are
7ffe3c632Sopenharmony_ci// met:
8ffe3c632Sopenharmony_ci//
9ffe3c632Sopenharmony_ci//     * Redistributions of source code must retain the above copyright
10ffe3c632Sopenharmony_ci// notice, this list of conditions and the following disclaimer.
11ffe3c632Sopenharmony_ci//     * Redistributions in binary form must reproduce the above
12ffe3c632Sopenharmony_ci// copyright notice, this list of conditions and the following disclaimer
13ffe3c632Sopenharmony_ci// in the documentation and/or other materials provided with the
14ffe3c632Sopenharmony_ci// distribution.
15ffe3c632Sopenharmony_ci//     * Neither the name of Google Inc. nor the names of its
16ffe3c632Sopenharmony_ci// contributors may be used to endorse or promote products derived from
17ffe3c632Sopenharmony_ci// this software without specific prior written permission.
18ffe3c632Sopenharmony_ci//
19ffe3c632Sopenharmony_ci// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20ffe3c632Sopenharmony_ci// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21ffe3c632Sopenharmony_ci// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22ffe3c632Sopenharmony_ci// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23ffe3c632Sopenharmony_ci// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24ffe3c632Sopenharmony_ci// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25ffe3c632Sopenharmony_ci// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26ffe3c632Sopenharmony_ci// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27ffe3c632Sopenharmony_ci// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28ffe3c632Sopenharmony_ci// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29ffe3c632Sopenharmony_ci// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30ffe3c632Sopenharmony_ci
31ffe3c632Sopenharmony_ci/**
32ffe3c632Sopenharmony_ci * @fileoverview Definition of jspb.Message.
33ffe3c632Sopenharmony_ci *
34ffe3c632Sopenharmony_ci * @author mwr@google.com (Mark Rawling)
35ffe3c632Sopenharmony_ci */
36ffe3c632Sopenharmony_ci
37ffe3c632Sopenharmony_cigoog.provide('jspb.ExtensionFieldBinaryInfo');
38ffe3c632Sopenharmony_cigoog.provide('jspb.ExtensionFieldInfo');
39ffe3c632Sopenharmony_cigoog.provide('jspb.Message');
40ffe3c632Sopenharmony_ci
41ffe3c632Sopenharmony_cigoog.require('goog.array');
42ffe3c632Sopenharmony_cigoog.require('goog.asserts');
43ffe3c632Sopenharmony_cigoog.require('goog.crypt.base64');
44ffe3c632Sopenharmony_cigoog.require('jspb.BinaryReader');
45ffe3c632Sopenharmony_cigoog.require('jspb.Map');
46ffe3c632Sopenharmony_ci
47ffe3c632Sopenharmony_ci
48ffe3c632Sopenharmony_ci
49ffe3c632Sopenharmony_ci
50ffe3c632Sopenharmony_ci/**
51ffe3c632Sopenharmony_ci * Stores information for a single extension field.
52ffe3c632Sopenharmony_ci *
53ffe3c632Sopenharmony_ci * For example, an extension field defined like so:
54ffe3c632Sopenharmony_ci *
55ffe3c632Sopenharmony_ci *     extend BaseMessage {
56ffe3c632Sopenharmony_ci *       optional MyMessage my_field = 123;
57ffe3c632Sopenharmony_ci *     }
58ffe3c632Sopenharmony_ci *
59ffe3c632Sopenharmony_ci * will result in an ExtensionFieldInfo object with these properties:
60ffe3c632Sopenharmony_ci *
61ffe3c632Sopenharmony_ci *     {
62ffe3c632Sopenharmony_ci *       fieldIndex: 123,
63ffe3c632Sopenharmony_ci *       fieldName: {my_field_renamed: 0},
64ffe3c632Sopenharmony_ci *       ctor: proto.example.MyMessage,
65ffe3c632Sopenharmony_ci *       toObjectFn: proto.example.MyMessage.toObject,
66ffe3c632Sopenharmony_ci *       isRepeated: 0
67ffe3c632Sopenharmony_ci *     }
68ffe3c632Sopenharmony_ci *
69ffe3c632Sopenharmony_ci * We include `toObjectFn` to allow the JSCompiler to perform dead-code removal
70ffe3c632Sopenharmony_ci * on unused toObject() methods.
71ffe3c632Sopenharmony_ci *
72ffe3c632Sopenharmony_ci * If an extension field is primitive, ctor and toObjectFn will be null.
73ffe3c632Sopenharmony_ci * isRepeated should be 0 or 1.
74ffe3c632Sopenharmony_ci *
75ffe3c632Sopenharmony_ci * binary{Reader,Writer}Fn and (if message type) binaryMessageSerializeFn are
76ffe3c632Sopenharmony_ci * always provided. binaryReaderFn and binaryWriterFn are references to the
77ffe3c632Sopenharmony_ci * appropriate methods on BinaryReader/BinaryWriter to read/write the value of
78ffe3c632Sopenharmony_ci * this extension, and binaryMessageSerializeFn is a reference to the message
79ffe3c632Sopenharmony_ci * class's .serializeBinary method, if available.
80ffe3c632Sopenharmony_ci *
81ffe3c632Sopenharmony_ci * @param {number} fieldNumber
82ffe3c632Sopenharmony_ci * @param {Object} fieldName This has the extension field name as a property.
83ffe3c632Sopenharmony_ci * @param {?function(new: jspb.Message, Array=)} ctor
84ffe3c632Sopenharmony_ci * @param {?function((boolean|undefined),!jspb.Message):!Object} toObjectFn
85ffe3c632Sopenharmony_ci * @param {number} isRepeated
86ffe3c632Sopenharmony_ci * @constructor
87ffe3c632Sopenharmony_ci * @struct
88ffe3c632Sopenharmony_ci * @template T
89ffe3c632Sopenharmony_ci */
90ffe3c632Sopenharmony_cijspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn,
91ffe3c632Sopenharmony_ci    isRepeated) {
92ffe3c632Sopenharmony_ci  /** @const */
93ffe3c632Sopenharmony_ci  this.fieldIndex = fieldNumber;
94ffe3c632Sopenharmony_ci  /** @const */
95ffe3c632Sopenharmony_ci  this.fieldName = fieldName;
96ffe3c632Sopenharmony_ci  /** @const */
97ffe3c632Sopenharmony_ci  this.ctor = ctor;
98ffe3c632Sopenharmony_ci  /** @const */
99ffe3c632Sopenharmony_ci  this.toObjectFn = toObjectFn;
100ffe3c632Sopenharmony_ci  /** @const */
101ffe3c632Sopenharmony_ci  this.isRepeated = isRepeated;
102ffe3c632Sopenharmony_ci};
103ffe3c632Sopenharmony_ci
104ffe3c632Sopenharmony_ci/**
105ffe3c632Sopenharmony_ci * Stores binary-related information for a single extension field.
106ffe3c632Sopenharmony_ci * @param {!jspb.ExtensionFieldInfo<T>} fieldInfo
107ffe3c632Sopenharmony_ci * @param {function(this:jspb.BinaryReader,number,?,?)} binaryReaderFn
108ffe3c632Sopenharmony_ci * @param {function(this:jspb.BinaryWriter,number,?)
109ffe3c632Sopenharmony_ci *        |function(this:jspb.BinaryWriter,number,?,?,?,?,?)} binaryWriterFn
110ffe3c632Sopenharmony_ci * @param {function(?,?)=} opt_binaryMessageSerializeFn
111ffe3c632Sopenharmony_ci * @param {function(?,?)=} opt_binaryMessageDeserializeFn
112ffe3c632Sopenharmony_ci * @param {boolean=} opt_isPacked
113ffe3c632Sopenharmony_ci * @constructor
114ffe3c632Sopenharmony_ci * @struct
115ffe3c632Sopenharmony_ci * @template T
116ffe3c632Sopenharmony_ci */
117ffe3c632Sopenharmony_cijspb.ExtensionFieldBinaryInfo = function(fieldInfo, binaryReaderFn, binaryWriterFn,
118ffe3c632Sopenharmony_ci    opt_binaryMessageSerializeFn, opt_binaryMessageDeserializeFn, opt_isPacked) {
119ffe3c632Sopenharmony_ci  /** @const */
120ffe3c632Sopenharmony_ci  this.fieldInfo = fieldInfo;
121ffe3c632Sopenharmony_ci  /** @const */
122ffe3c632Sopenharmony_ci  this.binaryReaderFn = binaryReaderFn;
123ffe3c632Sopenharmony_ci  /** @const */
124ffe3c632Sopenharmony_ci  this.binaryWriterFn = binaryWriterFn;
125ffe3c632Sopenharmony_ci  /** @const */
126ffe3c632Sopenharmony_ci  this.binaryMessageSerializeFn = opt_binaryMessageSerializeFn;
127ffe3c632Sopenharmony_ci  /** @const */
128ffe3c632Sopenharmony_ci  this.binaryMessageDeserializeFn = opt_binaryMessageDeserializeFn;
129ffe3c632Sopenharmony_ci  /** @const */
130ffe3c632Sopenharmony_ci  this.isPacked = opt_isPacked;
131ffe3c632Sopenharmony_ci};
132ffe3c632Sopenharmony_ci
133ffe3c632Sopenharmony_ci/**
134ffe3c632Sopenharmony_ci * @return {boolean} Does this field represent a sub Message?
135ffe3c632Sopenharmony_ci */
136ffe3c632Sopenharmony_cijspb.ExtensionFieldInfo.prototype.isMessageType = function() {
137ffe3c632Sopenharmony_ci  return !!this.ctor;
138ffe3c632Sopenharmony_ci};
139ffe3c632Sopenharmony_ci
140ffe3c632Sopenharmony_ci
141ffe3c632Sopenharmony_ci/**
142ffe3c632Sopenharmony_ci * Base class for all JsPb messages.
143ffe3c632Sopenharmony_ci *
144ffe3c632Sopenharmony_ci * Several common methods (toObject, serializeBinary, in particular) are not
145ffe3c632Sopenharmony_ci * defined on the prototype to encourage code patterns that minimize code bloat
146ffe3c632Sopenharmony_ci * due to otherwise unused code on all protos contained in the project.
147ffe3c632Sopenharmony_ci *
148ffe3c632Sopenharmony_ci * If you want to call these methods on a generic message, either
149ffe3c632Sopenharmony_ci * pass in your instance of method as a parameter:
150ffe3c632Sopenharmony_ci *     someFunction(instanceOfKnownProto,
151ffe3c632Sopenharmony_ci *                  KnownProtoClass.prototype.serializeBinary);
152ffe3c632Sopenharmony_ci * or use a lambda that knows the type:
153ffe3c632Sopenharmony_ci *     someFunction(()=>instanceOfKnownProto.serializeBinary());
154ffe3c632Sopenharmony_ci * or, if you don't care about code size, just suppress the
155ffe3c632Sopenharmony_ci *     WARNING - Property serializeBinary never defined on jspb.Message
156ffe3c632Sopenharmony_ci * and call it the intuitive way.
157ffe3c632Sopenharmony_ci *
158ffe3c632Sopenharmony_ci * @constructor
159ffe3c632Sopenharmony_ci * @struct
160ffe3c632Sopenharmony_ci */
161ffe3c632Sopenharmony_cijspb.Message = function() {
162ffe3c632Sopenharmony_ci};
163ffe3c632Sopenharmony_ci
164ffe3c632Sopenharmony_ci
165ffe3c632Sopenharmony_ci/**
166ffe3c632Sopenharmony_ci * @define {boolean} Whether to generate toObject methods for objects. Turn
167ffe3c632Sopenharmony_ci *     this off, if you do not want toObject to be ever used in your project.
168ffe3c632Sopenharmony_ci *     When turning off this flag, consider adding a conformance test that bans
169ffe3c632Sopenharmony_ci *     calling toObject. Enabling this will disable the JSCompiler's ability to
170ffe3c632Sopenharmony_ci *     dead code eliminate fields used in protocol buffers that are never used
171ffe3c632Sopenharmony_ci *     in an application.
172ffe3c632Sopenharmony_ci */
173ffe3c632Sopenharmony_cijspb.Message.GENERATE_TO_OBJECT =
174ffe3c632Sopenharmony_ci    goog.define('jspb.Message.GENERATE_TO_OBJECT', true);
175ffe3c632Sopenharmony_ci
176ffe3c632Sopenharmony_ci
177ffe3c632Sopenharmony_ci/**
178ffe3c632Sopenharmony_ci * @define {boolean} Whether to generate fromObject methods for objects. Turn
179ffe3c632Sopenharmony_ci *     this off, if you do not want fromObject to be ever used in your project.
180ffe3c632Sopenharmony_ci *     When turning off this flag, consider adding a conformance test that bans
181ffe3c632Sopenharmony_ci *     calling fromObject. Enabling this might disable the JSCompiler's ability
182ffe3c632Sopenharmony_ci *     to dead code eliminate fields used in protocol buffers that are never
183ffe3c632Sopenharmony_ci *     used in an application.
184ffe3c632Sopenharmony_ci *     By default this is enabled for test code only.
185ffe3c632Sopenharmony_ci */
186ffe3c632Sopenharmony_cijspb.Message.GENERATE_FROM_OBJECT = goog.define(
187ffe3c632Sopenharmony_ci    'jspb.Message.GENERATE_FROM_OBJECT', !goog.DISALLOW_TEST_ONLY_CODE);
188ffe3c632Sopenharmony_ci
189ffe3c632Sopenharmony_ci
190ffe3c632Sopenharmony_ci/**
191ffe3c632Sopenharmony_ci * @define {boolean} Whether to generate toString methods for objects. Turn
192ffe3c632Sopenharmony_ci *     this off if you do not use toString in your project and want to trim it
193ffe3c632Sopenharmony_ci *     from the compiled JS.
194ffe3c632Sopenharmony_ci */
195ffe3c632Sopenharmony_cijspb.Message.GENERATE_TO_STRING =
196ffe3c632Sopenharmony_ci    goog.define('jspb.Message.GENERATE_TO_STRING', true);
197ffe3c632Sopenharmony_ci
198ffe3c632Sopenharmony_ci
199ffe3c632Sopenharmony_ci/**
200ffe3c632Sopenharmony_ci * @define {boolean} Whether arrays passed to initialize() can be assumed to be
201ffe3c632Sopenharmony_ci *     local (e.g. not from another iframe) and thus safely classified with
202ffe3c632Sopenharmony_ci *     instanceof Array.
203ffe3c632Sopenharmony_ci */
204ffe3c632Sopenharmony_cijspb.Message.ASSUME_LOCAL_ARRAYS =
205ffe3c632Sopenharmony_ci    goog.define('jspb.Message.ASSUME_LOCAL_ARRAYS', false);
206ffe3c632Sopenharmony_ci
207ffe3c632Sopenharmony_ci
208ffe3c632Sopenharmony_ci// TODO(jakubvrana): Turn this off by default.
209ffe3c632Sopenharmony_ci/**
210ffe3c632Sopenharmony_ci * @define {boolean} Disabling the serialization of empty trailing fields
211ffe3c632Sopenharmony_ci *     reduces the size of serialized protos. The price is an extra iteration of
212ffe3c632Sopenharmony_ci *     the proto before serialization. This is enabled by default to be
213ffe3c632Sopenharmony_ci *     backwards compatible. Projects are advised to turn this flag always off.
214ffe3c632Sopenharmony_ci */
215ffe3c632Sopenharmony_cijspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS =
216ffe3c632Sopenharmony_ci    goog.define('jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS', true);
217ffe3c632Sopenharmony_ci
218ffe3c632Sopenharmony_ci
219ffe3c632Sopenharmony_ci/**
220ffe3c632Sopenharmony_ci * Does this JavaScript environment support Uint8Aray typed arrays?
221ffe3c632Sopenharmony_ci * @type {boolean}
222ffe3c632Sopenharmony_ci * @private
223ffe3c632Sopenharmony_ci */
224ffe3c632Sopenharmony_cijspb.Message.SUPPORTS_UINT8ARRAY_ = (typeof Uint8Array == 'function');
225ffe3c632Sopenharmony_ci
226ffe3c632Sopenharmony_ci
227ffe3c632Sopenharmony_ci/**
228ffe3c632Sopenharmony_ci * The internal data array.
229ffe3c632Sopenharmony_ci * @type {!Array}
230ffe3c632Sopenharmony_ci * @protected
231ffe3c632Sopenharmony_ci */
232ffe3c632Sopenharmony_cijspb.Message.prototype.array;
233ffe3c632Sopenharmony_ci
234ffe3c632Sopenharmony_ci
235ffe3c632Sopenharmony_ci/**
236ffe3c632Sopenharmony_ci * Wrappers are the constructed instances of message-type fields. They are built
237ffe3c632Sopenharmony_ci * on demand from the raw array data. Includes message fields, repeated message
238ffe3c632Sopenharmony_ci * fields and extension message fields. Indexed by field number.
239ffe3c632Sopenharmony_ci * @type {Object}
240ffe3c632Sopenharmony_ci * @private
241ffe3c632Sopenharmony_ci */
242ffe3c632Sopenharmony_cijspb.Message.prototype.wrappers_;
243ffe3c632Sopenharmony_ci
244ffe3c632Sopenharmony_ci
245ffe3c632Sopenharmony_ci/**
246ffe3c632Sopenharmony_ci * The object that contains extension fields, if any. This is an object that
247ffe3c632Sopenharmony_ci * maps from a proto field number to the field's value.
248ffe3c632Sopenharmony_ci * @type {Object}
249ffe3c632Sopenharmony_ci * @private
250ffe3c632Sopenharmony_ci */
251ffe3c632Sopenharmony_cijspb.Message.prototype.extensionObject_;
252ffe3c632Sopenharmony_ci
253ffe3c632Sopenharmony_ci
254ffe3c632Sopenharmony_ci/**
255ffe3c632Sopenharmony_ci * Non-extension fields with a field number at or above the pivot are
256ffe3c632Sopenharmony_ci * stored in the extension object (in addition to all extension fields).
257ffe3c632Sopenharmony_ci * @type {number}
258ffe3c632Sopenharmony_ci * @private
259ffe3c632Sopenharmony_ci */
260ffe3c632Sopenharmony_cijspb.Message.prototype.pivot_;
261ffe3c632Sopenharmony_ci
262ffe3c632Sopenharmony_ci
263ffe3c632Sopenharmony_ci/**
264ffe3c632Sopenharmony_ci * The JsPb message_id of this proto.
265ffe3c632Sopenharmony_ci * @type {string|undefined} the message id or undefined if this message
266ffe3c632Sopenharmony_ci *     has no id.
267ffe3c632Sopenharmony_ci * @private
268ffe3c632Sopenharmony_ci */
269ffe3c632Sopenharmony_cijspb.Message.prototype.messageId_;
270ffe3c632Sopenharmony_ci
271ffe3c632Sopenharmony_ci
272ffe3c632Sopenharmony_ci/**
273ffe3c632Sopenharmony_ci * Repeated fields that have been converted to their proper type. This is used
274ffe3c632Sopenharmony_ci * for numbers stored as strings (typically "NaN", "Infinity" and "-Infinity")
275ffe3c632Sopenharmony_ci * and for booleans stored as numbers (0 or 1).
276ffe3c632Sopenharmony_ci * @private {!Object<number,boolean>|undefined}
277ffe3c632Sopenharmony_ci */
278ffe3c632Sopenharmony_cijspb.Message.prototype.convertedPrimitiveFields_;
279ffe3c632Sopenharmony_ci
280ffe3c632Sopenharmony_ci/**
281ffe3c632Sopenharmony_ci * Repeated fields numbers.
282ffe3c632Sopenharmony_ci * @protected {?Array<number>|undefined}
283ffe3c632Sopenharmony_ci */
284ffe3c632Sopenharmony_cijspb.Message.prototype.repeatedFields;
285ffe3c632Sopenharmony_ci
286ffe3c632Sopenharmony_ci
287ffe3c632Sopenharmony_ci
288ffe3c632Sopenharmony_ci/**
289ffe3c632Sopenharmony_ci * Returns the JsPb message_id of this proto.
290ffe3c632Sopenharmony_ci * @return {string|undefined} the message id or undefined if this message
291ffe3c632Sopenharmony_ci *     has no id.
292ffe3c632Sopenharmony_ci */
293ffe3c632Sopenharmony_cijspb.Message.prototype.getJsPbMessageId = function() {
294ffe3c632Sopenharmony_ci  return this.messageId_;
295ffe3c632Sopenharmony_ci};
296ffe3c632Sopenharmony_ci
297ffe3c632Sopenharmony_ci
298ffe3c632Sopenharmony_ci/**
299ffe3c632Sopenharmony_ci * An offset applied to lookups into this.array to account for the presence or
300ffe3c632Sopenharmony_ci * absence of a messageId at position 0. For response messages, this will be 0.
301ffe3c632Sopenharmony_ci * Otherwise, it will be -1 so that the first array position is not wasted.
302ffe3c632Sopenharmony_ci * @type {number}
303ffe3c632Sopenharmony_ci * @private
304ffe3c632Sopenharmony_ci */
305ffe3c632Sopenharmony_cijspb.Message.prototype.arrayIndexOffset_;
306ffe3c632Sopenharmony_ci
307ffe3c632Sopenharmony_ci
308ffe3c632Sopenharmony_ci/**
309ffe3c632Sopenharmony_ci * Returns the index into msg.array at which the proto field with tag number
310ffe3c632Sopenharmony_ci * fieldNumber will be located.
311ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg Message for which we're calculating an index.
312ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
313ffe3c632Sopenharmony_ci * @return {number} The index.
314ffe3c632Sopenharmony_ci * @private
315ffe3c632Sopenharmony_ci */
316ffe3c632Sopenharmony_cijspb.Message.getIndex_ = function(msg, fieldNumber) {
317ffe3c632Sopenharmony_ci  return fieldNumber + msg.arrayIndexOffset_;
318ffe3c632Sopenharmony_ci};
319ffe3c632Sopenharmony_ci
320ffe3c632Sopenharmony_ci// This is only here to ensure we are not back sliding on ES6 requirements for
321ffe3c632Sopenharmony_ci// protos in g3.
322ffe3c632Sopenharmony_cijspb.Message.hiddenES6Property_ = class {};
323ffe3c632Sopenharmony_ci
324ffe3c632Sopenharmony_ci
325ffe3c632Sopenharmony_ci/**
326ffe3c632Sopenharmony_ci * Returns the tag number based on the index in msg.array.
327ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg Message for which we're calculating an index.
328ffe3c632Sopenharmony_ci * @param {number} index The tag number.
329ffe3c632Sopenharmony_ci * @return {number} The field number.
330ffe3c632Sopenharmony_ci * @private
331ffe3c632Sopenharmony_ci */
332ffe3c632Sopenharmony_cijspb.Message.getFieldNumber_ = function(msg, index) {
333ffe3c632Sopenharmony_ci  return index - msg.arrayIndexOffset_;
334ffe3c632Sopenharmony_ci};
335ffe3c632Sopenharmony_ci
336ffe3c632Sopenharmony_ci
337ffe3c632Sopenharmony_ci/**
338ffe3c632Sopenharmony_ci * Initializes a JsPb Message.
339ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg The JsPb proto to modify.
340ffe3c632Sopenharmony_ci * @param {Array|undefined} data An initial data array.
341ffe3c632Sopenharmony_ci * @param {string|number} messageId For response messages, the message id or ''
342ffe3c632Sopenharmony_ci *     if no message id is specified. For non-response messages, 0.
343ffe3c632Sopenharmony_ci * @param {number} suggestedPivot The field number at which to start putting
344ffe3c632Sopenharmony_ci *     fields into the extension object. This is only used if data does not
345ffe3c632Sopenharmony_ci *     contain an extension object already. -1 if no extension object is
346ffe3c632Sopenharmony_ci *     required for this message type.
347ffe3c632Sopenharmony_ci * @param {Array<number>} repeatedFields The message's repeated fields.
348ffe3c632Sopenharmony_ci * @param {Array<!Array<number>>=} opt_oneofFields The fields belonging to
349ffe3c632Sopenharmony_ci *     each of the message's oneof unions.
350ffe3c632Sopenharmony_ci * @protected
351ffe3c632Sopenharmony_ci */
352ffe3c632Sopenharmony_cijspb.Message.initialize = function(
353ffe3c632Sopenharmony_ci    msg, data, messageId, suggestedPivot, repeatedFields, opt_oneofFields) {
354ffe3c632Sopenharmony_ci  msg.wrappers_ = null;
355ffe3c632Sopenharmony_ci  if (!data) {
356ffe3c632Sopenharmony_ci    data = messageId ? [messageId] : [];
357ffe3c632Sopenharmony_ci  }
358ffe3c632Sopenharmony_ci  msg.messageId_ = messageId ? String(messageId) : undefined;
359ffe3c632Sopenharmony_ci  // If the messageId is 0, this message is not a response message, so we shift
360ffe3c632Sopenharmony_ci  // array indices down by 1 so as not to waste the first position in the array,
361ffe3c632Sopenharmony_ci  // which would otherwise go unused.
362ffe3c632Sopenharmony_ci  msg.arrayIndexOffset_ = messageId === 0 ? -1 : 0;
363ffe3c632Sopenharmony_ci  msg.array = data;
364ffe3c632Sopenharmony_ci  jspb.Message.initPivotAndExtensionObject_(msg, suggestedPivot);
365ffe3c632Sopenharmony_ci  msg.convertedPrimitiveFields_ = {};
366ffe3c632Sopenharmony_ci
367ffe3c632Sopenharmony_ci  if (!jspb.Message.SERIALIZE_EMPTY_TRAILING_FIELDS) {
368ffe3c632Sopenharmony_ci    // TODO(jakubvrana): This is same for all instances, move to prototype.
369ffe3c632Sopenharmony_ci    // TODO(jakubvrana): There are indexOf calls on this in serialization,
370ffe3c632Sopenharmony_ci    // consider switching to a set.
371ffe3c632Sopenharmony_ci    msg.repeatedFields = repeatedFields;
372ffe3c632Sopenharmony_ci  }
373ffe3c632Sopenharmony_ci
374ffe3c632Sopenharmony_ci  if (repeatedFields) {
375ffe3c632Sopenharmony_ci    for (var i = 0; i < repeatedFields.length; i++) {
376ffe3c632Sopenharmony_ci      var fieldNumber = repeatedFields[i];
377ffe3c632Sopenharmony_ci      if (fieldNumber < msg.pivot_) {
378ffe3c632Sopenharmony_ci        var index = jspb.Message.getIndex_(msg, fieldNumber);
379ffe3c632Sopenharmony_ci        msg.array[index] =
380ffe3c632Sopenharmony_ci            msg.array[index] || jspb.Message.EMPTY_LIST_SENTINEL_;
381ffe3c632Sopenharmony_ci      } else {
382ffe3c632Sopenharmony_ci        jspb.Message.maybeInitEmptyExtensionObject_(msg);
383ffe3c632Sopenharmony_ci        msg.extensionObject_[fieldNumber] = msg.extensionObject_[fieldNumber] ||
384ffe3c632Sopenharmony_ci            jspb.Message.EMPTY_LIST_SENTINEL_;
385ffe3c632Sopenharmony_ci      }
386ffe3c632Sopenharmony_ci    }
387ffe3c632Sopenharmony_ci  }
388ffe3c632Sopenharmony_ci
389ffe3c632Sopenharmony_ci  if (opt_oneofFields && opt_oneofFields.length) {
390ffe3c632Sopenharmony_ci    // Compute the oneof case for each union. This ensures only one value is
391ffe3c632Sopenharmony_ci    // set in the union.
392ffe3c632Sopenharmony_ci    for (var i = 0; i < opt_oneofFields.length; i++) {
393ffe3c632Sopenharmony_ci      jspb.Message.computeOneofCase(msg, opt_oneofFields[i]);
394ffe3c632Sopenharmony_ci    }
395ffe3c632Sopenharmony_ci  }
396ffe3c632Sopenharmony_ci};
397ffe3c632Sopenharmony_ci
398ffe3c632Sopenharmony_ci
399ffe3c632Sopenharmony_ci/**
400ffe3c632Sopenharmony_ci * Used to mark empty repeated fields. Serializes to null when serialized
401ffe3c632Sopenharmony_ci * to JSON.
402ffe3c632Sopenharmony_ci * When reading a repeated field readers must check the return value against
403ffe3c632Sopenharmony_ci * this value and return and replace it with a new empty array if it is
404ffe3c632Sopenharmony_ci * present.
405ffe3c632Sopenharmony_ci * @private @const {!Object}
406ffe3c632Sopenharmony_ci */
407ffe3c632Sopenharmony_cijspb.Message.EMPTY_LIST_SENTINEL_ = goog.DEBUG && Object.freeze ?
408ffe3c632Sopenharmony_ci    Object.freeze([]) :
409ffe3c632Sopenharmony_ci    [];
410ffe3c632Sopenharmony_ci
411ffe3c632Sopenharmony_ci
412ffe3c632Sopenharmony_ci/**
413ffe3c632Sopenharmony_ci * Returns true if the provided argument is an array.
414ffe3c632Sopenharmony_ci * @param {*} o The object to classify as array or not.
415ffe3c632Sopenharmony_ci * @return {boolean} True if the provided object is an array.
416ffe3c632Sopenharmony_ci * @private
417ffe3c632Sopenharmony_ci */
418ffe3c632Sopenharmony_cijspb.Message.isArray_ = function(o) {
419ffe3c632Sopenharmony_ci  return jspb.Message.ASSUME_LOCAL_ARRAYS ? o instanceof Array :
420ffe3c632Sopenharmony_ci                                            Array.isArray(o);
421ffe3c632Sopenharmony_ci};
422ffe3c632Sopenharmony_ci
423ffe3c632Sopenharmony_ci/**
424ffe3c632Sopenharmony_ci * Returns true if the provided argument is an extension object.
425ffe3c632Sopenharmony_ci * @param {*} o The object to classify as array or not.
426ffe3c632Sopenharmony_ci * @return {boolean} True if the provided object is an extension object.
427ffe3c632Sopenharmony_ci * @private
428ffe3c632Sopenharmony_ci */
429ffe3c632Sopenharmony_cijspb.Message.isExtensionObject_ = function(o) {
430ffe3c632Sopenharmony_ci  // Normal fields are never objects, so we can be sure that if we find an
431ffe3c632Sopenharmony_ci  // object here, then it's the extension object. However, we must ensure that
432ffe3c632Sopenharmony_ci  // the object is not an array, since arrays are valid field values (bytes
433ffe3c632Sopenharmony_ci  // fields can also be array).
434ffe3c632Sopenharmony_ci  // NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
435ffe3c632Sopenharmony_ci  // in Safari on iOS 8. See the description of CL/86511464 for details.
436ffe3c632Sopenharmony_ci  return (o !== null && typeof o == 'object' &&
437ffe3c632Sopenharmony_ci      !jspb.Message.isArray_(o) &&
438ffe3c632Sopenharmony_ci      !(jspb.Message.SUPPORTS_UINT8ARRAY_ && o instanceof Uint8Array));
439ffe3c632Sopenharmony_ci};
440ffe3c632Sopenharmony_ci
441ffe3c632Sopenharmony_ci
442ffe3c632Sopenharmony_ci/**
443ffe3c632Sopenharmony_ci * If the array contains an extension object in its last position, then the
444ffe3c632Sopenharmony_ci * object is kept in place and its position is used as the pivot.  If not,
445ffe3c632Sopenharmony_ci * decides the pivot of the message based on suggestedPivot without
446ffe3c632Sopenharmony_ci * materializing the extension object.
447ffe3c632Sopenharmony_ci *
448ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg The JsPb proto to modify.
449ffe3c632Sopenharmony_ci * @param {number} suggestedPivot See description for initialize().
450ffe3c632Sopenharmony_ci * @private
451ffe3c632Sopenharmony_ci */
452ffe3c632Sopenharmony_cijspb.Message.initPivotAndExtensionObject_ = function(msg, suggestedPivot) {
453ffe3c632Sopenharmony_ci  // There are 3 variants that need to be dealt with which are the
454ffe3c632Sopenharmony_ci  // combination of whether there exists an extension object (EO) and
455ffe3c632Sopenharmony_ci  // whether there is a suggested pivot (SP).
456ffe3c632Sopenharmony_ci  //
457ffe3c632Sopenharmony_ci  // EO,    ?    : pivot is the index of the EO
458ffe3c632Sopenharmony_ci  // no-EO, no-SP: pivot is MAX_INT
459ffe3c632Sopenharmony_ci  // no-EO, SP   : pivot is the max(lastindex + 1, SP)
460ffe3c632Sopenharmony_ci
461ffe3c632Sopenharmony_ci  var msgLength = msg.array.length;
462ffe3c632Sopenharmony_ci  var lastIndex = -1;
463ffe3c632Sopenharmony_ci  if (msgLength) {
464ffe3c632Sopenharmony_ci    lastIndex = msgLength - 1;
465ffe3c632Sopenharmony_ci    var obj = msg.array[lastIndex];
466ffe3c632Sopenharmony_ci    if (jspb.Message.isExtensionObject_(obj)) {
467ffe3c632Sopenharmony_ci      msg.pivot_ = jspb.Message.getFieldNumber_(msg, lastIndex);
468ffe3c632Sopenharmony_ci      msg.extensionObject_ = obj;
469ffe3c632Sopenharmony_ci      return;
470ffe3c632Sopenharmony_ci    }
471ffe3c632Sopenharmony_ci  }
472ffe3c632Sopenharmony_ci
473ffe3c632Sopenharmony_ci  if (suggestedPivot > -1) {
474ffe3c632Sopenharmony_ci    // If a extension object is not present, set the pivot value as being
475ffe3c632Sopenharmony_ci    // after the last value in the array to avoid overwriting values, etc.
476ffe3c632Sopenharmony_ci    msg.pivot_ = Math.max(
477ffe3c632Sopenharmony_ci        suggestedPivot, jspb.Message.getFieldNumber_(msg, lastIndex + 1));
478ffe3c632Sopenharmony_ci    // Avoid changing the shape of the proto with an empty extension object by
479ffe3c632Sopenharmony_ci    // deferring the materialization of the extension object until the first
480ffe3c632Sopenharmony_ci    // time a field set into it (may be due to getting a repeated proto field
481ffe3c632Sopenharmony_ci    // from it, in which case a new empty array is set into it at first).
482ffe3c632Sopenharmony_ci    msg.extensionObject_ = null;
483ffe3c632Sopenharmony_ci  } else {
484ffe3c632Sopenharmony_ci    // suggestedPivot is -1, which means that we don't have an extension object
485ffe3c632Sopenharmony_ci    // at all, in which case all fields are stored in the array.
486ffe3c632Sopenharmony_ci    msg.pivot_ = Number.MAX_VALUE;
487ffe3c632Sopenharmony_ci  }
488ffe3c632Sopenharmony_ci};
489ffe3c632Sopenharmony_ci
490ffe3c632Sopenharmony_ci
491ffe3c632Sopenharmony_ci/**
492ffe3c632Sopenharmony_ci * Creates an empty extensionObject_ if non exists.
493ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg The JsPb proto to modify.
494ffe3c632Sopenharmony_ci * @private
495ffe3c632Sopenharmony_ci */
496ffe3c632Sopenharmony_cijspb.Message.maybeInitEmptyExtensionObject_ = function(msg) {
497ffe3c632Sopenharmony_ci  var pivotIndex = jspb.Message.getIndex_(msg, msg.pivot_);
498ffe3c632Sopenharmony_ci  if (!msg.array[pivotIndex]) {
499ffe3c632Sopenharmony_ci    msg.extensionObject_ = msg.array[pivotIndex] = {};
500ffe3c632Sopenharmony_ci  }
501ffe3c632Sopenharmony_ci};
502ffe3c632Sopenharmony_ci
503ffe3c632Sopenharmony_ci
504ffe3c632Sopenharmony_ci/**
505ffe3c632Sopenharmony_ci * Converts a JsPb repeated message field into an object list.
506ffe3c632Sopenharmony_ci * @param {!Array<T>} field The repeated message field to be
507ffe3c632Sopenharmony_ci *     converted.
508ffe3c632Sopenharmony_ci * @param {?function(boolean=): Object|
509ffe3c632Sopenharmony_ci *     function((boolean|undefined),T): Object} toObjectFn The toObject
510ffe3c632Sopenharmony_ci *     function for this field.  We need to pass this for effective dead code
511ffe3c632Sopenharmony_ci *     removal.
512ffe3c632Sopenharmony_ci * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
513ffe3c632Sopenharmony_ci *     for transitional soy proto support: http://goto/soy-param-migration
514ffe3c632Sopenharmony_ci * @return {!Array<Object>} An array of converted message objects.
515ffe3c632Sopenharmony_ci * @template T
516ffe3c632Sopenharmony_ci */
517ffe3c632Sopenharmony_cijspb.Message.toObjectList = function(field, toObjectFn, opt_includeInstance) {
518ffe3c632Sopenharmony_ci  // Not using goog.array.map in the generated code to keep it small.
519ffe3c632Sopenharmony_ci  // And not using it here to avoid a function call.
520ffe3c632Sopenharmony_ci  var result = [];
521ffe3c632Sopenharmony_ci  for (var i = 0; i < field.length; i++) {
522ffe3c632Sopenharmony_ci    result[i] = toObjectFn.call(field[i], opt_includeInstance, field[i]);
523ffe3c632Sopenharmony_ci  }
524ffe3c632Sopenharmony_ci  return result;
525ffe3c632Sopenharmony_ci};
526ffe3c632Sopenharmony_ci
527ffe3c632Sopenharmony_ci
528ffe3c632Sopenharmony_ci/**
529ffe3c632Sopenharmony_ci * Adds a proto's extension data to a Soy rendering object.
530ffe3c632Sopenharmony_ci * @param {!jspb.Message} proto The proto whose extensions to convert.
531ffe3c632Sopenharmony_ci * @param {!Object} obj The Soy object to add converted extension data to.
532ffe3c632Sopenharmony_ci * @param {!Object} extensions The proto class' registered extensions.
533ffe3c632Sopenharmony_ci * @param {function(this:?, jspb.ExtensionFieldInfo) : *} getExtensionFn
534ffe3c632Sopenharmony_ci *     The proto class' getExtension function. Passed for effective dead code
535ffe3c632Sopenharmony_ci *     removal.
536ffe3c632Sopenharmony_ci * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
537ffe3c632Sopenharmony_ci *     for transitional soy proto support: http://goto/soy-param-migration
538ffe3c632Sopenharmony_ci */
539ffe3c632Sopenharmony_cijspb.Message.toObjectExtension = function(proto, obj, extensions,
540ffe3c632Sopenharmony_ci    getExtensionFn, opt_includeInstance) {
541ffe3c632Sopenharmony_ci  for (var fieldNumber in extensions) {
542ffe3c632Sopenharmony_ci    var fieldInfo = extensions[fieldNumber];
543ffe3c632Sopenharmony_ci    var value = getExtensionFn.call(proto, fieldInfo);
544ffe3c632Sopenharmony_ci    if (value != null) {
545ffe3c632Sopenharmony_ci      for (var name in fieldInfo.fieldName) {
546ffe3c632Sopenharmony_ci        if (fieldInfo.fieldName.hasOwnProperty(name)) {
547ffe3c632Sopenharmony_ci          break; // the compiled field name
548ffe3c632Sopenharmony_ci        }
549ffe3c632Sopenharmony_ci      }
550ffe3c632Sopenharmony_ci      if (!fieldInfo.toObjectFn) {
551ffe3c632Sopenharmony_ci        obj[name] = value;
552ffe3c632Sopenharmony_ci      } else {
553ffe3c632Sopenharmony_ci        if (fieldInfo.isRepeated) {
554ffe3c632Sopenharmony_ci          obj[name] = jspb.Message.toObjectList(
555ffe3c632Sopenharmony_ci              /** @type {!Array<!jspb.Message>} */ (value),
556ffe3c632Sopenharmony_ci              fieldInfo.toObjectFn, opt_includeInstance);
557ffe3c632Sopenharmony_ci        } else {
558ffe3c632Sopenharmony_ci          obj[name] = fieldInfo.toObjectFn(
559ffe3c632Sopenharmony_ci              opt_includeInstance, /** @type {!jspb.Message} */ (value));
560ffe3c632Sopenharmony_ci        }
561ffe3c632Sopenharmony_ci      }
562ffe3c632Sopenharmony_ci    }
563ffe3c632Sopenharmony_ci  }
564ffe3c632Sopenharmony_ci};
565ffe3c632Sopenharmony_ci
566ffe3c632Sopenharmony_ci
567ffe3c632Sopenharmony_ci/**
568ffe3c632Sopenharmony_ci * Writes a proto's extension data to a binary-format output stream.
569ffe3c632Sopenharmony_ci * @param {!jspb.Message} proto The proto whose extensions to convert.
570ffe3c632Sopenharmony_ci * @param {*} writer The binary-format writer to write to.
571ffe3c632Sopenharmony_ci * @param {!Object} extensions The proto class' registered extensions.
572ffe3c632Sopenharmony_ci * @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo) : *} getExtensionFn The proto
573ffe3c632Sopenharmony_ci *     class' getExtension function. Passed for effective dead code removal.
574ffe3c632Sopenharmony_ci */
575ffe3c632Sopenharmony_cijspb.Message.serializeBinaryExtensions = function(proto, writer, extensions,
576ffe3c632Sopenharmony_ci    getExtensionFn) {
577ffe3c632Sopenharmony_ci  for (var fieldNumber in extensions) {
578ffe3c632Sopenharmony_ci    var binaryFieldInfo = extensions[fieldNumber];
579ffe3c632Sopenharmony_ci    var fieldInfo = binaryFieldInfo.fieldInfo;
580ffe3c632Sopenharmony_ci
581ffe3c632Sopenharmony_ci    // The old codegen doesn't add the extra fields to ExtensionFieldInfo, so we
582ffe3c632Sopenharmony_ci    // need to gracefully error-out here rather than produce a null dereference
583ffe3c632Sopenharmony_ci    // below.
584ffe3c632Sopenharmony_ci    if (!binaryFieldInfo.binaryWriterFn) {
585ffe3c632Sopenharmony_ci      throw new Error('Message extension present that was generated ' +
586ffe3c632Sopenharmony_ci                      'without binary serialization support');
587ffe3c632Sopenharmony_ci    }
588ffe3c632Sopenharmony_ci    var value = getExtensionFn.call(proto, fieldInfo);
589ffe3c632Sopenharmony_ci    if (value != null) {
590ffe3c632Sopenharmony_ci      if (fieldInfo.isMessageType()) {
591ffe3c632Sopenharmony_ci        // If the message type of the extension was generated without binary
592ffe3c632Sopenharmony_ci        // support, there may not be a binary message serializer function, and
593ffe3c632Sopenharmony_ci        // we can't know when we codegen the extending message that the extended
594ffe3c632Sopenharmony_ci        // message may require binary support, so we can *only* catch this error
595ffe3c632Sopenharmony_ci        // here, at runtime (and this decoupled codegen is the whole point of
596ffe3c632Sopenharmony_ci        // extensions!).
597ffe3c632Sopenharmony_ci        if (binaryFieldInfo.binaryMessageSerializeFn) {
598ffe3c632Sopenharmony_ci          binaryFieldInfo.binaryWriterFn.call(writer, fieldInfo.fieldIndex,
599ffe3c632Sopenharmony_ci              value, binaryFieldInfo.binaryMessageSerializeFn);
600ffe3c632Sopenharmony_ci        } else {
601ffe3c632Sopenharmony_ci          throw new Error('Message extension present holding submessage ' +
602ffe3c632Sopenharmony_ci                          'without binary support enabled, and message is ' +
603ffe3c632Sopenharmony_ci                          'being serialized to binary format');
604ffe3c632Sopenharmony_ci        }
605ffe3c632Sopenharmony_ci      } else {
606ffe3c632Sopenharmony_ci        binaryFieldInfo.binaryWriterFn.call(
607ffe3c632Sopenharmony_ci            writer, fieldInfo.fieldIndex, value);
608ffe3c632Sopenharmony_ci      }
609ffe3c632Sopenharmony_ci    }
610ffe3c632Sopenharmony_ci  }
611ffe3c632Sopenharmony_ci};
612ffe3c632Sopenharmony_ci
613ffe3c632Sopenharmony_ci
614ffe3c632Sopenharmony_ci/**
615ffe3c632Sopenharmony_ci * Reads an extension field from the given reader and, if a valid extension,
616ffe3c632Sopenharmony_ci * sets the extension value.
617ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
618ffe3c632Sopenharmony_ci * @param {!jspb.BinaryReader} reader
619ffe3c632Sopenharmony_ci * @param {!Object} extensions The extensions object.
620ffe3c632Sopenharmony_ci * @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo)} getExtensionFn
621ffe3c632Sopenharmony_ci * @param {function(this:jspb.Message,!jspb.ExtensionFieldInfo, ?)} setExtensionFn
622ffe3c632Sopenharmony_ci */
623ffe3c632Sopenharmony_cijspb.Message.readBinaryExtension = function(msg, reader, extensions,
624ffe3c632Sopenharmony_ci    getExtensionFn, setExtensionFn) {
625ffe3c632Sopenharmony_ci  var binaryFieldInfo = extensions[reader.getFieldNumber()];
626ffe3c632Sopenharmony_ci  if (!binaryFieldInfo) {
627ffe3c632Sopenharmony_ci    reader.skipField();
628ffe3c632Sopenharmony_ci    return;
629ffe3c632Sopenharmony_ci  }
630ffe3c632Sopenharmony_ci  var fieldInfo = binaryFieldInfo.fieldInfo;
631ffe3c632Sopenharmony_ci  if (!binaryFieldInfo.binaryReaderFn) {
632ffe3c632Sopenharmony_ci    throw new Error('Deserializing extension whose generated code does not ' +
633ffe3c632Sopenharmony_ci                    'support binary format');
634ffe3c632Sopenharmony_ci  }
635ffe3c632Sopenharmony_ci
636ffe3c632Sopenharmony_ci  var value;
637ffe3c632Sopenharmony_ci  if (fieldInfo.isMessageType()) {
638ffe3c632Sopenharmony_ci    value = new fieldInfo.ctor();
639ffe3c632Sopenharmony_ci    binaryFieldInfo.binaryReaderFn.call(
640ffe3c632Sopenharmony_ci        reader, value, binaryFieldInfo.binaryMessageDeserializeFn);
641ffe3c632Sopenharmony_ci  } else {
642ffe3c632Sopenharmony_ci    // All other types.
643ffe3c632Sopenharmony_ci    value = binaryFieldInfo.binaryReaderFn.call(reader);
644ffe3c632Sopenharmony_ci  }
645ffe3c632Sopenharmony_ci
646ffe3c632Sopenharmony_ci  if (fieldInfo.isRepeated && !binaryFieldInfo.isPacked) {
647ffe3c632Sopenharmony_ci    var currentList = getExtensionFn.call(msg, fieldInfo);
648ffe3c632Sopenharmony_ci    if (!currentList) {
649ffe3c632Sopenharmony_ci      setExtensionFn.call(msg, fieldInfo, [value]);
650ffe3c632Sopenharmony_ci    } else {
651ffe3c632Sopenharmony_ci      currentList.push(value);
652ffe3c632Sopenharmony_ci    }
653ffe3c632Sopenharmony_ci  } else {
654ffe3c632Sopenharmony_ci    setExtensionFn.call(msg, fieldInfo, value);
655ffe3c632Sopenharmony_ci  }
656ffe3c632Sopenharmony_ci};
657ffe3c632Sopenharmony_ci
658ffe3c632Sopenharmony_ci
659ffe3c632Sopenharmony_ci/**
660ffe3c632Sopenharmony_ci * Gets the value of a non-extension field.
661ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
662ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
663ffe3c632Sopenharmony_ci * @return {string|number|boolean|Uint8Array|Array|null|undefined}
664ffe3c632Sopenharmony_ci * The field's value.
665ffe3c632Sopenharmony_ci * @protected
666ffe3c632Sopenharmony_ci */
667ffe3c632Sopenharmony_cijspb.Message.getField = function(msg, fieldNumber) {
668ffe3c632Sopenharmony_ci  if (fieldNumber < msg.pivot_) {
669ffe3c632Sopenharmony_ci    var index = jspb.Message.getIndex_(msg, fieldNumber);
670ffe3c632Sopenharmony_ci    var val = msg.array[index];
671ffe3c632Sopenharmony_ci    if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
672ffe3c632Sopenharmony_ci      return msg.array[index] = [];
673ffe3c632Sopenharmony_ci    }
674ffe3c632Sopenharmony_ci    return val;
675ffe3c632Sopenharmony_ci  } else {
676ffe3c632Sopenharmony_ci    if (!msg.extensionObject_) {
677ffe3c632Sopenharmony_ci      return undefined;
678ffe3c632Sopenharmony_ci    }
679ffe3c632Sopenharmony_ci    var val = msg.extensionObject_[fieldNumber];
680ffe3c632Sopenharmony_ci    if (val === jspb.Message.EMPTY_LIST_SENTINEL_) {
681ffe3c632Sopenharmony_ci      return msg.extensionObject_[fieldNumber] = [];
682ffe3c632Sopenharmony_ci    }
683ffe3c632Sopenharmony_ci    return val;
684ffe3c632Sopenharmony_ci  }
685ffe3c632Sopenharmony_ci};
686ffe3c632Sopenharmony_ci
687ffe3c632Sopenharmony_ci
688ffe3c632Sopenharmony_ci/**
689ffe3c632Sopenharmony_ci * Gets the value of a non-extension repeated field.
690ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
691ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
692ffe3c632Sopenharmony_ci * @return {!Array}
693ffe3c632Sopenharmony_ci * The field's value.
694ffe3c632Sopenharmony_ci * @protected
695ffe3c632Sopenharmony_ci */
696ffe3c632Sopenharmony_cijspb.Message.getRepeatedField = function(msg, fieldNumber) {
697ffe3c632Sopenharmony_ci  return /** @type {!Array} */ (jspb.Message.getField(msg, fieldNumber));
698ffe3c632Sopenharmony_ci};
699ffe3c632Sopenharmony_ci
700ffe3c632Sopenharmony_ci
701ffe3c632Sopenharmony_ci/**
702ffe3c632Sopenharmony_ci * Gets the value of an optional float or double field.
703ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
704ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
705ffe3c632Sopenharmony_ci * @return {?number|undefined} The field's value.
706ffe3c632Sopenharmony_ci * @protected
707ffe3c632Sopenharmony_ci */
708ffe3c632Sopenharmony_cijspb.Message.getOptionalFloatingPointField = function(msg, fieldNumber) {
709ffe3c632Sopenharmony_ci  var value = jspb.Message.getField(msg, fieldNumber);
710ffe3c632Sopenharmony_ci  // Converts "NaN", "Infinity" and "-Infinity" to their corresponding numbers.
711ffe3c632Sopenharmony_ci  return value == null ? value : +value;
712ffe3c632Sopenharmony_ci};
713ffe3c632Sopenharmony_ci
714ffe3c632Sopenharmony_ci
715ffe3c632Sopenharmony_ci/**
716ffe3c632Sopenharmony_ci * Gets the value of an optional boolean field.
717ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
718ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
719ffe3c632Sopenharmony_ci * @return {?boolean|undefined} The field's value.
720ffe3c632Sopenharmony_ci * @protected
721ffe3c632Sopenharmony_ci */
722ffe3c632Sopenharmony_cijspb.Message.getBooleanField = function(msg, fieldNumber) {
723ffe3c632Sopenharmony_ci  var value = jspb.Message.getField(msg, fieldNumber);
724ffe3c632Sopenharmony_ci  // TODO(b/122673075): always return null when the value is null-ish.
725ffe3c632Sopenharmony_ci  return value == null ? (value) : !!value;
726ffe3c632Sopenharmony_ci};
727ffe3c632Sopenharmony_ci
728ffe3c632Sopenharmony_ci
729ffe3c632Sopenharmony_ci/**
730ffe3c632Sopenharmony_ci * Gets the value of a repeated float or double field.
731ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
732ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
733ffe3c632Sopenharmony_ci * @return {!Array<number>} The field's value.
734ffe3c632Sopenharmony_ci * @protected
735ffe3c632Sopenharmony_ci */
736ffe3c632Sopenharmony_cijspb.Message.getRepeatedFloatingPointField = function(msg, fieldNumber) {
737ffe3c632Sopenharmony_ci  var values = jspb.Message.getRepeatedField(msg, fieldNumber);
738ffe3c632Sopenharmony_ci  if (!msg.convertedPrimitiveFields_) {
739ffe3c632Sopenharmony_ci    msg.convertedPrimitiveFields_ = {};
740ffe3c632Sopenharmony_ci  }
741ffe3c632Sopenharmony_ci  if (!msg.convertedPrimitiveFields_[fieldNumber]) {
742ffe3c632Sopenharmony_ci    for (var i = 0; i < values.length; i++) {
743ffe3c632Sopenharmony_ci      // Converts "NaN", "Infinity" and "-Infinity" to their corresponding
744ffe3c632Sopenharmony_ci      // numbers.
745ffe3c632Sopenharmony_ci      values[i] = +values[i];
746ffe3c632Sopenharmony_ci    }
747ffe3c632Sopenharmony_ci    msg.convertedPrimitiveFields_[fieldNumber] = true;
748ffe3c632Sopenharmony_ci  }
749ffe3c632Sopenharmony_ci  return /** @type {!Array<number>} */ (values);
750ffe3c632Sopenharmony_ci};
751ffe3c632Sopenharmony_ci
752ffe3c632Sopenharmony_ci/**
753ffe3c632Sopenharmony_ci * Gets the value of a repeated boolean field.
754ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
755ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
756ffe3c632Sopenharmony_ci * @return {!Array<boolean>} The field's value.
757ffe3c632Sopenharmony_ci * @protected
758ffe3c632Sopenharmony_ci */
759ffe3c632Sopenharmony_cijspb.Message.getRepeatedBooleanField = function(msg, fieldNumber) {
760ffe3c632Sopenharmony_ci  var values = jspb.Message.getRepeatedField(msg, fieldNumber);
761ffe3c632Sopenharmony_ci  if (!msg.convertedPrimitiveFields_) {
762ffe3c632Sopenharmony_ci    msg.convertedPrimitiveFields_ = {};
763ffe3c632Sopenharmony_ci  }
764ffe3c632Sopenharmony_ci  if (!msg.convertedPrimitiveFields_[fieldNumber]) {
765ffe3c632Sopenharmony_ci    for (var i = 0; i < values.length; i++) {
766ffe3c632Sopenharmony_ci      // Converts 0 and 1 to their corresponding booleans.
767ffe3c632Sopenharmony_ci      values[i] = !!values[i];
768ffe3c632Sopenharmony_ci    }
769ffe3c632Sopenharmony_ci    msg.convertedPrimitiveFields_[fieldNumber] = true;
770ffe3c632Sopenharmony_ci  }
771ffe3c632Sopenharmony_ci  return /** @type {!Array<boolean>} */ (values);
772ffe3c632Sopenharmony_ci};
773ffe3c632Sopenharmony_ci
774ffe3c632Sopenharmony_ci
775ffe3c632Sopenharmony_ci/**
776ffe3c632Sopenharmony_ci * Coerce a 'bytes' field to a base 64 string.
777ffe3c632Sopenharmony_ci * @param {string|Uint8Array|null} value
778ffe3c632Sopenharmony_ci * @return {?string} The field's coerced value.
779ffe3c632Sopenharmony_ci */
780ffe3c632Sopenharmony_cijspb.Message.bytesAsB64 = function(value) {
781ffe3c632Sopenharmony_ci  if (value == null || typeof value === 'string') {
782ffe3c632Sopenharmony_ci    return value;
783ffe3c632Sopenharmony_ci  }
784ffe3c632Sopenharmony_ci  if (jspb.Message.SUPPORTS_UINT8ARRAY_ && value instanceof Uint8Array) {
785ffe3c632Sopenharmony_ci    return goog.crypt.base64.encodeByteArray(value);
786ffe3c632Sopenharmony_ci  }
787ffe3c632Sopenharmony_ci  goog.asserts.fail('Cannot coerce to b64 string: ' + goog.typeOf(value));
788ffe3c632Sopenharmony_ci  return null;
789ffe3c632Sopenharmony_ci};
790ffe3c632Sopenharmony_ci
791ffe3c632Sopenharmony_ci
792ffe3c632Sopenharmony_ci/**
793ffe3c632Sopenharmony_ci * Coerce a 'bytes' field to a Uint8Array byte buffer.
794ffe3c632Sopenharmony_ci * Note that Uint8Array is not supported on IE versions before 10 nor on Opera
795ffe3c632Sopenharmony_ci * Mini. @see http://caniuse.com/Uint8Array
796ffe3c632Sopenharmony_ci * @param {string|Uint8Array|null} value
797ffe3c632Sopenharmony_ci * @return {?Uint8Array} The field's coerced value.
798ffe3c632Sopenharmony_ci */
799ffe3c632Sopenharmony_cijspb.Message.bytesAsU8 = function(value) {
800ffe3c632Sopenharmony_ci  if (value == null || value instanceof Uint8Array) {
801ffe3c632Sopenharmony_ci    return value;
802ffe3c632Sopenharmony_ci  }
803ffe3c632Sopenharmony_ci  if (typeof value === 'string') {
804ffe3c632Sopenharmony_ci    return goog.crypt.base64.decodeStringToUint8Array(value);
805ffe3c632Sopenharmony_ci  }
806ffe3c632Sopenharmony_ci  goog.asserts.fail('Cannot coerce to Uint8Array: ' + goog.typeOf(value));
807ffe3c632Sopenharmony_ci  return null;
808ffe3c632Sopenharmony_ci};
809ffe3c632Sopenharmony_ci
810ffe3c632Sopenharmony_ci
811ffe3c632Sopenharmony_ci/**
812ffe3c632Sopenharmony_ci * Coerce a repeated 'bytes' field to an array of base 64 strings.
813ffe3c632Sopenharmony_ci * Note: the returned array should be treated as immutable.
814ffe3c632Sopenharmony_ci * @param {!Array<string>|!Array<!Uint8Array>} value
815ffe3c632Sopenharmony_ci * @return {!Array<string?>} The field's coerced value.
816ffe3c632Sopenharmony_ci */
817ffe3c632Sopenharmony_cijspb.Message.bytesListAsB64 = function(value) {
818ffe3c632Sopenharmony_ci  jspb.Message.assertConsistentTypes_(value);
819ffe3c632Sopenharmony_ci  if (!value.length || typeof value[0] === 'string') {
820ffe3c632Sopenharmony_ci    return /** @type {!Array<string>} */ (value);
821ffe3c632Sopenharmony_ci  }
822ffe3c632Sopenharmony_ci  return goog.array.map(value, jspb.Message.bytesAsB64);
823ffe3c632Sopenharmony_ci};
824ffe3c632Sopenharmony_ci
825ffe3c632Sopenharmony_ci
826ffe3c632Sopenharmony_ci/**
827ffe3c632Sopenharmony_ci * Coerce a repeated 'bytes' field to an array of Uint8Array byte buffers.
828ffe3c632Sopenharmony_ci * Note: the returned array should be treated as immutable.
829ffe3c632Sopenharmony_ci * Note that Uint8Array is not supported on IE versions before 10 nor on Opera
830ffe3c632Sopenharmony_ci * Mini. @see http://caniuse.com/Uint8Array
831ffe3c632Sopenharmony_ci * @param {!Array<string>|!Array<!Uint8Array>} value
832ffe3c632Sopenharmony_ci * @return {!Array<Uint8Array?>} The field's coerced value.
833ffe3c632Sopenharmony_ci */
834ffe3c632Sopenharmony_cijspb.Message.bytesListAsU8 = function(value) {
835ffe3c632Sopenharmony_ci  jspb.Message.assertConsistentTypes_(value);
836ffe3c632Sopenharmony_ci  if (!value.length || value[0] instanceof Uint8Array) {
837ffe3c632Sopenharmony_ci    return /** @type {!Array<!Uint8Array>} */ (value);
838ffe3c632Sopenharmony_ci  }
839ffe3c632Sopenharmony_ci  return goog.array.map(value, jspb.Message.bytesAsU8);
840ffe3c632Sopenharmony_ci};
841ffe3c632Sopenharmony_ci
842ffe3c632Sopenharmony_ci
843ffe3c632Sopenharmony_ci/**
844ffe3c632Sopenharmony_ci * Asserts that all elements of an array are of the same type.
845ffe3c632Sopenharmony_ci * @param {Array?} array The array to test.
846ffe3c632Sopenharmony_ci * @private
847ffe3c632Sopenharmony_ci */
848ffe3c632Sopenharmony_cijspb.Message.assertConsistentTypes_ = function(array) {
849ffe3c632Sopenharmony_ci  if (goog.DEBUG && array && array.length > 1) {
850ffe3c632Sopenharmony_ci    var expected = goog.typeOf(array[0]);
851ffe3c632Sopenharmony_ci    goog.array.forEach(array, function(e) {
852ffe3c632Sopenharmony_ci      if (goog.typeOf(e) != expected) {
853ffe3c632Sopenharmony_ci        goog.asserts.fail('Inconsistent type in JSPB repeated field array. ' +
854ffe3c632Sopenharmony_ci            'Got ' + goog.typeOf(e) + ' expected ' + expected);
855ffe3c632Sopenharmony_ci      }
856ffe3c632Sopenharmony_ci    });
857ffe3c632Sopenharmony_ci  }
858ffe3c632Sopenharmony_ci};
859ffe3c632Sopenharmony_ci
860ffe3c632Sopenharmony_ci
861ffe3c632Sopenharmony_ci/**
862ffe3c632Sopenharmony_ci * Gets the value of a non-extension primitive field, with proto3 (non-nullable
863ffe3c632Sopenharmony_ci * primitives) semantics. Returns `defaultValue` if the field is not otherwise
864ffe3c632Sopenharmony_ci * set.
865ffe3c632Sopenharmony_ci * @template T
866ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
867ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
868ffe3c632Sopenharmony_ci * @param {T} defaultValue The default value.
869ffe3c632Sopenharmony_ci * @return {T} The field's value.
870ffe3c632Sopenharmony_ci * @protected
871ffe3c632Sopenharmony_ci */
872ffe3c632Sopenharmony_cijspb.Message.getFieldWithDefault = function(msg, fieldNumber, defaultValue) {
873ffe3c632Sopenharmony_ci  var value = jspb.Message.getField(msg, fieldNumber);
874ffe3c632Sopenharmony_ci  if (value == null) {
875ffe3c632Sopenharmony_ci    return defaultValue;
876ffe3c632Sopenharmony_ci  } else {
877ffe3c632Sopenharmony_ci    return value;
878ffe3c632Sopenharmony_ci  }
879ffe3c632Sopenharmony_ci};
880ffe3c632Sopenharmony_ci
881ffe3c632Sopenharmony_ci
882ffe3c632Sopenharmony_ci/**
883ffe3c632Sopenharmony_ci * Gets the value of a boolean field, with proto3 (non-nullable primitives)
884ffe3c632Sopenharmony_ci * semantics. Returns `defaultValue` if the field is not otherwise set.
885ffe3c632Sopenharmony_ci * @template T
886ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
887ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
888ffe3c632Sopenharmony_ci * @param {boolean} defaultValue The default value.
889ffe3c632Sopenharmony_ci * @return {boolean} The field's value.
890ffe3c632Sopenharmony_ci * @protected
891ffe3c632Sopenharmony_ci */
892ffe3c632Sopenharmony_cijspb.Message.getBooleanFieldWithDefault = function(
893ffe3c632Sopenharmony_ci    msg, fieldNumber, defaultValue) {
894ffe3c632Sopenharmony_ci  var value = jspb.Message.getBooleanField(msg, fieldNumber);
895ffe3c632Sopenharmony_ci  if (value == null) {
896ffe3c632Sopenharmony_ci    return defaultValue;
897ffe3c632Sopenharmony_ci  } else {
898ffe3c632Sopenharmony_ci    return value;
899ffe3c632Sopenharmony_ci  }
900ffe3c632Sopenharmony_ci};
901ffe3c632Sopenharmony_ci
902ffe3c632Sopenharmony_ci
903ffe3c632Sopenharmony_ci/**
904ffe3c632Sopenharmony_ci * Gets the value of a floating point field, with proto3 (non-nullable
905ffe3c632Sopenharmony_ci * primitives) semantics. Returns `defaultValue` if the field is not otherwise
906ffe3c632Sopenharmony_ci * set.
907ffe3c632Sopenharmony_ci * @template T
908ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
909ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
910ffe3c632Sopenharmony_ci * @param {number} defaultValue The default value.
911ffe3c632Sopenharmony_ci * @return {number} The field's value.
912ffe3c632Sopenharmony_ci * @protected
913ffe3c632Sopenharmony_ci */
914ffe3c632Sopenharmony_cijspb.Message.getFloatingPointFieldWithDefault = function(
915ffe3c632Sopenharmony_ci    msg, fieldNumber, defaultValue) {
916ffe3c632Sopenharmony_ci  var value = jspb.Message.getOptionalFloatingPointField(msg, fieldNumber);
917ffe3c632Sopenharmony_ci  if (value == null) {
918ffe3c632Sopenharmony_ci    return defaultValue;
919ffe3c632Sopenharmony_ci  } else {
920ffe3c632Sopenharmony_ci    return value;
921ffe3c632Sopenharmony_ci  }
922ffe3c632Sopenharmony_ci};
923ffe3c632Sopenharmony_ci
924ffe3c632Sopenharmony_ci
925ffe3c632Sopenharmony_ci/**
926ffe3c632Sopenharmony_ci * Alias for getFieldWithDefault used by older generated code.
927ffe3c632Sopenharmony_ci * @template T
928ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
929ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
930ffe3c632Sopenharmony_ci * @param {T} defaultValue The default value.
931ffe3c632Sopenharmony_ci * @return {T} The field's value.
932ffe3c632Sopenharmony_ci * @protected
933ffe3c632Sopenharmony_ci */
934ffe3c632Sopenharmony_cijspb.Message.getFieldProto3 = jspb.Message.getFieldWithDefault;
935ffe3c632Sopenharmony_ci
936ffe3c632Sopenharmony_ci
937ffe3c632Sopenharmony_ci/**
938ffe3c632Sopenharmony_ci * Gets the value of a map field, lazily creating the map container if
939ffe3c632Sopenharmony_ci * necessary.
940ffe3c632Sopenharmony_ci *
941ffe3c632Sopenharmony_ci * This should only be called from generated code, because it requires knowledge
942ffe3c632Sopenharmony_ci * of serialization/parsing callbacks (which are required by the map at
943ffe3c632Sopenharmony_ci * construction time, and the map may be constructed here).
944ffe3c632Sopenharmony_ci *
945ffe3c632Sopenharmony_ci * @template K, V
946ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg
947ffe3c632Sopenharmony_ci * @param {number} fieldNumber
948ffe3c632Sopenharmony_ci * @param {boolean|undefined} noLazyCreate
949ffe3c632Sopenharmony_ci * @param {?=} opt_valueCtor
950ffe3c632Sopenharmony_ci * @return {!jspb.Map<K, V>|undefined}
951ffe3c632Sopenharmony_ci * @protected
952ffe3c632Sopenharmony_ci */
953ffe3c632Sopenharmony_cijspb.Message.getMapField = function(msg, fieldNumber, noLazyCreate,
954ffe3c632Sopenharmony_ci    opt_valueCtor) {
955ffe3c632Sopenharmony_ci  if (!msg.wrappers_) {
956ffe3c632Sopenharmony_ci    msg.wrappers_ = {};
957ffe3c632Sopenharmony_ci  }
958ffe3c632Sopenharmony_ci  // If we already have a map in the map wrappers, return that.
959ffe3c632Sopenharmony_ci  if (fieldNumber in msg.wrappers_) {
960ffe3c632Sopenharmony_ci    return msg.wrappers_[fieldNumber];
961ffe3c632Sopenharmony_ci  }
962ffe3c632Sopenharmony_ci  var arr = jspb.Message.getField(msg, fieldNumber);
963ffe3c632Sopenharmony_ci  // Wrap the underlying elements array with a Map.
964ffe3c632Sopenharmony_ci  if (!arr) {
965ffe3c632Sopenharmony_ci    if (noLazyCreate) {
966ffe3c632Sopenharmony_ci      return undefined;
967ffe3c632Sopenharmony_ci    }
968ffe3c632Sopenharmony_ci    arr = [];
969ffe3c632Sopenharmony_ci    jspb.Message.setField(msg, fieldNumber, arr);
970ffe3c632Sopenharmony_ci  }
971ffe3c632Sopenharmony_ci  return msg.wrappers_[fieldNumber] =
972ffe3c632Sopenharmony_ci      new jspb.Map(
973ffe3c632Sopenharmony_ci          /** @type {!Array<!Array<!Object>>} */ (arr), opt_valueCtor);
974ffe3c632Sopenharmony_ci};
975ffe3c632Sopenharmony_ci
976ffe3c632Sopenharmony_ci
977ffe3c632Sopenharmony_ci/**
978ffe3c632Sopenharmony_ci * Sets the value of a non-extension field.
979ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
980ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
981ffe3c632Sopenharmony_ci * @param {string|number|boolean|Uint8Array|Array|undefined} value New value
982ffe3c632Sopenharmony_ci * @return {T} return msg
983ffe3c632Sopenharmony_ci * @template T
984ffe3c632Sopenharmony_ci * @protected
985ffe3c632Sopenharmony_ci */
986ffe3c632Sopenharmony_cijspb.Message.setField = function(msg, fieldNumber, value) {
987ffe3c632Sopenharmony_ci  // TODO(b/35241823): replace this with a bounded generic when available
988ffe3c632Sopenharmony_ci  goog.asserts.assertInstanceof(msg, jspb.Message);
989ffe3c632Sopenharmony_ci  if (fieldNumber < msg.pivot_) {
990ffe3c632Sopenharmony_ci    msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = value;
991ffe3c632Sopenharmony_ci  } else {
992ffe3c632Sopenharmony_ci    jspb.Message.maybeInitEmptyExtensionObject_(msg);
993ffe3c632Sopenharmony_ci    msg.extensionObject_[fieldNumber] = value;
994ffe3c632Sopenharmony_ci  }
995ffe3c632Sopenharmony_ci  return msg;
996ffe3c632Sopenharmony_ci};
997ffe3c632Sopenharmony_ci
998ffe3c632Sopenharmony_ci
999ffe3c632Sopenharmony_ci/**
1000ffe3c632Sopenharmony_ci * Sets the value of a non-extension integer field of a proto3
1001ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1002ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1003ffe3c632Sopenharmony_ci * @param {number} value New value
1004ffe3c632Sopenharmony_ci * @return {T} return msg
1005ffe3c632Sopenharmony_ci * @template T
1006ffe3c632Sopenharmony_ci * @protected
1007ffe3c632Sopenharmony_ci */
1008ffe3c632Sopenharmony_cijspb.Message.setProto3IntField = function(msg, fieldNumber, value) {
1009ffe3c632Sopenharmony_ci  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0);
1010ffe3c632Sopenharmony_ci};
1011ffe3c632Sopenharmony_ci
1012ffe3c632Sopenharmony_ci
1013ffe3c632Sopenharmony_ci/**
1014ffe3c632Sopenharmony_ci * Sets the value of a non-extension floating point field of a proto3
1015ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1016ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1017ffe3c632Sopenharmony_ci * @param {number} value New value
1018ffe3c632Sopenharmony_ci * @return {T} return msg
1019ffe3c632Sopenharmony_ci * @template T
1020ffe3c632Sopenharmony_ci * @protected
1021ffe3c632Sopenharmony_ci */
1022ffe3c632Sopenharmony_cijspb.Message.setProto3FloatField = function(msg, fieldNumber, value) {
1023ffe3c632Sopenharmony_ci  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0.0);
1024ffe3c632Sopenharmony_ci};
1025ffe3c632Sopenharmony_ci
1026ffe3c632Sopenharmony_ci
1027ffe3c632Sopenharmony_ci/**
1028ffe3c632Sopenharmony_ci * Sets the value of a non-extension boolean field of a proto3
1029ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1030ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1031ffe3c632Sopenharmony_ci * @param {boolean} value New value
1032ffe3c632Sopenharmony_ci * @return {T} return msg
1033ffe3c632Sopenharmony_ci * @template T
1034ffe3c632Sopenharmony_ci * @protected
1035ffe3c632Sopenharmony_ci */
1036ffe3c632Sopenharmony_cijspb.Message.setProto3BooleanField = function(msg, fieldNumber, value) {
1037ffe3c632Sopenharmony_ci  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, false);
1038ffe3c632Sopenharmony_ci};
1039ffe3c632Sopenharmony_ci
1040ffe3c632Sopenharmony_ci
1041ffe3c632Sopenharmony_ci/**
1042ffe3c632Sopenharmony_ci * Sets the value of a non-extension String field of a proto3
1043ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1044ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1045ffe3c632Sopenharmony_ci * @param {string} value New value
1046ffe3c632Sopenharmony_ci * @return {T} return msg
1047ffe3c632Sopenharmony_ci * @template T
1048ffe3c632Sopenharmony_ci * @protected
1049ffe3c632Sopenharmony_ci */
1050ffe3c632Sopenharmony_cijspb.Message.setProto3StringField = function(msg, fieldNumber, value) {
1051ffe3c632Sopenharmony_ci  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, '');
1052ffe3c632Sopenharmony_ci};
1053ffe3c632Sopenharmony_ci
1054ffe3c632Sopenharmony_ci
1055ffe3c632Sopenharmony_ci/**
1056ffe3c632Sopenharmony_ci * Sets the value of a non-extension Bytes field of a proto3
1057ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1058ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1059ffe3c632Sopenharmony_ci * @param {!Uint8Array|string} value New value
1060ffe3c632Sopenharmony_ci * @return {T} return msg
1061ffe3c632Sopenharmony_ci * @template T
1062ffe3c632Sopenharmony_ci * @protected
1063ffe3c632Sopenharmony_ci */
1064ffe3c632Sopenharmony_cijspb.Message.setProto3BytesField = function(msg, fieldNumber, value) {
1065ffe3c632Sopenharmony_ci  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, '');
1066ffe3c632Sopenharmony_ci};
1067ffe3c632Sopenharmony_ci
1068ffe3c632Sopenharmony_ci
1069ffe3c632Sopenharmony_ci/**
1070ffe3c632Sopenharmony_ci * Sets the value of a non-extension enum field of a proto3
1071ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1072ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1073ffe3c632Sopenharmony_ci * @param {number} value New value
1074ffe3c632Sopenharmony_ci * @return {T} return msg
1075ffe3c632Sopenharmony_ci * @template T
1076ffe3c632Sopenharmony_ci * @protected
1077ffe3c632Sopenharmony_ci */
1078ffe3c632Sopenharmony_cijspb.Message.setProto3EnumField = function(msg, fieldNumber, value) {
1079ffe3c632Sopenharmony_ci  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, 0);
1080ffe3c632Sopenharmony_ci};
1081ffe3c632Sopenharmony_ci
1082ffe3c632Sopenharmony_ci
1083ffe3c632Sopenharmony_ci/**
1084ffe3c632Sopenharmony_ci * Sets the value of a non-extension int field of a proto3 that has jstype set
1085ffe3c632Sopenharmony_ci * to String.
1086ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1087ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1088ffe3c632Sopenharmony_ci * @param {string} value New value
1089ffe3c632Sopenharmony_ci * @return {T} return msg
1090ffe3c632Sopenharmony_ci * @template T
1091ffe3c632Sopenharmony_ci * @protected
1092ffe3c632Sopenharmony_ci */
1093ffe3c632Sopenharmony_cijspb.Message.setProto3StringIntField = function(msg, fieldNumber, value) {
1094ffe3c632Sopenharmony_ci  return jspb.Message.setFieldIgnoringDefault_(msg, fieldNumber, value, '0');
1095ffe3c632Sopenharmony_ci};
1096ffe3c632Sopenharmony_ci
1097ffe3c632Sopenharmony_ci/**
1098ffe3c632Sopenharmony_ci * Sets the value of a non-extension primitive field, with proto3 (non-nullable
1099ffe3c632Sopenharmony_ci * primitives) semantics of ignoring values that are equal to the type's
1100ffe3c632Sopenharmony_ci * default.
1101ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1102ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1103ffe3c632Sopenharmony_ci * @param {!Uint8Array|string|number|boolean|undefined} value New value
1104ffe3c632Sopenharmony_ci * @param {!Uint8Array|string|number|boolean} defaultValue The default value.
1105ffe3c632Sopenharmony_ci * @return {T} return msg
1106ffe3c632Sopenharmony_ci * @template T
1107ffe3c632Sopenharmony_ci * @private
1108ffe3c632Sopenharmony_ci */
1109ffe3c632Sopenharmony_cijspb.Message.setFieldIgnoringDefault_ = function(
1110ffe3c632Sopenharmony_ci    msg, fieldNumber, value, defaultValue) {
1111ffe3c632Sopenharmony_ci  // TODO(b/35241823): replace this with a bounded generic when available
1112ffe3c632Sopenharmony_ci  goog.asserts.assertInstanceof(msg, jspb.Message);
1113ffe3c632Sopenharmony_ci  if (value !== defaultValue) {
1114ffe3c632Sopenharmony_ci    jspb.Message.setField(msg, fieldNumber, value);
1115ffe3c632Sopenharmony_ci  } else if (fieldNumber < msg.pivot_) {
1116ffe3c632Sopenharmony_ci    msg.array[jspb.Message.getIndex_(msg, fieldNumber)] = null;
1117ffe3c632Sopenharmony_ci  } else {
1118ffe3c632Sopenharmony_ci    jspb.Message.maybeInitEmptyExtensionObject_(msg);
1119ffe3c632Sopenharmony_ci    delete msg.extensionObject_[fieldNumber];
1120ffe3c632Sopenharmony_ci  }
1121ffe3c632Sopenharmony_ci  return msg;
1122ffe3c632Sopenharmony_ci};
1123ffe3c632Sopenharmony_ci
1124ffe3c632Sopenharmony_ci
1125ffe3c632Sopenharmony_ci/**
1126ffe3c632Sopenharmony_ci * Adds a value to a repeated, primitive field.
1127ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1128ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1129ffe3c632Sopenharmony_ci * @param {string|number|boolean|!Uint8Array} value New value
1130ffe3c632Sopenharmony_ci * @param {number=} opt_index Index where to put new value.
1131ffe3c632Sopenharmony_ci * @return {T} return msg
1132ffe3c632Sopenharmony_ci * @template T
1133ffe3c632Sopenharmony_ci * @protected
1134ffe3c632Sopenharmony_ci */
1135ffe3c632Sopenharmony_cijspb.Message.addToRepeatedField = function(msg, fieldNumber, value, opt_index) {
1136ffe3c632Sopenharmony_ci  // TODO(b/35241823): replace this with a bounded generic when available
1137ffe3c632Sopenharmony_ci  goog.asserts.assertInstanceof(msg, jspb.Message);
1138ffe3c632Sopenharmony_ci  var arr = jspb.Message.getRepeatedField(msg, fieldNumber);
1139ffe3c632Sopenharmony_ci  if (opt_index != undefined) {
1140ffe3c632Sopenharmony_ci    arr.splice(opt_index, 0, value);
1141ffe3c632Sopenharmony_ci  } else {
1142ffe3c632Sopenharmony_ci    arr.push(value);
1143ffe3c632Sopenharmony_ci  }
1144ffe3c632Sopenharmony_ci  return msg;
1145ffe3c632Sopenharmony_ci};
1146ffe3c632Sopenharmony_ci
1147ffe3c632Sopenharmony_ci
1148ffe3c632Sopenharmony_ci/**
1149ffe3c632Sopenharmony_ci * Sets the value of a field in a oneof union and clears all other fields in
1150ffe3c632Sopenharmony_ci * the union.
1151ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1152ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1153ffe3c632Sopenharmony_ci * @param {!Array<number>} oneof The fields belonging to the union.
1154ffe3c632Sopenharmony_ci * @param {string|number|boolean|Uint8Array|Array|undefined} value New value
1155ffe3c632Sopenharmony_ci * @return {T} return msg
1156ffe3c632Sopenharmony_ci * @template T
1157ffe3c632Sopenharmony_ci * @protected
1158ffe3c632Sopenharmony_ci */
1159ffe3c632Sopenharmony_cijspb.Message.setOneofField = function(msg, fieldNumber, oneof, value) {
1160ffe3c632Sopenharmony_ci  // TODO(b/35241823): replace this with a bounded generic when available
1161ffe3c632Sopenharmony_ci  goog.asserts.assertInstanceof(msg, jspb.Message);
1162ffe3c632Sopenharmony_ci  var currentCase = jspb.Message.computeOneofCase(msg, oneof);
1163ffe3c632Sopenharmony_ci  if (currentCase && currentCase !== fieldNumber && value !== undefined) {
1164ffe3c632Sopenharmony_ci    if (msg.wrappers_ && currentCase in msg.wrappers_) {
1165ffe3c632Sopenharmony_ci      msg.wrappers_[currentCase] = undefined;
1166ffe3c632Sopenharmony_ci    }
1167ffe3c632Sopenharmony_ci    jspb.Message.setField(msg, currentCase, undefined);
1168ffe3c632Sopenharmony_ci  }
1169ffe3c632Sopenharmony_ci  return jspb.Message.setField(msg, fieldNumber, value);
1170ffe3c632Sopenharmony_ci};
1171ffe3c632Sopenharmony_ci
1172ffe3c632Sopenharmony_ci
1173ffe3c632Sopenharmony_ci/**
1174ffe3c632Sopenharmony_ci * Computes the selection in a oneof group for the given message, ensuring
1175ffe3c632Sopenharmony_ci * only one field is set in the process.
1176ffe3c632Sopenharmony_ci *
1177ffe3c632Sopenharmony_ci * According to the protobuf language guide (
1178ffe3c632Sopenharmony_ci * https://developers.google.com/protocol-buffers/docs/proto#oneof), "if the
1179ffe3c632Sopenharmony_ci * parser encounters multiple members of the same oneof on the wire, only the
1180ffe3c632Sopenharmony_ci * last member seen is used in the parsed message." Since JSPB serializes
1181ffe3c632Sopenharmony_ci * messages to a JSON array, the "last member seen" will always be the field
1182ffe3c632Sopenharmony_ci * with the greatest field number (directly corresponding to the greatest
1183ffe3c632Sopenharmony_ci * array index).
1184ffe3c632Sopenharmony_ci *
1185ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
1186ffe3c632Sopenharmony_ci * @param {!Array<number>} oneof The field numbers belonging to the union.
1187ffe3c632Sopenharmony_ci * @return {number} The field number currently set in the union, or 0 if none.
1188ffe3c632Sopenharmony_ci * @protected
1189ffe3c632Sopenharmony_ci */
1190ffe3c632Sopenharmony_cijspb.Message.computeOneofCase = function(msg, oneof) {
1191ffe3c632Sopenharmony_ci  var oneofField;
1192ffe3c632Sopenharmony_ci  var oneofValue;
1193ffe3c632Sopenharmony_ci
1194ffe3c632Sopenharmony_ci  for (var i = 0; i < oneof.length; i++) {
1195ffe3c632Sopenharmony_ci    var fieldNumber = oneof[i];
1196ffe3c632Sopenharmony_ci    var value = jspb.Message.getField(msg, fieldNumber);
1197ffe3c632Sopenharmony_ci    if (value != null) {
1198ffe3c632Sopenharmony_ci      oneofField = fieldNumber;
1199ffe3c632Sopenharmony_ci      oneofValue = value;
1200ffe3c632Sopenharmony_ci      jspb.Message.setField(msg, fieldNumber, undefined);
1201ffe3c632Sopenharmony_ci    }
1202ffe3c632Sopenharmony_ci  }
1203ffe3c632Sopenharmony_ci
1204ffe3c632Sopenharmony_ci  if (oneofField) {
1205ffe3c632Sopenharmony_ci    // NB: We know the value is unique, so we can call jspb.Message.setField
1206ffe3c632Sopenharmony_ci    // directly instead of jpsb.Message.setOneofField. Also, setOneofField
1207ffe3c632Sopenharmony_ci    // calls this function.
1208ffe3c632Sopenharmony_ci    jspb.Message.setField(msg, oneofField, oneofValue);
1209ffe3c632Sopenharmony_ci    return oneofField;
1210ffe3c632Sopenharmony_ci  }
1211ffe3c632Sopenharmony_ci
1212ffe3c632Sopenharmony_ci  return 0;
1213ffe3c632Sopenharmony_ci};
1214ffe3c632Sopenharmony_ci
1215ffe3c632Sopenharmony_ci
1216ffe3c632Sopenharmony_ci/**
1217ffe3c632Sopenharmony_ci * Gets and wraps a proto field on access.
1218ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
1219ffe3c632Sopenharmony_ci * @param {function(new:jspb.Message, Array)} ctor Constructor for the field.
1220ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1221ffe3c632Sopenharmony_ci * @param {number=} opt_required True (1) if this is a required field.
1222ffe3c632Sopenharmony_ci * @return {jspb.Message} The field as a jspb proto.
1223ffe3c632Sopenharmony_ci * @protected
1224ffe3c632Sopenharmony_ci */
1225ffe3c632Sopenharmony_cijspb.Message.getWrapperField = function(msg, ctor, fieldNumber, opt_required) {
1226ffe3c632Sopenharmony_ci  // TODO(mwr): Consider copying data and/or arrays.
1227ffe3c632Sopenharmony_ci  if (!msg.wrappers_) {
1228ffe3c632Sopenharmony_ci    msg.wrappers_ = {};
1229ffe3c632Sopenharmony_ci  }
1230ffe3c632Sopenharmony_ci  if (!msg.wrappers_[fieldNumber]) {
1231ffe3c632Sopenharmony_ci    var data = /** @type {Array} */ (jspb.Message.getField(msg, fieldNumber));
1232ffe3c632Sopenharmony_ci    if (opt_required || data) {
1233ffe3c632Sopenharmony_ci      // TODO(mwr): Remove existence test for always valid default protos.
1234ffe3c632Sopenharmony_ci      msg.wrappers_[fieldNumber] = new ctor(data);
1235ffe3c632Sopenharmony_ci    }
1236ffe3c632Sopenharmony_ci  }
1237ffe3c632Sopenharmony_ci  return /** @type {jspb.Message} */ (msg.wrappers_[fieldNumber]);
1238ffe3c632Sopenharmony_ci};
1239ffe3c632Sopenharmony_ci
1240ffe3c632Sopenharmony_ci
1241ffe3c632Sopenharmony_ci/**
1242ffe3c632Sopenharmony_ci * Gets and wraps a repeated proto field on access.
1243ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
1244ffe3c632Sopenharmony_ci * @param {function(new:jspb.Message, Array)} ctor Constructor for the field.
1245ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1246ffe3c632Sopenharmony_ci * @return {!Array<!jspb.Message>} The repeated field as an array of protos.
1247ffe3c632Sopenharmony_ci * @protected
1248ffe3c632Sopenharmony_ci */
1249ffe3c632Sopenharmony_cijspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) {
1250ffe3c632Sopenharmony_ci  jspb.Message.wrapRepeatedField_(msg, ctor, fieldNumber);
1251ffe3c632Sopenharmony_ci  var val = msg.wrappers_[fieldNumber];
1252ffe3c632Sopenharmony_ci  if (val == jspb.Message.EMPTY_LIST_SENTINEL_) {
1253ffe3c632Sopenharmony_ci    val = msg.wrappers_[fieldNumber] = [];
1254ffe3c632Sopenharmony_ci  }
1255ffe3c632Sopenharmony_ci  return /** @type {!Array<!jspb.Message>} */ (val);
1256ffe3c632Sopenharmony_ci};
1257ffe3c632Sopenharmony_ci
1258ffe3c632Sopenharmony_ci
1259ffe3c632Sopenharmony_ci/**
1260ffe3c632Sopenharmony_ci * Wraps underlying array into proto message representation if it wasn't done
1261ffe3c632Sopenharmony_ci * before.
1262ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
1263ffe3c632Sopenharmony_ci * @param {function(new:jspb.Message, ?Array)} ctor Constructor for the field.
1264ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1265ffe3c632Sopenharmony_ci * @private
1266ffe3c632Sopenharmony_ci */
1267ffe3c632Sopenharmony_cijspb.Message.wrapRepeatedField_ = function(msg, ctor, fieldNumber) {
1268ffe3c632Sopenharmony_ci  if (!msg.wrappers_) {
1269ffe3c632Sopenharmony_ci    msg.wrappers_ = {};
1270ffe3c632Sopenharmony_ci  }
1271ffe3c632Sopenharmony_ci  if (!msg.wrappers_[fieldNumber]) {
1272ffe3c632Sopenharmony_ci    var data = jspb.Message.getRepeatedField(msg, fieldNumber);
1273ffe3c632Sopenharmony_ci    for (var wrappers = [], i = 0; i < data.length; i++) {
1274ffe3c632Sopenharmony_ci      wrappers[i] = new ctor(data[i]);
1275ffe3c632Sopenharmony_ci    }
1276ffe3c632Sopenharmony_ci    msg.wrappers_[fieldNumber] = wrappers;
1277ffe3c632Sopenharmony_ci  }
1278ffe3c632Sopenharmony_ci};
1279ffe3c632Sopenharmony_ci
1280ffe3c632Sopenharmony_ci
1281ffe3c632Sopenharmony_ci/**
1282ffe3c632Sopenharmony_ci * Sets a proto field and syncs it to the backing array.
1283ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1284ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1285ffe3c632Sopenharmony_ci * @param {?jspb.Message|?jspb.Map|undefined} value A new value for this proto
1286ffe3c632Sopenharmony_ci * field.
1287ffe3c632Sopenharmony_ci * @return {T} the msg
1288ffe3c632Sopenharmony_ci * @template T
1289ffe3c632Sopenharmony_ci * @protected
1290ffe3c632Sopenharmony_ci */
1291ffe3c632Sopenharmony_cijspb.Message.setWrapperField = function(msg, fieldNumber, value) {
1292ffe3c632Sopenharmony_ci  // TODO(b/35241823): replace this with a bounded generic when available
1293ffe3c632Sopenharmony_ci  goog.asserts.assertInstanceof(msg, jspb.Message);
1294ffe3c632Sopenharmony_ci  if (!msg.wrappers_) {
1295ffe3c632Sopenharmony_ci    msg.wrappers_ = {};
1296ffe3c632Sopenharmony_ci  }
1297ffe3c632Sopenharmony_ci  var data = value ? value.toArray() : value;
1298ffe3c632Sopenharmony_ci  msg.wrappers_[fieldNumber] = value;
1299ffe3c632Sopenharmony_ci  return jspb.Message.setField(msg, fieldNumber, data);
1300ffe3c632Sopenharmony_ci};
1301ffe3c632Sopenharmony_ci
1302ffe3c632Sopenharmony_ci
1303ffe3c632Sopenharmony_ci
1304ffe3c632Sopenharmony_ci/**
1305ffe3c632Sopenharmony_ci * Sets a proto field in a oneof union and syncs it to the backing array.
1306ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1307ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1308ffe3c632Sopenharmony_ci * @param {!Array<number>} oneof The fields belonging to the union.
1309ffe3c632Sopenharmony_ci * @param {jspb.Message|undefined} value A new value for this proto field.
1310ffe3c632Sopenharmony_ci * @return {T} the msg
1311ffe3c632Sopenharmony_ci * @template T
1312ffe3c632Sopenharmony_ci * @protected
1313ffe3c632Sopenharmony_ci */
1314ffe3c632Sopenharmony_cijspb.Message.setOneofWrapperField = function(msg, fieldNumber, oneof, value) {
1315ffe3c632Sopenharmony_ci  // TODO(b/35241823): replace this with a bounded generic when available
1316ffe3c632Sopenharmony_ci  goog.asserts.assertInstanceof(msg, jspb.Message);
1317ffe3c632Sopenharmony_ci  if (!msg.wrappers_) {
1318ffe3c632Sopenharmony_ci    msg.wrappers_ = {};
1319ffe3c632Sopenharmony_ci  }
1320ffe3c632Sopenharmony_ci  var data = value ? value.toArray() : value;
1321ffe3c632Sopenharmony_ci  msg.wrappers_[fieldNumber] = value;
1322ffe3c632Sopenharmony_ci  return jspb.Message.setOneofField(msg, fieldNumber, oneof, data);
1323ffe3c632Sopenharmony_ci};
1324ffe3c632Sopenharmony_ci
1325ffe3c632Sopenharmony_ci
1326ffe3c632Sopenharmony_ci/**
1327ffe3c632Sopenharmony_ci * Sets a repeated proto field and syncs it to the backing array.
1328ffe3c632Sopenharmony_ci * @param {T} msg A jspb proto.
1329ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1330ffe3c632Sopenharmony_ci * @param {Array<!jspb.Message>|undefined} value An array of protos.
1331ffe3c632Sopenharmony_ci * @return {T} the msg
1332ffe3c632Sopenharmony_ci * @template T
1333ffe3c632Sopenharmony_ci * @protected
1334ffe3c632Sopenharmony_ci */
1335ffe3c632Sopenharmony_cijspb.Message.setRepeatedWrapperField = function(msg, fieldNumber, value) {
1336ffe3c632Sopenharmony_ci  // TODO(b/35241823): replace this with a bounded generic when available
1337ffe3c632Sopenharmony_ci  goog.asserts.assertInstanceof(msg, jspb.Message);
1338ffe3c632Sopenharmony_ci  if (!msg.wrappers_) {
1339ffe3c632Sopenharmony_ci    msg.wrappers_ = {};
1340ffe3c632Sopenharmony_ci  }
1341ffe3c632Sopenharmony_ci  value = value || [];
1342ffe3c632Sopenharmony_ci  for (var data = [], i = 0; i < value.length; i++) {
1343ffe3c632Sopenharmony_ci    data[i] = value[i].toArray();
1344ffe3c632Sopenharmony_ci  }
1345ffe3c632Sopenharmony_ci  msg.wrappers_[fieldNumber] = value;
1346ffe3c632Sopenharmony_ci  return jspb.Message.setField(msg, fieldNumber, data);
1347ffe3c632Sopenharmony_ci};
1348ffe3c632Sopenharmony_ci
1349ffe3c632Sopenharmony_ci
1350ffe3c632Sopenharmony_ci/**
1351ffe3c632Sopenharmony_ci * Add a message to a repeated proto field.
1352ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A jspb proto.
1353ffe3c632Sopenharmony_ci * @param {number} fieldNumber The field number.
1354ffe3c632Sopenharmony_ci * @param {T_CHILD|undefined} value Proto that will be added to the
1355ffe3c632Sopenharmony_ci *     repeated field.
1356ffe3c632Sopenharmony_ci * @param {function(new:T_CHILD, ?Array=)} ctor The constructor of the
1357ffe3c632Sopenharmony_ci *     message type.
1358ffe3c632Sopenharmony_ci * @param {number|undefined} index Index at which to insert the value.
1359ffe3c632Sopenharmony_ci * @return {T_CHILD_NOT_UNDEFINED} proto that was inserted to the repeated field
1360ffe3c632Sopenharmony_ci * @template MessageType
1361ffe3c632Sopenharmony_ci * Use go/closure-ttl to declare a non-undefined version of T_CHILD. Replace the
1362ffe3c632Sopenharmony_ci * undefined in blah|undefined with none. This is necessary because the compiler
1363ffe3c632Sopenharmony_ci * will infer T_CHILD to be |undefined.
1364ffe3c632Sopenharmony_ci * @template T_CHILD
1365ffe3c632Sopenharmony_ci * @template T_CHILD_NOT_UNDEFINED :=
1366ffe3c632Sopenharmony_ci *     cond(isUnknown(T_CHILD), unknown(),
1367ffe3c632Sopenharmony_ci *       mapunion(T_CHILD, (X) =>
1368ffe3c632Sopenharmony_ci *         cond(eq(X, 'undefined'), none(), X)))
1369ffe3c632Sopenharmony_ci * =:
1370ffe3c632Sopenharmony_ci * @protected
1371ffe3c632Sopenharmony_ci */
1372ffe3c632Sopenharmony_cijspb.Message.addToRepeatedWrapperField = function(
1373ffe3c632Sopenharmony_ci    msg, fieldNumber, value, ctor, index) {
1374ffe3c632Sopenharmony_ci  jspb.Message.wrapRepeatedField_(msg, ctor, fieldNumber);
1375ffe3c632Sopenharmony_ci  var wrapperArray = msg.wrappers_[fieldNumber];
1376ffe3c632Sopenharmony_ci  if (!wrapperArray) {
1377ffe3c632Sopenharmony_ci    wrapperArray = msg.wrappers_[fieldNumber] = [];
1378ffe3c632Sopenharmony_ci  }
1379ffe3c632Sopenharmony_ci  var insertedValue = value ? value : new ctor();
1380ffe3c632Sopenharmony_ci  var array = jspb.Message.getRepeatedField(msg, fieldNumber);
1381ffe3c632Sopenharmony_ci  if (index != undefined) {
1382ffe3c632Sopenharmony_ci    wrapperArray.splice(index, 0, insertedValue);
1383ffe3c632Sopenharmony_ci    array.splice(index, 0, insertedValue.toArray());
1384ffe3c632Sopenharmony_ci  } else {
1385ffe3c632Sopenharmony_ci    wrapperArray.push(insertedValue);
1386ffe3c632Sopenharmony_ci    array.push(insertedValue.toArray());
1387ffe3c632Sopenharmony_ci  }
1388ffe3c632Sopenharmony_ci  return insertedValue;
1389ffe3c632Sopenharmony_ci};
1390ffe3c632Sopenharmony_ci
1391ffe3c632Sopenharmony_ci
1392ffe3c632Sopenharmony_ci/**
1393ffe3c632Sopenharmony_ci * Converts a JsPb repeated message field into a map. The map will contain
1394ffe3c632Sopenharmony_ci * protos unless an optional toObject function is given, in which case it will
1395ffe3c632Sopenharmony_ci * contain objects suitable for Soy rendering.
1396ffe3c632Sopenharmony_ci * @param {!Array<T>} field The repeated message field to be
1397ffe3c632Sopenharmony_ci *     converted.
1398ffe3c632Sopenharmony_ci * @param {function() : string?} mapKeyGetterFn The function to get the key of
1399ffe3c632Sopenharmony_ci *     the map.
1400ffe3c632Sopenharmony_ci * @param {?function(boolean=): Object|
1401ffe3c632Sopenharmony_ci *     function((boolean|undefined),T): Object} opt_toObjectFn The
1402ffe3c632Sopenharmony_ci *     toObject function for this field. We need to pass this for effective
1403ffe3c632Sopenharmony_ci *     dead code removal.
1404ffe3c632Sopenharmony_ci * @param {boolean=} opt_includeInstance Whether to include the JSPB instance
1405ffe3c632Sopenharmony_ci *     for transitional soy proto support: http://goto/soy-param-migration
1406ffe3c632Sopenharmony_ci * @return {!Object<string, Object>} A map of proto or Soy objects.
1407ffe3c632Sopenharmony_ci * @template T
1408ffe3c632Sopenharmony_ci */
1409ffe3c632Sopenharmony_cijspb.Message.toMap = function(
1410ffe3c632Sopenharmony_ci    field, mapKeyGetterFn, opt_toObjectFn, opt_includeInstance) {
1411ffe3c632Sopenharmony_ci  var result = {};
1412ffe3c632Sopenharmony_ci  for (var i = 0; i < field.length; i++) {
1413ffe3c632Sopenharmony_ci    result[mapKeyGetterFn.call(field[i])] = opt_toObjectFn ?
1414ffe3c632Sopenharmony_ci        opt_toObjectFn.call(field[i], opt_includeInstance,
1415ffe3c632Sopenharmony_ci            /** @type {!jspb.Message} */ (field[i])) : field[i];
1416ffe3c632Sopenharmony_ci  }
1417ffe3c632Sopenharmony_ci  return result;
1418ffe3c632Sopenharmony_ci};
1419ffe3c632Sopenharmony_ci
1420ffe3c632Sopenharmony_ci
1421ffe3c632Sopenharmony_ci/**
1422ffe3c632Sopenharmony_ci * Syncs all map fields' contents back to their underlying arrays.
1423ffe3c632Sopenharmony_ci * @private
1424ffe3c632Sopenharmony_ci */
1425ffe3c632Sopenharmony_cijspb.Message.prototype.syncMapFields_ = function() {
1426ffe3c632Sopenharmony_ci  // This iterates over submessage, map, and repeated fields, which is intended.
1427ffe3c632Sopenharmony_ci  // Submessages can contain maps which also need to be synced.
1428ffe3c632Sopenharmony_ci  //
1429ffe3c632Sopenharmony_ci  // There is a lot of opportunity for optimization here.  For example we could
1430ffe3c632Sopenharmony_ci  // statically determine that some messages have no submessages with maps and
1431ffe3c632Sopenharmony_ci  // optimize this method away for those just by generating one extra static
1432ffe3c632Sopenharmony_ci  // boolean per message type.
1433ffe3c632Sopenharmony_ci  if (this.wrappers_) {
1434ffe3c632Sopenharmony_ci    for (var fieldNumber in this.wrappers_) {
1435ffe3c632Sopenharmony_ci      var val = this.wrappers_[fieldNumber];
1436ffe3c632Sopenharmony_ci      if (Array.isArray(val)) {
1437ffe3c632Sopenharmony_ci        for (var i = 0; i < val.length; i++) {
1438ffe3c632Sopenharmony_ci          if (val[i]) {
1439ffe3c632Sopenharmony_ci            val[i].toArray();
1440ffe3c632Sopenharmony_ci          }
1441ffe3c632Sopenharmony_ci        }
1442ffe3c632Sopenharmony_ci      } else {
1443ffe3c632Sopenharmony_ci        // Works for submessages and maps.
1444ffe3c632Sopenharmony_ci        if (val) {
1445ffe3c632Sopenharmony_ci          val.toArray();
1446ffe3c632Sopenharmony_ci        }
1447ffe3c632Sopenharmony_ci      }
1448ffe3c632Sopenharmony_ci    }
1449ffe3c632Sopenharmony_ci  }
1450ffe3c632Sopenharmony_ci};
1451ffe3c632Sopenharmony_ci
1452ffe3c632Sopenharmony_ci
1453ffe3c632Sopenharmony_ci/**
1454ffe3c632Sopenharmony_ci * Returns the internal array of this proto.
1455ffe3c632Sopenharmony_ci * <p>Note: If you use this array to construct a second proto, the content
1456ffe3c632Sopenharmony_ci * would then be partially shared between the two protos.
1457ffe3c632Sopenharmony_ci * @return {!Array} The proto represented as an array.
1458ffe3c632Sopenharmony_ci */
1459ffe3c632Sopenharmony_cijspb.Message.prototype.toArray = function() {
1460ffe3c632Sopenharmony_ci  this.syncMapFields_();
1461ffe3c632Sopenharmony_ci  return this.array;
1462ffe3c632Sopenharmony_ci};
1463ffe3c632Sopenharmony_ci
1464ffe3c632Sopenharmony_ci
1465ffe3c632Sopenharmony_ci
1466ffe3c632Sopenharmony_ciif (jspb.Message.GENERATE_TO_STRING) {
1467ffe3c632Sopenharmony_ci
1468ffe3c632Sopenharmony_ci/**
1469ffe3c632Sopenharmony_ci * Creates a string representation of the internal data array of this proto.
1470ffe3c632Sopenharmony_ci * <p>NOTE: This string is *not* suitable for use in server requests.
1471ffe3c632Sopenharmony_ci * @return {string} A string representation of this proto.
1472ffe3c632Sopenharmony_ci * @override
1473ffe3c632Sopenharmony_ci */
1474ffe3c632Sopenharmony_cijspb.Message.prototype.toString = function() {
1475ffe3c632Sopenharmony_ci  this.syncMapFields_();
1476ffe3c632Sopenharmony_ci  return this.array.toString();
1477ffe3c632Sopenharmony_ci};
1478ffe3c632Sopenharmony_ci
1479ffe3c632Sopenharmony_ci}
1480ffe3c632Sopenharmony_ci
1481ffe3c632Sopenharmony_ci/**
1482ffe3c632Sopenharmony_ci * Gets the value of the extension field from the extended object.
1483ffe3c632Sopenharmony_ci * @param {jspb.ExtensionFieldInfo<T>} fieldInfo Specifies the field to get.
1484ffe3c632Sopenharmony_ci * @return {T} The value of the field.
1485ffe3c632Sopenharmony_ci * @template T
1486ffe3c632Sopenharmony_ci */
1487ffe3c632Sopenharmony_cijspb.Message.prototype.getExtension = function(fieldInfo) {
1488ffe3c632Sopenharmony_ci  if (!this.extensionObject_) {
1489ffe3c632Sopenharmony_ci    return undefined;
1490ffe3c632Sopenharmony_ci  }
1491ffe3c632Sopenharmony_ci  if (!this.wrappers_) {
1492ffe3c632Sopenharmony_ci    this.wrappers_ = {};
1493ffe3c632Sopenharmony_ci  }
1494ffe3c632Sopenharmony_ci  var fieldNumber = fieldInfo.fieldIndex;
1495ffe3c632Sopenharmony_ci  if (fieldInfo.isRepeated) {
1496ffe3c632Sopenharmony_ci    if (fieldInfo.isMessageType()) {
1497ffe3c632Sopenharmony_ci      if (!this.wrappers_[fieldNumber]) {
1498ffe3c632Sopenharmony_ci        this.wrappers_[fieldNumber] =
1499ffe3c632Sopenharmony_ci            goog.array.map(this.extensionObject_[fieldNumber] || [],
1500ffe3c632Sopenharmony_ci                function(arr) {
1501ffe3c632Sopenharmony_ci                  return new fieldInfo.ctor(arr);
1502ffe3c632Sopenharmony_ci                });
1503ffe3c632Sopenharmony_ci      }
1504ffe3c632Sopenharmony_ci      return this.wrappers_[fieldNumber];
1505ffe3c632Sopenharmony_ci    } else {
1506ffe3c632Sopenharmony_ci      return this.extensionObject_[fieldNumber];
1507ffe3c632Sopenharmony_ci    }
1508ffe3c632Sopenharmony_ci  } else {
1509ffe3c632Sopenharmony_ci    if (fieldInfo.isMessageType()) {
1510ffe3c632Sopenharmony_ci      if (!this.wrappers_[fieldNumber] && this.extensionObject_[fieldNumber]) {
1511ffe3c632Sopenharmony_ci        this.wrappers_[fieldNumber] = new fieldInfo.ctor(
1512ffe3c632Sopenharmony_ci            /** @type {Array|undefined} */ (
1513ffe3c632Sopenharmony_ci                this.extensionObject_[fieldNumber]));
1514ffe3c632Sopenharmony_ci      }
1515ffe3c632Sopenharmony_ci      return this.wrappers_[fieldNumber];
1516ffe3c632Sopenharmony_ci    } else {
1517ffe3c632Sopenharmony_ci      return this.extensionObject_[fieldNumber];
1518ffe3c632Sopenharmony_ci    }
1519ffe3c632Sopenharmony_ci  }
1520ffe3c632Sopenharmony_ci};
1521ffe3c632Sopenharmony_ci
1522ffe3c632Sopenharmony_ci
1523ffe3c632Sopenharmony_ci/**
1524ffe3c632Sopenharmony_ci * Sets the value of the extension field in the extended object.
1525ffe3c632Sopenharmony_ci * @param {jspb.ExtensionFieldInfo} fieldInfo Specifies the field to set.
1526ffe3c632Sopenharmony_ci * @param {jspb.Message|string|Uint8Array|number|boolean|Array?} value The value
1527ffe3c632Sopenharmony_ci *     to set.
1528ffe3c632Sopenharmony_ci * @return {THIS} For chaining
1529ffe3c632Sopenharmony_ci * @this {THIS}
1530ffe3c632Sopenharmony_ci * @template THIS
1531ffe3c632Sopenharmony_ci */
1532ffe3c632Sopenharmony_cijspb.Message.prototype.setExtension = function(fieldInfo, value) {
1533ffe3c632Sopenharmony_ci  // Cast self, since the inferred THIS is unknown inside the function body.
1534ffe3c632Sopenharmony_ci  // https://github.com/google/closure-compiler/issues/1411#issuecomment-232442220
1535ffe3c632Sopenharmony_ci  var self = /** @type {!jspb.Message} */ (this);
1536ffe3c632Sopenharmony_ci  if (!self.wrappers_) {
1537ffe3c632Sopenharmony_ci    self.wrappers_ = {};
1538ffe3c632Sopenharmony_ci  }
1539ffe3c632Sopenharmony_ci  jspb.Message.maybeInitEmptyExtensionObject_(self);
1540ffe3c632Sopenharmony_ci  var fieldNumber = fieldInfo.fieldIndex;
1541ffe3c632Sopenharmony_ci  if (fieldInfo.isRepeated) {
1542ffe3c632Sopenharmony_ci    value = value || [];
1543ffe3c632Sopenharmony_ci    if (fieldInfo.isMessageType()) {
1544ffe3c632Sopenharmony_ci      self.wrappers_[fieldNumber] = value;
1545ffe3c632Sopenharmony_ci      self.extensionObject_[fieldNumber] = goog.array.map(
1546ffe3c632Sopenharmony_ci          /** @type {!Array<!jspb.Message>} */ (value), function(msg) {
1547ffe3c632Sopenharmony_ci        return msg.toArray();
1548ffe3c632Sopenharmony_ci      });
1549ffe3c632Sopenharmony_ci    } else {
1550ffe3c632Sopenharmony_ci      self.extensionObject_[fieldNumber] = value;
1551ffe3c632Sopenharmony_ci    }
1552ffe3c632Sopenharmony_ci  } else {
1553ffe3c632Sopenharmony_ci    if (fieldInfo.isMessageType()) {
1554ffe3c632Sopenharmony_ci      self.wrappers_[fieldNumber] = value;
1555ffe3c632Sopenharmony_ci      self.extensionObject_[fieldNumber] =
1556ffe3c632Sopenharmony_ci          value ? /** @type {!jspb.Message} */ (value).toArray() : value;
1557ffe3c632Sopenharmony_ci    } else {
1558ffe3c632Sopenharmony_ci      self.extensionObject_[fieldNumber] = value;
1559ffe3c632Sopenharmony_ci    }
1560ffe3c632Sopenharmony_ci  }
1561ffe3c632Sopenharmony_ci  return self;
1562ffe3c632Sopenharmony_ci};
1563ffe3c632Sopenharmony_ci
1564ffe3c632Sopenharmony_ci
1565ffe3c632Sopenharmony_ci/**
1566ffe3c632Sopenharmony_ci * Creates a difference object between two messages.
1567ffe3c632Sopenharmony_ci *
1568ffe3c632Sopenharmony_ci * The result will contain the top-level fields of m2 that differ from those of
1569ffe3c632Sopenharmony_ci * m1 at any level of nesting. No data is cloned, the result object will
1570ffe3c632Sopenharmony_ci * share its top-level elements with m2 (but not with m1).
1571ffe3c632Sopenharmony_ci *
1572ffe3c632Sopenharmony_ci * Note that repeated fields should not have null/undefined elements, but if
1573ffe3c632Sopenharmony_ci * they do, this operation will treat repeated fields of different length as
1574ffe3c632Sopenharmony_ci * the same if the only difference between them is due to trailing
1575ffe3c632Sopenharmony_ci * null/undefined values.
1576ffe3c632Sopenharmony_ci *
1577ffe3c632Sopenharmony_ci * @param {!jspb.Message} m1 The first message object.
1578ffe3c632Sopenharmony_ci * @param {!jspb.Message} m2 The second message object.
1579ffe3c632Sopenharmony_ci * @return {!jspb.Message} The difference returned as a proto message.
1580ffe3c632Sopenharmony_ci *     Note that the returned message may be missing required fields. This is
1581ffe3c632Sopenharmony_ci *     currently tolerated in Js, but would cause an error if you tried to
1582ffe3c632Sopenharmony_ci *     send such a proto to the server. You can access the raw difference
1583ffe3c632Sopenharmony_ci *     array with result.toArray().
1584ffe3c632Sopenharmony_ci * @throws {Error} If the messages are responses with different types.
1585ffe3c632Sopenharmony_ci */
1586ffe3c632Sopenharmony_cijspb.Message.difference = function(m1, m2) {
1587ffe3c632Sopenharmony_ci  if (!(m1 instanceof m2.constructor)) {
1588ffe3c632Sopenharmony_ci    throw new Error('Messages have different types.');
1589ffe3c632Sopenharmony_ci  }
1590ffe3c632Sopenharmony_ci  var arr1 = m1.toArray();
1591ffe3c632Sopenharmony_ci  var arr2 = m2.toArray();
1592ffe3c632Sopenharmony_ci  var res = [];
1593ffe3c632Sopenharmony_ci  var start = 0;
1594ffe3c632Sopenharmony_ci  var length = arr1.length > arr2.length ? arr1.length : arr2.length;
1595ffe3c632Sopenharmony_ci  if (m1.getJsPbMessageId()) {
1596ffe3c632Sopenharmony_ci    res[0] = m1.getJsPbMessageId();
1597ffe3c632Sopenharmony_ci    start = 1;
1598ffe3c632Sopenharmony_ci  }
1599ffe3c632Sopenharmony_ci  for (var i = start; i < length; i++) {
1600ffe3c632Sopenharmony_ci    if (!jspb.Message.compareFields(arr1[i], arr2[i])) {
1601ffe3c632Sopenharmony_ci      res[i] = arr2[i];
1602ffe3c632Sopenharmony_ci    }
1603ffe3c632Sopenharmony_ci  }
1604ffe3c632Sopenharmony_ci  return new m1.constructor(res);
1605ffe3c632Sopenharmony_ci};
1606ffe3c632Sopenharmony_ci
1607ffe3c632Sopenharmony_ci
1608ffe3c632Sopenharmony_ci/**
1609ffe3c632Sopenharmony_ci * Tests whether two messages are equal.
1610ffe3c632Sopenharmony_ci * @param {jspb.Message|undefined} m1 The first message object.
1611ffe3c632Sopenharmony_ci * @param {jspb.Message|undefined} m2 The second message object.
1612ffe3c632Sopenharmony_ci * @return {boolean} true if both messages are null/undefined, or if both are
1613ffe3c632Sopenharmony_ci *     of the same type and have the same field values.
1614ffe3c632Sopenharmony_ci */
1615ffe3c632Sopenharmony_cijspb.Message.equals = function(m1, m2) {
1616ffe3c632Sopenharmony_ci  return m1 == m2 || (!!(m1 && m2) && (m1 instanceof m2.constructor) &&
1617ffe3c632Sopenharmony_ci      jspb.Message.compareFields(m1.toArray(), m2.toArray()));
1618ffe3c632Sopenharmony_ci};
1619ffe3c632Sopenharmony_ci
1620ffe3c632Sopenharmony_ci
1621ffe3c632Sopenharmony_ci/**
1622ffe3c632Sopenharmony_ci * Compares two message extension fields recursively.
1623ffe3c632Sopenharmony_ci * @param {!Object} extension1 The first field.
1624ffe3c632Sopenharmony_ci * @param {!Object} extension2 The second field.
1625ffe3c632Sopenharmony_ci * @return {boolean} true if the extensions are null/undefined, or otherwise
1626ffe3c632Sopenharmony_ci *     equal.
1627ffe3c632Sopenharmony_ci */
1628ffe3c632Sopenharmony_cijspb.Message.compareExtensions = function(extension1, extension2) {
1629ffe3c632Sopenharmony_ci  extension1 = extension1 || {};
1630ffe3c632Sopenharmony_ci  extension2 = extension2 || {};
1631ffe3c632Sopenharmony_ci
1632ffe3c632Sopenharmony_ci  var keys = {};
1633ffe3c632Sopenharmony_ci  for (var name in extension1) {
1634ffe3c632Sopenharmony_ci    keys[name] = 0;
1635ffe3c632Sopenharmony_ci  }
1636ffe3c632Sopenharmony_ci  for (var name in extension2) {
1637ffe3c632Sopenharmony_ci    keys[name] = 0;
1638ffe3c632Sopenharmony_ci  }
1639ffe3c632Sopenharmony_ci  for (name in keys) {
1640ffe3c632Sopenharmony_ci    if (!jspb.Message.compareFields(extension1[name], extension2[name])) {
1641ffe3c632Sopenharmony_ci      return false;
1642ffe3c632Sopenharmony_ci    }
1643ffe3c632Sopenharmony_ci  }
1644ffe3c632Sopenharmony_ci  return true;
1645ffe3c632Sopenharmony_ci};
1646ffe3c632Sopenharmony_ci
1647ffe3c632Sopenharmony_ci
1648ffe3c632Sopenharmony_ci/**
1649ffe3c632Sopenharmony_ci * Compares two message fields recursively.
1650ffe3c632Sopenharmony_ci * @param {*} field1 The first field.
1651ffe3c632Sopenharmony_ci * @param {*} field2 The second field.
1652ffe3c632Sopenharmony_ci * @return {boolean} true if the fields are null/undefined, or otherwise equal.
1653ffe3c632Sopenharmony_ci */
1654ffe3c632Sopenharmony_cijspb.Message.compareFields = function(field1, field2) {
1655ffe3c632Sopenharmony_ci  // If the fields are trivially equal, they're equal.
1656ffe3c632Sopenharmony_ci  if (field1 == field2) return true;
1657ffe3c632Sopenharmony_ci
1658ffe3c632Sopenharmony_ci  if (!goog.isObject(field1) || !goog.isObject(field2)) {
1659ffe3c632Sopenharmony_ci    // NaN != NaN so we cover this case.
1660ffe3c632Sopenharmony_ci    if ((typeof field1 === 'number' && isNaN(field1)) ||
1661ffe3c632Sopenharmony_ci        (typeof field2 === 'number' && isNaN(field2))) {
1662ffe3c632Sopenharmony_ci      // One of the fields might be a string 'NaN'.
1663ffe3c632Sopenharmony_ci      return String(field1) == String(field2);
1664ffe3c632Sopenharmony_ci    }
1665ffe3c632Sopenharmony_ci    // If the fields aren't trivially equal and one of them isn't an object,
1666ffe3c632Sopenharmony_ci    // they can't possibly be equal.
1667ffe3c632Sopenharmony_ci    return false;
1668ffe3c632Sopenharmony_ci  }
1669ffe3c632Sopenharmony_ci
1670ffe3c632Sopenharmony_ci  // We have two objects. If they're different types, they're not equal.
1671ffe3c632Sopenharmony_ci  field1 = /** @type {!Object} */(field1);
1672ffe3c632Sopenharmony_ci  field2 = /** @type {!Object} */(field2);
1673ffe3c632Sopenharmony_ci  if (field1.constructor != field2.constructor) return false;
1674ffe3c632Sopenharmony_ci
1675ffe3c632Sopenharmony_ci  // If both are Uint8Arrays, compare them element-by-element.
1676ffe3c632Sopenharmony_ci  if (jspb.Message.SUPPORTS_UINT8ARRAY_ && field1.constructor === Uint8Array) {
1677ffe3c632Sopenharmony_ci    var bytes1 = /** @type {!Uint8Array} */(field1);
1678ffe3c632Sopenharmony_ci    var bytes2 = /** @type {!Uint8Array} */(field2);
1679ffe3c632Sopenharmony_ci    if (bytes1.length != bytes2.length) return false;
1680ffe3c632Sopenharmony_ci    for (var i = 0; i < bytes1.length; i++) {
1681ffe3c632Sopenharmony_ci      if (bytes1[i] != bytes2[i]) return false;
1682ffe3c632Sopenharmony_ci    }
1683ffe3c632Sopenharmony_ci    return true;
1684ffe3c632Sopenharmony_ci  }
1685ffe3c632Sopenharmony_ci
1686ffe3c632Sopenharmony_ci  // If they're both Arrays, compare them element by element except for the
1687ffe3c632Sopenharmony_ci  // optional extension objects at the end, which we compare separately.
1688ffe3c632Sopenharmony_ci  if (field1.constructor === Array) {
1689ffe3c632Sopenharmony_ci    var typedField1 = /** @type {!Array<?>} */ (field1);
1690ffe3c632Sopenharmony_ci    var typedField2 = /** @type {!Array<?>} */ (field2);
1691ffe3c632Sopenharmony_ci    var extension1 = undefined;
1692ffe3c632Sopenharmony_ci    var extension2 = undefined;
1693ffe3c632Sopenharmony_ci
1694ffe3c632Sopenharmony_ci    var length = Math.max(typedField1.length, typedField2.length);
1695ffe3c632Sopenharmony_ci    for (var i = 0; i < length; i++) {
1696ffe3c632Sopenharmony_ci      var val1 = typedField1[i];
1697ffe3c632Sopenharmony_ci      var val2 = typedField2[i];
1698ffe3c632Sopenharmony_ci
1699ffe3c632Sopenharmony_ci      if (val1 && (val1.constructor == Object)) {
1700ffe3c632Sopenharmony_ci        goog.asserts.assert(extension1 === undefined);
1701ffe3c632Sopenharmony_ci        goog.asserts.assert(i === typedField1.length - 1);
1702ffe3c632Sopenharmony_ci        extension1 = val1;
1703ffe3c632Sopenharmony_ci        val1 = undefined;
1704ffe3c632Sopenharmony_ci      }
1705ffe3c632Sopenharmony_ci
1706ffe3c632Sopenharmony_ci      if (val2 && (val2.constructor == Object)) {
1707ffe3c632Sopenharmony_ci        goog.asserts.assert(extension2 === undefined);
1708ffe3c632Sopenharmony_ci        goog.asserts.assert(i === typedField2.length - 1);
1709ffe3c632Sopenharmony_ci        extension2 = val2;
1710ffe3c632Sopenharmony_ci        val2 = undefined;
1711ffe3c632Sopenharmony_ci      }
1712ffe3c632Sopenharmony_ci
1713ffe3c632Sopenharmony_ci      if (!jspb.Message.compareFields(val1, val2)) {
1714ffe3c632Sopenharmony_ci        return false;
1715ffe3c632Sopenharmony_ci      }
1716ffe3c632Sopenharmony_ci    }
1717ffe3c632Sopenharmony_ci
1718ffe3c632Sopenharmony_ci    if (extension1 || extension2) {
1719ffe3c632Sopenharmony_ci      extension1 = extension1 || {};
1720ffe3c632Sopenharmony_ci      extension2 = extension2 || {};
1721ffe3c632Sopenharmony_ci      return jspb.Message.compareExtensions(extension1, extension2);
1722ffe3c632Sopenharmony_ci    }
1723ffe3c632Sopenharmony_ci
1724ffe3c632Sopenharmony_ci    return true;
1725ffe3c632Sopenharmony_ci  }
1726ffe3c632Sopenharmony_ci
1727ffe3c632Sopenharmony_ci  // If they're both plain Objects (i.e. extensions), compare them as
1728ffe3c632Sopenharmony_ci  // extensions.
1729ffe3c632Sopenharmony_ci  if (field1.constructor === Object) {
1730ffe3c632Sopenharmony_ci    return jspb.Message.compareExtensions(field1, field2);
1731ffe3c632Sopenharmony_ci  }
1732ffe3c632Sopenharmony_ci
1733ffe3c632Sopenharmony_ci  throw new Error('Invalid type in JSPB array');
1734ffe3c632Sopenharmony_ci};
1735ffe3c632Sopenharmony_ci
1736ffe3c632Sopenharmony_ci
1737ffe3c632Sopenharmony_ci/**
1738ffe3c632Sopenharmony_ci * Templated, type-safe cloneMessage definition.
1739ffe3c632Sopenharmony_ci * @return {THIS}
1740ffe3c632Sopenharmony_ci * @this {THIS}
1741ffe3c632Sopenharmony_ci * @template THIS
1742ffe3c632Sopenharmony_ci */
1743ffe3c632Sopenharmony_cijspb.Message.prototype.cloneMessage = function() {
1744ffe3c632Sopenharmony_ci  return jspb.Message.cloneMessage(/** @type {!jspb.Message} */ (this));
1745ffe3c632Sopenharmony_ci};
1746ffe3c632Sopenharmony_ci
1747ffe3c632Sopenharmony_ci/**
1748ffe3c632Sopenharmony_ci * Alias clone to cloneMessage. goog.object.unsafeClone uses clone to
1749ffe3c632Sopenharmony_ci * efficiently copy objects. Without this alias, copying jspb messages comes
1750ffe3c632Sopenharmony_ci * with a large performance penalty.
1751ffe3c632Sopenharmony_ci * @return {THIS}
1752ffe3c632Sopenharmony_ci * @this {THIS}
1753ffe3c632Sopenharmony_ci * @template THIS
1754ffe3c632Sopenharmony_ci */
1755ffe3c632Sopenharmony_cijspb.Message.prototype.clone = function() {
1756ffe3c632Sopenharmony_ci  return jspb.Message.cloneMessage(/** @type {!jspb.Message} */ (this));
1757ffe3c632Sopenharmony_ci};
1758ffe3c632Sopenharmony_ci
1759ffe3c632Sopenharmony_ci/**
1760ffe3c632Sopenharmony_ci * Static clone function. NOTE: A type-safe method called "cloneMessage"
1761ffe3c632Sopenharmony_ci * exists
1762ffe3c632Sopenharmony_ci * on each generated JsPb class. Do not call this function directly.
1763ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A message to clone.
1764ffe3c632Sopenharmony_ci * @return {!jspb.Message} A deep clone of the given message.
1765ffe3c632Sopenharmony_ci */
1766ffe3c632Sopenharmony_cijspb.Message.clone = function(msg) {
1767ffe3c632Sopenharmony_ci  // Although we could include the wrappers, we leave them out here.
1768ffe3c632Sopenharmony_ci  return jspb.Message.cloneMessage(msg);
1769ffe3c632Sopenharmony_ci};
1770ffe3c632Sopenharmony_ci
1771ffe3c632Sopenharmony_ci
1772ffe3c632Sopenharmony_ci/**
1773ffe3c632Sopenharmony_ci * @param {!jspb.Message} msg A message to clone.
1774ffe3c632Sopenharmony_ci * @return {!jspb.Message} A deep clone of the given message.
1775ffe3c632Sopenharmony_ci * @protected
1776ffe3c632Sopenharmony_ci */
1777ffe3c632Sopenharmony_cijspb.Message.cloneMessage = function(msg) {
1778ffe3c632Sopenharmony_ci  // Although we could include the wrappers, we leave them out here.
1779ffe3c632Sopenharmony_ci  return new msg.constructor(jspb.Message.clone_(msg.toArray()));
1780ffe3c632Sopenharmony_ci};
1781ffe3c632Sopenharmony_ci
1782ffe3c632Sopenharmony_ci
1783ffe3c632Sopenharmony_ci/**
1784ffe3c632Sopenharmony_ci * Takes 2 messages of the same type and copies the contents of the first
1785ffe3c632Sopenharmony_ci * message into the second. After this the 2 messages will equals in terms of
1786ffe3c632Sopenharmony_ci * value semantics but share no state. All data in the destination message will
1787ffe3c632Sopenharmony_ci * be overridden.
1788ffe3c632Sopenharmony_ci *
1789ffe3c632Sopenharmony_ci * @param {MESSAGE} fromMessage Message that will be copied into toMessage.
1790ffe3c632Sopenharmony_ci * @param {MESSAGE} toMessage Message which will receive a copy of fromMessage
1791ffe3c632Sopenharmony_ci *     as its contents.
1792ffe3c632Sopenharmony_ci * @template MESSAGE
1793ffe3c632Sopenharmony_ci */
1794ffe3c632Sopenharmony_cijspb.Message.copyInto = function(fromMessage, toMessage) {
1795ffe3c632Sopenharmony_ci  goog.asserts.assertInstanceof(fromMessage, jspb.Message);
1796ffe3c632Sopenharmony_ci  goog.asserts.assertInstanceof(toMessage, jspb.Message);
1797ffe3c632Sopenharmony_ci  goog.asserts.assert(fromMessage.constructor == toMessage.constructor,
1798ffe3c632Sopenharmony_ci      'Copy source and target message should have the same type.');
1799ffe3c632Sopenharmony_ci  var copyOfFrom = jspb.Message.clone(fromMessage);
1800ffe3c632Sopenharmony_ci
1801ffe3c632Sopenharmony_ci  var to = toMessage.toArray();
1802ffe3c632Sopenharmony_ci  var from = copyOfFrom.toArray();
1803ffe3c632Sopenharmony_ci
1804ffe3c632Sopenharmony_ci  // Empty destination in case it has more values at the end of the array.
1805ffe3c632Sopenharmony_ci  to.length = 0;
1806ffe3c632Sopenharmony_ci  // and then copy everything from the new to the existing message.
1807ffe3c632Sopenharmony_ci  for (var i = 0; i < from.length; i++) {
1808ffe3c632Sopenharmony_ci    to[i] = from[i];
1809ffe3c632Sopenharmony_ci  }
1810ffe3c632Sopenharmony_ci
1811ffe3c632Sopenharmony_ci  // This is either null or empty for a fresh copy.
1812ffe3c632Sopenharmony_ci  toMessage.wrappers_ = copyOfFrom.wrappers_;
1813ffe3c632Sopenharmony_ci  // Just a reference into the shared array.
1814ffe3c632Sopenharmony_ci  toMessage.extensionObject_ = copyOfFrom.extensionObject_;
1815ffe3c632Sopenharmony_ci};
1816ffe3c632Sopenharmony_ci
1817ffe3c632Sopenharmony_ci
1818ffe3c632Sopenharmony_ci/**
1819ffe3c632Sopenharmony_ci * Helper for cloning an internal JsPb object.
1820ffe3c632Sopenharmony_ci * @param {!Object} obj A JsPb object, eg, a field, to be cloned.
1821ffe3c632Sopenharmony_ci * @return {!Object} A clone of the input object.
1822ffe3c632Sopenharmony_ci * @private
1823ffe3c632Sopenharmony_ci */
1824ffe3c632Sopenharmony_cijspb.Message.clone_ = function(obj) {
1825ffe3c632Sopenharmony_ci  var o;
1826ffe3c632Sopenharmony_ci  if (Array.isArray(obj)) {
1827ffe3c632Sopenharmony_ci    // Allocate array of correct size.
1828ffe3c632Sopenharmony_ci    var clonedArray = new Array(obj.length);
1829ffe3c632Sopenharmony_ci    // Use array iteration where possible because it is faster than for-in.
1830ffe3c632Sopenharmony_ci    for (var i = 0; i < obj.length; i++) {
1831ffe3c632Sopenharmony_ci      o = obj[i];
1832ffe3c632Sopenharmony_ci      if (o != null) {
1833ffe3c632Sopenharmony_ci        // NOTE:redundant null check existing for NTI compatibility.
1834ffe3c632Sopenharmony_ci        // see b/70515949
1835ffe3c632Sopenharmony_ci        clonedArray[i] = (typeof o == 'object') ?
1836ffe3c632Sopenharmony_ci            jspb.Message.clone_(goog.asserts.assert(o)) :
1837ffe3c632Sopenharmony_ci            o;
1838ffe3c632Sopenharmony_ci      }
1839ffe3c632Sopenharmony_ci    }
1840ffe3c632Sopenharmony_ci    return clonedArray;
1841ffe3c632Sopenharmony_ci  }
1842ffe3c632Sopenharmony_ci  if (jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array) {
1843ffe3c632Sopenharmony_ci    return new Uint8Array(obj);
1844ffe3c632Sopenharmony_ci  }
1845ffe3c632Sopenharmony_ci  var clone = {};
1846ffe3c632Sopenharmony_ci  for (var key in obj) {
1847ffe3c632Sopenharmony_ci    o = obj[key];
1848ffe3c632Sopenharmony_ci    if (o != null) {
1849ffe3c632Sopenharmony_ci      // NOTE:redundant null check existing for NTI compatibility.
1850ffe3c632Sopenharmony_ci      // see b/70515949
1851ffe3c632Sopenharmony_ci      clone[key] = (typeof o == 'object') ?
1852ffe3c632Sopenharmony_ci          jspb.Message.clone_(goog.asserts.assert(o)) :
1853ffe3c632Sopenharmony_ci          o;
1854ffe3c632Sopenharmony_ci    }
1855ffe3c632Sopenharmony_ci  }
1856ffe3c632Sopenharmony_ci  return clone;
1857ffe3c632Sopenharmony_ci};
1858ffe3c632Sopenharmony_ci
1859ffe3c632Sopenharmony_ci
1860ffe3c632Sopenharmony_ci/**
1861ffe3c632Sopenharmony_ci * Registers a JsPb message type id with its constructor.
1862ffe3c632Sopenharmony_ci * @param {string} id The id for this type of message.
1863ffe3c632Sopenharmony_ci * @param {Function} constructor The message constructor.
1864ffe3c632Sopenharmony_ci */
1865ffe3c632Sopenharmony_cijspb.Message.registerMessageType = function(id, constructor) {
1866ffe3c632Sopenharmony_ci  // This is needed so we can later access messageId directly on the constructor,
1867ffe3c632Sopenharmony_ci  // otherwise it is not available due to 'property collapsing' by the compiler.
1868ffe3c632Sopenharmony_ci  /**
1869ffe3c632Sopenharmony_ci   * @suppress {strictMissingProperties} messageId is not defined on Function
1870ffe3c632Sopenharmony_ci   */
1871ffe3c632Sopenharmony_ci  constructor.messageId = id;
1872ffe3c632Sopenharmony_ci};
1873ffe3c632Sopenharmony_ci/**
1874ffe3c632Sopenharmony_ci * The extensions registered on MessageSet. This is a map of extension
1875ffe3c632Sopenharmony_ci * field number to field info object. This should be considered as a
1876ffe3c632Sopenharmony_ci * private API.
1877ffe3c632Sopenharmony_ci *
1878ffe3c632Sopenharmony_ci * This is similar to [jspb class name].extensions object for
1879ffe3c632Sopenharmony_ci * non-MessageSet. We special case MessageSet so that we do not need
1880ffe3c632Sopenharmony_ci * to goog.require MessageSet from classes that extends MessageSet.
1881ffe3c632Sopenharmony_ci *
1882ffe3c632Sopenharmony_ci * @type {!Object<number, jspb.ExtensionFieldInfo>}
1883ffe3c632Sopenharmony_ci */
1884ffe3c632Sopenharmony_cijspb.Message.messageSetExtensions = {};
1885ffe3c632Sopenharmony_ci
1886ffe3c632Sopenharmony_ci/**
1887ffe3c632Sopenharmony_ci * @type {!Object<number, jspb.ExtensionFieldBinaryInfo>}
1888ffe3c632Sopenharmony_ci */
1889ffe3c632Sopenharmony_cijspb.Message.messageSetExtensionsBinary = {};
1890