• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31/**
32 * @fileoverview This file contains utilities for encoding Javascript objects
33 * into binary, wire-format protocol buffers (in the form of Uint8Arrays) that
34 * a server can consume directly.
35 *
36 * jspb's BinaryWriter class defines methods for efficiently encoding
37 * Javascript objects into binary, wire-format protocol buffers and supports
38 * all the fundamental field types used in protocol buffers.
39 *
40 * Major caveat 1 - Users of this library _must_ keep their Javascript proto
41 * parsing code in sync with the original .proto file - presumably you'll be
42 * using the typed jspb code generator, but if you bypass that you'll need
43 * to keep things in sync by hand.
44 *
45 * Major caveat 2 - Javascript is unable to accurately represent integers
46 * larger than 2^53 due to its use of a double-precision floating point format
47 * for all numbers. BinaryWriter does not make any special effort to preserve
48 * precision for values above this limit - if you need to pass 64-bit integers
49 * (hash codes, for example) between the client and server without precision
50 * loss, do _not_ use this library.
51 *
52 * Major caveat 3 - This class uses typed arrays and must not be used on older
53 * browsers that do not support them.
54 *
55 * @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
56 * @author aappleby@google.com (Austin Appleby)
57 */
58
59goog.provide('jspb.BinaryWriter');
60
61goog.require('goog.asserts');
62goog.require('goog.crypt.base64');
63goog.require('jspb.BinaryConstants');
64goog.require('jspb.BinaryEncoder');
65goog.require('jspb.arith.Int64');
66goog.require('jspb.arith.UInt64');
67goog.require('jspb.utils');
68
69
70
71/**
72 * BinaryWriter implements encoders for all the wire types specified in
73 * https://developers.google.com/protocol-buffers/docs/encoding.
74 *
75 * @constructor
76 * @struct
77 */
78jspb.BinaryWriter = function() {
79  /**
80   * Blocks of serialized data that will be concatenated once all messages have
81   * been written.
82   * @private {!Array<!Uint8Array|!Array<number>>}
83   */
84  this.blocks_ = [];
85
86  /**
87   * Total number of bytes in the blocks_ array. Does _not_ include bytes in
88   * the encoder below.
89   * @private {number}
90   */
91  this.totalLength_ = 0;
92
93  /**
94   * Binary encoder holding pieces of a message that we're still serializing.
95   * When we get to a stopping point (either the start of a new submessage, or
96   * when we need to append a raw Uint8Array), the encoder's buffer will be
97   * added to the block array above and the encoder will be reset.
98   * @private {!jspb.BinaryEncoder}
99   */
100  this.encoder_ = new jspb.BinaryEncoder();
101
102  /**
103   * A stack of bookmarks containing the parent blocks for each message started
104   * via beginSubMessage(), needed as bookkeeping for endSubMessage().
105   * TODO(aappleby): Deprecated, users should be calling writeMessage().
106   * @private {!Array<!Array<number>>}
107   */
108  this.bookmarks_ = [];
109};
110
111
112/**
113 * Append a typed array of bytes onto the buffer.
114 *
115 * @param {!Uint8Array} arr The byte array to append.
116 * @private
117 */
118jspb.BinaryWriter.prototype.appendUint8Array_ = function(arr) {
119  var temp = this.encoder_.end();
120  this.blocks_.push(temp);
121  this.blocks_.push(arr);
122  this.totalLength_ += temp.length + arr.length;
123};
124
125
126/**
127 * Begins a new message by writing the field header and returning a bookmark
128 * which we will use to patch in the message length to in endDelimited_ below.
129 * @param {number} field
130 * @return {!Array<number>}
131 * @private
132 */
133jspb.BinaryWriter.prototype.beginDelimited_ = function(field) {
134  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
135  var bookmark = this.encoder_.end();
136  this.blocks_.push(bookmark);
137  this.totalLength_ += bookmark.length;
138  bookmark.push(this.totalLength_);
139  return bookmark;
140};
141
142
143/**
144 * Ends a message by encoding the _change_ in length of the buffer to the
145 * parent block and adds the number of bytes needed to encode that length to
146 * the total byte length.
147 * @param {!Array<number>} bookmark
148 * @private
149 */
150jspb.BinaryWriter.prototype.endDelimited_ = function(bookmark) {
151  var oldLength = bookmark.pop();
152  var messageLength = this.totalLength_ + this.encoder_.length() - oldLength;
153  goog.asserts.assert(messageLength >= 0);
154
155  while (messageLength > 127) {
156    bookmark.push((messageLength & 0x7f) | 0x80);
157    messageLength = messageLength >>> 7;
158    this.totalLength_++;
159  }
160
161  bookmark.push(messageLength);
162  this.totalLength_++;
163};
164
165
166/**
167 * Writes a pre-serialized message to the buffer.
168 * @param {!Uint8Array} bytes The array of bytes to write.
169 * @param {number} start The start of the range to write.
170 * @param {number} end The end of the range to write.
171 */
172jspb.BinaryWriter.prototype.writeSerializedMessage = function(
173    bytes, start, end) {
174  this.appendUint8Array_(bytes.subarray(start, end));
175};
176
177
178/**
179 * Writes a pre-serialized message to the buffer if the message and endpoints
180 * are non-null.
181 * @param {?Uint8Array} bytes The array of bytes to write.
182 * @param {?number} start The start of the range to write.
183 * @param {?number} end The end of the range to write.
184 */
185jspb.BinaryWriter.prototype.maybeWriteSerializedMessage = function(
186    bytes, start, end) {
187  if (bytes != null && start != null && end != null) {
188    this.writeSerializedMessage(bytes, start, end);
189  }
190};
191
192
193/**
194 * Resets the writer, throwing away any accumulated buffers.
195 */
196jspb.BinaryWriter.prototype.reset = function() {
197  this.blocks_ = [];
198  this.encoder_.end();
199  this.totalLength_ = 0;
200  this.bookmarks_ = [];
201};
202
203
204/**
205 * Converts the encoded data into a Uint8Array.
206 * @return {!Uint8Array}
207 */
208jspb.BinaryWriter.prototype.getResultBuffer = function() {
209  goog.asserts.assert(this.bookmarks_.length == 0);
210
211  var flat = new Uint8Array(this.totalLength_ + this.encoder_.length());
212
213  var blocks = this.blocks_;
214  var blockCount = blocks.length;
215  var offset = 0;
216
217  for (var i = 0; i < blockCount; i++) {
218    var block = blocks[i];
219    flat.set(block, offset);
220    offset += block.length;
221  }
222
223  var tail = this.encoder_.end();
224  flat.set(tail, offset);
225  offset += tail.length;
226
227  // Post condition: `flattened` must have had every byte written.
228  goog.asserts.assert(offset == flat.length);
229
230  // Replace our block list with the flattened block, which lets GC reclaim
231  // the temp blocks sooner.
232  this.blocks_ = [flat];
233
234  return flat;
235};
236
237
238/**
239 * Converts the encoded data into a base64-encoded string.
240 * @param {!goog.crypt.base64.Alphabet=} alphabet Which flavor of base64 to use.
241 * @return {string}
242 */
243jspb.BinaryWriter.prototype.getResultBase64String = function(alphabet) {
244  return goog.crypt.base64.encodeByteArray(this.getResultBuffer(), alphabet);
245};
246
247
248/**
249 * Begins a new sub-message. The client must call endSubMessage() when they're
250 * done.
251 * TODO(aappleby): Deprecated. Move callers to writeMessage().
252 * @param {number} field The field number of the sub-message.
253 */
254jspb.BinaryWriter.prototype.beginSubMessage = function(field) {
255  this.bookmarks_.push(this.beginDelimited_(field));
256};
257
258
259/**
260 * Finishes a sub-message and packs it into the parent messages' buffer.
261 * TODO(aappleby): Deprecated. Move callers to writeMessage().
262 */
263jspb.BinaryWriter.prototype.endSubMessage = function() {
264  goog.asserts.assert(this.bookmarks_.length >= 0);
265  this.endDelimited_(this.bookmarks_.pop());
266};
267
268
269/**
270 * Encodes a (field number, wire type) tuple into a wire-format field header
271 * and stores it in the buffer as a varint.
272 * @param {number} field The field number.
273 * @param {number} wireType The wire-type of the field, as specified in the
274 *     protocol buffer documentation.
275 * @private
276 */
277jspb.BinaryWriter.prototype.writeFieldHeader_ =
278    function(field, wireType) {
279  goog.asserts.assert(field >= 1 && field == Math.floor(field));
280  var x = field * 8 + wireType;
281  this.encoder_.writeUnsignedVarint32(x);
282};
283
284
285/**
286 * Writes a field of any valid scalar type to the binary stream.
287 * @param {jspb.BinaryConstants.FieldType} fieldType
288 * @param {number} field
289 * @param {jspb.AnyFieldType} value
290 */
291jspb.BinaryWriter.prototype.writeAny = function(fieldType, field, value) {
292  var fieldTypes = jspb.BinaryConstants.FieldType;
293  switch (fieldType) {
294    case fieldTypes.DOUBLE:
295      this.writeDouble(field, /** @type {number} */(value));
296      return;
297    case fieldTypes.FLOAT:
298      this.writeFloat(field, /** @type {number} */(value));
299      return;
300    case fieldTypes.INT64:
301      this.writeInt64(field, /** @type {number} */(value));
302      return;
303    case fieldTypes.UINT64:
304      this.writeUint64(field, /** @type {number} */(value));
305      return;
306    case fieldTypes.INT32:
307      this.writeInt32(field, /** @type {number} */(value));
308      return;
309    case fieldTypes.FIXED64:
310      this.writeFixed64(field, /** @type {number} */(value));
311      return;
312    case fieldTypes.FIXED32:
313      this.writeFixed32(field, /** @type {number} */(value));
314      return;
315    case fieldTypes.BOOL:
316      this.writeBool(field, /** @type {boolean} */(value));
317      return;
318    case fieldTypes.STRING:
319      this.writeString(field, /** @type {string} */(value));
320      return;
321    case fieldTypes.GROUP:
322      goog.asserts.fail('Group field type not supported in writeAny()');
323      return;
324    case fieldTypes.MESSAGE:
325      goog.asserts.fail('Message field type not supported in writeAny()');
326      return;
327    case fieldTypes.BYTES:
328      this.writeBytes(field, /** @type {?Uint8Array} */(value));
329      return;
330    case fieldTypes.UINT32:
331      this.writeUint32(field, /** @type {number} */(value));
332      return;
333    case fieldTypes.ENUM:
334      this.writeEnum(field, /** @type {number} */(value));
335      return;
336    case fieldTypes.SFIXED32:
337      this.writeSfixed32(field, /** @type {number} */(value));
338      return;
339    case fieldTypes.SFIXED64:
340      this.writeSfixed64(field, /** @type {number} */(value));
341      return;
342    case fieldTypes.SINT32:
343      this.writeSint32(field, /** @type {number} */(value));
344      return;
345    case fieldTypes.SINT64:
346      this.writeSint64(field, /** @type {number} */(value));
347      return;
348    case fieldTypes.FHASH64:
349      this.writeFixedHash64(field, /** @type {string} */(value));
350      return;
351    case fieldTypes.VHASH64:
352      this.writeVarintHash64(field, /** @type {string} */(value));
353      return;
354    default:
355      goog.asserts.fail('Invalid field type in writeAny()');
356      return;
357  }
358};
359
360
361/**
362 * Writes a varint field to the buffer without range checking.
363 * @param {number} field The field number.
364 * @param {number?} value The value to write.
365 * @private
366 */
367jspb.BinaryWriter.prototype.writeUnsignedVarint32_ = function(field, value) {
368  if (value == null) return;
369  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
370  this.encoder_.writeUnsignedVarint32(value);
371};
372
373
374/**
375 * Writes a varint field to the buffer without range checking.
376 * @param {number} field The field number.
377 * @param {number?} value The value to write.
378 * @private
379 */
380jspb.BinaryWriter.prototype.writeSignedVarint32_ = function(field, value) {
381  if (value == null) return;
382  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
383  this.encoder_.writeSignedVarint32(value);
384};
385
386
387/**
388 * Writes a varint field to the buffer without range checking.
389 * @param {number} field The field number.
390 * @param {number?} value The value to write.
391 * @private
392 */
393jspb.BinaryWriter.prototype.writeUnsignedVarint64_ = function(field, value) {
394  if (value == null) return;
395  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
396  this.encoder_.writeUnsignedVarint64(value);
397};
398
399
400/**
401 * Writes a varint field to the buffer without range checking.
402 * @param {number} field The field number.
403 * @param {number?} value The value to write.
404 * @private
405 */
406jspb.BinaryWriter.prototype.writeSignedVarint64_ = function(field, value) {
407  if (value == null) return;
408  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
409  this.encoder_.writeSignedVarint64(value);
410};
411
412
413/**
414 * Writes a zigzag varint field to the buffer without range checking.
415 * @param {number} field The field number.
416 * @param {number?} value The value to write.
417 * @private
418 */
419jspb.BinaryWriter.prototype.writeZigzagVarint32_ = function(field, value) {
420  if (value == null) return;
421  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
422  this.encoder_.writeZigzagVarint32(value);
423};
424
425
426/**
427 * Writes a zigzag varint field to the buffer without range checking.
428 * @param {number} field The field number.
429 * @param {number?} value The value to write.
430 * @private
431 */
432jspb.BinaryWriter.prototype.writeZigzagVarint64_ = function(field, value) {
433  if (value == null) return;
434  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
435  this.encoder_.writeZigzagVarint64(value);
436};
437
438
439/**
440 * Writes a zigzag varint field to the buffer without range checking.
441 * @param {number} field The field number.
442 * @param {string?} value The value to write.
443 * @private
444 */
445jspb.BinaryWriter.prototype.writeZigzagVarint64String_ = function(
446    field, value) {
447  if (value == null) return;
448  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
449  this.encoder_.writeZigzagVarint64String(value);
450};
451
452
453/**
454 * Writes a zigzag varint field to the buffer without range checking.
455 * @param {number} field The field number.
456 * @param {string?} value The value to write.
457 * @private
458 */
459jspb.BinaryWriter.prototype.writeZigzagVarintHash64_ = function(field, value) {
460  if (value == null) return;
461  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
462  this.encoder_.writeZigzagVarintHash64(value);
463};
464
465
466/**
467 * Writes an int32 field to the buffer. Numbers outside the range [-2^31,2^31)
468 * will be truncated.
469 * @param {number} field The field number.
470 * @param {number?} value The value to write.
471 */
472jspb.BinaryWriter.prototype.writeInt32 = function(field, value) {
473  if (value == null) return;
474  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
475                      (value < jspb.BinaryConstants.TWO_TO_31));
476  this.writeSignedVarint32_(field, value);
477};
478
479
480/**
481 * Writes an int32 field represented as a string to the buffer. Numbers outside
482 * the range [-2^31,2^31) will be truncated.
483 * @param {number} field The field number.
484 * @param {string?} value The value to write.
485 */
486jspb.BinaryWriter.prototype.writeInt32String = function(field, value) {
487  if (value == null) return;
488  var intValue = /** {number} */ parseInt(value, 10);
489  goog.asserts.assert((intValue >= -jspb.BinaryConstants.TWO_TO_31) &&
490                      (intValue < jspb.BinaryConstants.TWO_TO_31));
491  this.writeSignedVarint32_(field, intValue);
492};
493
494
495/**
496 * Writes an int64 field to the buffer. Numbers outside the range [-2^63,2^63)
497 * will be truncated.
498 * @param {number} field The field number.
499 * @param {number?} value The value to write.
500 */
501jspb.BinaryWriter.prototype.writeInt64 = function(field, value) {
502  if (value == null) return;
503  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
504                      (value < jspb.BinaryConstants.TWO_TO_63));
505  this.writeSignedVarint64_(field, value);
506};
507
508
509/**
510 * Writes a int64 field (with value as a string) to the buffer.
511 * @param {number} field The field number.
512 * @param {string?} value The value to write.
513 */
514jspb.BinaryWriter.prototype.writeInt64String = function(field, value) {
515  if (value == null) return;
516  var num = jspb.arith.Int64.fromString(value);
517  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
518  this.encoder_.writeSplitVarint64(num.lo, num.hi);
519};
520
521
522/**
523 * Writes a uint32 field to the buffer. Numbers outside the range [0,2^32)
524 * will be truncated.
525 * @param {number} field The field number.
526 * @param {number?} value The value to write.
527 */
528jspb.BinaryWriter.prototype.writeUint32 = function(field, value) {
529  if (value == null) return;
530  goog.asserts.assert((value >= 0) &&
531                      (value < jspb.BinaryConstants.TWO_TO_32));
532  this.writeUnsignedVarint32_(field, value);
533};
534
535
536/**
537 * Writes a uint32 field represented as a string to the buffer. Numbers outside
538 * the range [0,2^32) will be truncated.
539 * @param {number} field The field number.
540 * @param {string?} value The value to write.
541 */
542jspb.BinaryWriter.prototype.writeUint32String = function(field, value) {
543  if (value == null) return;
544  var intValue = /** {number} */ parseInt(value, 10);
545  goog.asserts.assert((intValue >= 0) &&
546                      (intValue < jspb.BinaryConstants.TWO_TO_32));
547  this.writeUnsignedVarint32_(field, intValue);
548};
549
550
551/**
552 * Writes a uint64 field to the buffer. Numbers outside the range [0,2^64)
553 * will be truncated.
554 * @param {number} field The field number.
555 * @param {number?} value The value to write.
556 */
557jspb.BinaryWriter.prototype.writeUint64 = function(field, value) {
558  if (value == null) return;
559  goog.asserts.assert((value >= 0) &&
560                      (value < jspb.BinaryConstants.TWO_TO_64));
561  this.writeUnsignedVarint64_(field, value);
562};
563
564
565/**
566 * Writes a uint64 field (with value as a string) to the buffer.
567 * @param {number} field The field number.
568 * @param {string?} value The value to write.
569 */
570jspb.BinaryWriter.prototype.writeUint64String = function(field, value) {
571  if (value == null) return;
572  var num = jspb.arith.UInt64.fromString(value);
573  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
574  this.encoder_.writeSplitVarint64(num.lo, num.hi);
575};
576
577
578/**
579 * Writes an sint32 field to the buffer. Numbers outside the range [-2^31,2^31)
580 * will be truncated.
581 * @param {number} field The field number.
582 * @param {number?} value The value to write.
583 */
584jspb.BinaryWriter.prototype.writeSint32 = function(field, value) {
585  if (value == null) return;
586  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
587                      (value < jspb.BinaryConstants.TWO_TO_31));
588  this.writeZigzagVarint32_(field, value);
589};
590
591
592/**
593 * Writes an sint64 field to the buffer. Numbers outside the range [-2^63,2^63)
594 * will be truncated.
595 * @param {number} field The field number.
596 * @param {number?} value The value to write.
597 */
598jspb.BinaryWriter.prototype.writeSint64 = function(field, value) {
599  if (value == null) return;
600  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
601                      (value < jspb.BinaryConstants.TWO_TO_63));
602  this.writeZigzagVarint64_(field, value);
603};
604
605
606/**
607 * Writes an sint64 field to the buffer from a hash64 encoded value. Numbers
608 * outside the range [-2^63,2^63) will be truncated.
609 * @param {number} field The field number.
610 * @param {string?} value The hash64 string to write.
611 */
612jspb.BinaryWriter.prototype.writeSintHash64 = function(field, value) {
613  if (value == null) return;
614  this.writeZigzagVarintHash64_(field, value);
615};
616
617
618/**
619 * Writes an sint64 field to the buffer. Numbers outside the range [-2^63,2^63)
620 * will be truncated.
621 * @param {number} field The field number.
622 * @param {string?} value The decimal string to write.
623 */
624jspb.BinaryWriter.prototype.writeSint64String = function(field, value) {
625  if (value == null) return;
626  this.writeZigzagVarint64String_(field, value);
627};
628
629
630/**
631 * Writes a fixed32 field to the buffer. Numbers outside the range [0,2^32)
632 * will be truncated.
633 * @param {number} field The field number.
634 * @param {number?} value The value to write.
635 */
636jspb.BinaryWriter.prototype.writeFixed32 = function(field, value) {
637  if (value == null) return;
638  goog.asserts.assert((value >= 0) &&
639                      (value < jspb.BinaryConstants.TWO_TO_32));
640  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
641  this.encoder_.writeUint32(value);
642};
643
644
645/**
646 * Writes a fixed64 field to the buffer. Numbers outside the range [0,2^64)
647 * will be truncated.
648 * @param {number} field The field number.
649 * @param {number?} value The value to write.
650 */
651jspb.BinaryWriter.prototype.writeFixed64 = function(field, value) {
652  if (value == null) return;
653  goog.asserts.assert((value >= 0) &&
654                      (value < jspb.BinaryConstants.TWO_TO_64));
655  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
656  this.encoder_.writeUint64(value);
657};
658
659
660/**
661 * Writes a fixed64 field (with value as a string) to the buffer.
662 * @param {number} field The field number.
663 * @param {string?} value The value to write.
664 */
665jspb.BinaryWriter.prototype.writeFixed64String = function(field, value) {
666  if (value == null) return;
667  var num = jspb.arith.UInt64.fromString(value);
668  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
669  this.encoder_.writeSplitFixed64(num.lo, num.hi);
670};
671
672
673/**
674 * Writes a sfixed32 field to the buffer. Numbers outside the range
675 * [-2^31,2^31) will be truncated.
676 * @param {number} field The field number.
677 * @param {number?} value The value to write.
678 */
679jspb.BinaryWriter.prototype.writeSfixed32 = function(field, value) {
680  if (value == null) return;
681  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
682                      (value < jspb.BinaryConstants.TWO_TO_31));
683  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
684  this.encoder_.writeInt32(value);
685};
686
687
688/**
689 * Writes a sfixed64 field to the buffer. Numbers outside the range
690 * [-2^63,2^63) will be truncated.
691 * @param {number} field The field number.
692 * @param {number?} value The value to write.
693 */
694jspb.BinaryWriter.prototype.writeSfixed64 = function(field, value) {
695  if (value == null) return;
696  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
697                      (value < jspb.BinaryConstants.TWO_TO_63));
698  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
699  this.encoder_.writeInt64(value);
700};
701
702
703/**
704 * Writes a sfixed64 string field to the buffer. Numbers outside the range
705 * [-2^63,2^63) will be truncated.
706 * @param {number} field The field number.
707 * @param {string?} value The value to write.
708 */
709jspb.BinaryWriter.prototype.writeSfixed64String = function(field, value) {
710  if (value == null) return;
711  var num = jspb.arith.Int64.fromString(value);
712  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
713  this.encoder_.writeSplitFixed64(num.lo, num.hi);
714};
715
716
717/**
718 * Writes a single-precision floating point field to the buffer. Numbers
719 * requiring more than 32 bits of precision will be truncated.
720 * @param {number} field The field number.
721 * @param {number?} value The value to write.
722 */
723jspb.BinaryWriter.prototype.writeFloat = function(field, value) {
724  if (value == null) return;
725  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
726  this.encoder_.writeFloat(value);
727};
728
729
730/**
731 * Writes a double-precision floating point field to the buffer. As this is the
732 * native format used by JavaScript, no precision will be lost.
733 * @param {number} field The field number.
734 * @param {number?} value The value to write.
735 */
736jspb.BinaryWriter.prototype.writeDouble = function(field, value) {
737  if (value == null) return;
738  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
739  this.encoder_.writeDouble(value);
740};
741
742
743/**
744 * Writes a boolean field to the buffer. We allow numbers as input
745 * because the JSPB code generator uses 0/1 instead of true/false to save space
746 * in the string representation of the proto.
747 * @param {number} field The field number.
748 * @param {boolean?|number?} value The value to write.
749 */
750jspb.BinaryWriter.prototype.writeBool = function(field, value) {
751  if (value == null) return;
752  goog.asserts.assert(typeof value === 'boolean' || typeof value === 'number');
753  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
754  this.encoder_.writeBool(value);
755};
756
757
758/**
759 * Writes an enum field to the buffer.
760 * @param {number} field The field number.
761 * @param {number?} value The value to write.
762 */
763jspb.BinaryWriter.prototype.writeEnum = function(field, value) {
764  if (value == null) return;
765  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
766                      (value < jspb.BinaryConstants.TWO_TO_31));
767  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
768  this.encoder_.writeSignedVarint32(value);
769};
770
771
772/**
773 * Writes a string field to the buffer.
774 * @param {number} field The field number.
775 * @param {string?} value The string to write.
776 */
777jspb.BinaryWriter.prototype.writeString = function(field, value) {
778  if (value == null) return;
779  var bookmark = this.beginDelimited_(field);
780  this.encoder_.writeString(value);
781  this.endDelimited_(bookmark);
782};
783
784
785/**
786 * Writes an arbitrary byte field to the buffer. Note - to match the behavior
787 * of the C++ implementation, empty byte arrays _are_ serialized.
788 * @param {number} field The field number.
789 * @param {?jspb.ByteSource} value The array of bytes to write.
790 */
791jspb.BinaryWriter.prototype.writeBytes = function(field, value) {
792  if (value == null) return;
793  var bytes = jspb.utils.byteSourceToUint8Array(value);
794  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
795  this.encoder_.writeUnsignedVarint32(bytes.length);
796  this.appendUint8Array_(bytes);
797};
798
799
800/**
801 * Writes a message to the buffer.
802 * @param {number} field The field number.
803 * @param {?MessageType} value The message to write.
804 * @param {function(MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
805 *     Will be invoked with the value to write and the writer to write it with.
806 * @template MessageType
807 * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
808 * the null in blah|null with none.  This is necessary because the compiler will
809 * infer MessageType to be nullable if the value parameter is nullable.
810 * @template MessageTypeNonNull :=
811 *     cond(isUnknown(MessageType), unknown(),
812 *       mapunion(MessageType, (X) =>
813 *         cond(eq(X, 'null'), none(), X)))
814 * =:
815 */
816jspb.BinaryWriter.prototype.writeMessage = function(
817    field, value, writerCallback) {
818  if (value == null) return;
819  var bookmark = this.beginDelimited_(field);
820  writerCallback(value, this);
821  this.endDelimited_(bookmark);
822};
823
824
825/**
826 * Writes a message set extension to the buffer.
827 * @param {number} field The field number for the extension.
828 * @param {?MessageType} value The extension message object to write. Note that
829 *     message set can only have extensions with type of optional message.
830 * @param {function(!MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
831 *     Will be invoked with the value to write and the writer to write it with.
832 * @template MessageType
833 * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
834 * the null in blah|null with none.  This is necessary because the compiler will
835 * infer MessageType to be nullable if the value parameter is nullable.
836 * @template MessageTypeNonNull :=
837 *     cond(isUnknown(MessageType), unknown(),
838 *       mapunion(MessageType, (X) =>
839 *         cond(eq(X, 'null'), none(), X)))
840 * =:
841 */
842jspb.BinaryWriter.prototype.writeMessageSet = function(
843    field, value, writerCallback) {
844  if (value == null) return;
845  // The wire format for a message set is defined by
846  // google3/net/proto/message_set.proto
847  this.writeFieldHeader_(1, jspb.BinaryConstants.WireType.START_GROUP);
848  this.writeFieldHeader_(2, jspb.BinaryConstants.WireType.VARINT);
849  this.encoder_.writeSignedVarint32(field);
850  var bookmark = this.beginDelimited_(3);
851  writerCallback(value, this);
852  this.endDelimited_(bookmark);
853  this.writeFieldHeader_(1, jspb.BinaryConstants.WireType.END_GROUP);
854};
855
856
857/**
858 * Writes a group message to the buffer.
859 *
860 * @param {number} field The field number.
861 * @param {?MessageType} value The message to write, wrapped with START_GROUP /
862 *     END_GROUP tags. Will be a no-op if 'value' is null.
863 * @param {function(MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
864 *     Will be invoked with the value to write and the writer to write it with.
865 * @template MessageType
866 * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
867 * the null in blah|null with none.  This is necessary because the compiler will
868 * infer MessageType to be nullable if the value parameter is nullable.
869 * @template MessageTypeNonNull :=
870 *     cond(isUnknown(MessageType), unknown(),
871 *       mapunion(MessageType, (X) =>
872 *         cond(eq(X, 'null'), none(), X)))
873 * =:
874 */
875jspb.BinaryWriter.prototype.writeGroup = function(
876    field, value, writerCallback) {
877  if (value == null) return;
878  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP);
879  writerCallback(value, this);
880  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP);
881};
882
883
884/**
885 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
886 * the buffer.
887 * @param {number} field The field number.
888 * @param {string?} value The hash string.
889 */
890jspb.BinaryWriter.prototype.writeFixedHash64 = function(field, value) {
891  if (value == null) return;
892  goog.asserts.assert(value.length == 8);
893  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
894  this.encoder_.writeFixedHash64(value);
895};
896
897
898/**
899 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
900 * the buffer.
901 * @param {number} field The field number.
902 * @param {string?} value The hash string.
903 */
904jspb.BinaryWriter.prototype.writeVarintHash64 = function(field, value) {
905  if (value == null) return;
906  goog.asserts.assert(value.length == 8);
907  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
908  this.encoder_.writeVarintHash64(value);
909};
910
911
912/**
913 * Writes a 64-bit field to the buffer as a fixed64.
914 * @param {number} field The field number.
915 * @param {number} lowBits The low 32 bits.
916 * @param {number} highBits The high 32 bits.
917 */
918jspb.BinaryWriter.prototype.writeSplitFixed64 = function(
919    field, lowBits, highBits) {
920  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
921  this.encoder_.writeSplitFixed64(lowBits, highBits);
922};
923
924
925/**
926 * Writes a 64-bit field to the buffer as a varint.
927 * @param {number} field The field number.
928 * @param {number} lowBits The low 32 bits.
929 * @param {number} highBits The high 32 bits.
930 */
931jspb.BinaryWriter.prototype.writeSplitVarint64 = function(
932    field, lowBits, highBits) {
933  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
934  this.encoder_.writeSplitVarint64(lowBits, highBits);
935};
936
937
938/**
939 * Writes a 64-bit field to the buffer as a zigzag encoded varint.
940 * @param {number} field The field number.
941 * @param {number} lowBits The low 32 bits.
942 * @param {number} highBits The high 32 bits.
943 */
944jspb.BinaryWriter.prototype.writeSplitZigzagVarint64 = function(
945    field, lowBits, highBits) {
946  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
947  var encoder = this.encoder_;
948  jspb.utils.toZigzag64(lowBits, highBits, function(lowBits, highBits) {
949    encoder.writeSplitVarint64(lowBits >>> 0, highBits >>> 0);
950  });
951};
952
953
954/**
955 * Writes an array of numbers to the buffer as a repeated 32-bit int field.
956 * @param {number} field The field number.
957 * @param {?Array<number>} value The array of ints to write.
958 */
959jspb.BinaryWriter.prototype.writeRepeatedInt32 = function(field, value) {
960  if (value == null) return;
961  for (var i = 0; i < value.length; i++) {
962    this.writeSignedVarint32_(field, value[i]);
963  }
964};
965
966
967/**
968 * Writes an array of numbers formatted as strings to the buffer as a repeated
969 * 32-bit int field.
970 * @param {number} field The field number.
971 * @param {?Array<string>} value The array of ints to write.
972 */
973jspb.BinaryWriter.prototype.writeRepeatedInt32String = function(field, value) {
974  if (value == null) return;
975  for (var i = 0; i < value.length; i++) {
976    this.writeInt32String(field, value[i]);
977  }
978};
979
980
981/**
982 * Writes an array of numbers to the buffer as a repeated 64-bit int field.
983 * @param {number} field The field number.
984 * @param {?Array<number>} value The array of ints to write.
985 */
986jspb.BinaryWriter.prototype.writeRepeatedInt64 = function(field, value) {
987  if (value == null) return;
988  for (var i = 0; i < value.length; i++) {
989    this.writeSignedVarint64_(field, value[i]);
990  }
991};
992
993
994/**
995 * Writes an array of 64-bit values to the buffer as a fixed64.
996 * @param {number} field The field number.
997 * @param {?Array<T>} value The value.
998 * @param {function(T): number} lo Function to get low bits.
999 * @param {function(T): number} hi Function to get high bits.
1000 * @template T
1001 */
1002jspb.BinaryWriter.prototype.writeRepeatedSplitFixed64 = function(
1003    field, value, lo, hi) {
1004  if (value == null) return;
1005  for (var i = 0; i < value.length; i++) {
1006    this.writeSplitFixed64(field, lo(value[i]), hi(value[i]));
1007  }
1008};
1009
1010
1011/**
1012 * Writes an array of 64-bit values to the buffer as a varint.
1013 * @param {number} field The field number.
1014 * @param {?Array<T>} value The value.
1015 * @param {function(T): number} lo Function to get low bits.
1016 * @param {function(T): number} hi Function to get high bits.
1017 * @template T
1018 */
1019jspb.BinaryWriter.prototype.writeRepeatedSplitVarint64 = function(
1020    field, value, lo, hi) {
1021  if (value == null) return;
1022  for (var i = 0; i < value.length; i++) {
1023    this.writeSplitVarint64(field, lo(value[i]), hi(value[i]));
1024  }
1025};
1026
1027
1028/**
1029 * Writes an array of 64-bit values to the buffer as a zigzag varint.
1030 * @param {number} field The field number.
1031 * @param {?Array<T>} value The value.
1032 * @param {function(T): number} lo Function to get low bits.
1033 * @param {function(T): number} hi Function to get high bits.
1034 * @template T
1035 */
1036jspb.BinaryWriter.prototype.writeRepeatedSplitZigzagVarint64 = function(
1037    field, value, lo, hi) {
1038  if (value == null) return;
1039  for (var i = 0; i < value.length; i++) {
1040    this.writeSplitZigzagVarint64(field, lo(value[i]), hi(value[i]));
1041  }
1042};
1043
1044
1045/**
1046 * Writes an array of numbers formatted as strings to the buffer as a repeated
1047 * 64-bit int field.
1048 * @param {number} field The field number.
1049 * @param {?Array<string>} value The array of ints to write.
1050 */
1051jspb.BinaryWriter.prototype.writeRepeatedInt64String = function(field, value) {
1052  if (value == null) return;
1053  for (var i = 0; i < value.length; i++) {
1054    this.writeInt64String(field, value[i]);
1055  }
1056};
1057
1058
1059/**
1060 * Writes an array numbers to the buffer as a repeated unsigned 32-bit int
1061 *     field.
1062 * @param {number} field The field number.
1063 * @param {?Array<number>} value The array of ints to write.
1064 */
1065jspb.BinaryWriter.prototype.writeRepeatedUint32 = function(field, value) {
1066  if (value == null) return;
1067  for (var i = 0; i < value.length; i++) {
1068    this.writeUnsignedVarint32_(field, value[i]);
1069  }
1070};
1071
1072
1073/**
1074 * Writes an array of numbers formatted as strings to the buffer as a repeated
1075 * unsigned 32-bit int field.
1076 * @param {number} field The field number.
1077 * @param {?Array<string>} value The array of ints to write.
1078 */
1079jspb.BinaryWriter.prototype.writeRepeatedUint32String = function(field, value) {
1080  if (value == null) return;
1081  for (var i = 0; i < value.length; i++) {
1082    this.writeUint32String(field, value[i]);
1083  }
1084};
1085
1086
1087/**
1088 * Writes an array numbers to the buffer as a repeated unsigned 64-bit int
1089 *     field.
1090 * @param {number} field The field number.
1091 * @param {?Array<number>} value The array of ints to write.
1092 */
1093jspb.BinaryWriter.prototype.writeRepeatedUint64 = function(field, value) {
1094  if (value == null) return;
1095  for (var i = 0; i < value.length; i++) {
1096    this.writeUnsignedVarint64_(field, value[i]);
1097  }
1098};
1099
1100
1101/**
1102 * Writes an array of numbers formatted as strings to the buffer as a repeated
1103 * unsigned 64-bit int field.
1104 * @param {number} field The field number.
1105 * @param {?Array<string>} value The array of ints to write.
1106 */
1107jspb.BinaryWriter.prototype.writeRepeatedUint64String = function(field, value) {
1108  if (value == null) return;
1109  for (var i = 0; i < value.length; i++) {
1110    this.writeUint64String(field, value[i]);
1111  }
1112};
1113
1114
1115/**
1116 * Writes an array numbers to the buffer as a repeated signed 32-bit int field.
1117 * @param {number} field The field number.
1118 * @param {?Array<number>} value The array of ints to write.
1119 */
1120jspb.BinaryWriter.prototype.writeRepeatedSint32 = function(field, value) {
1121  if (value == null) return;
1122  for (var i = 0; i < value.length; i++) {
1123    this.writeZigzagVarint32_(field, value[i]);
1124  }
1125};
1126
1127
1128/**
1129 * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
1130 * @param {number} field The field number.
1131 * @param {?Array<number>} value The array of ints to write.
1132 */
1133jspb.BinaryWriter.prototype.writeRepeatedSint64 = function(field, value) {
1134  if (value == null) return;
1135  for (var i = 0; i < value.length; i++) {
1136    this.writeZigzagVarint64_(field, value[i]);
1137  }
1138};
1139
1140
1141/**
1142 * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
1143 * @param {number} field The field number.
1144 * @param {?Array<string>} value The array of ints to write.
1145 */
1146jspb.BinaryWriter.prototype.writeRepeatedSint64String = function(field, value) {
1147  if (value == null) return;
1148  for (var i = 0; i < value.length; i++) {
1149    this.writeZigzagVarint64String_(field, value[i]);
1150  }
1151};
1152
1153
1154/**
1155 * Writes an array of hash64 strings to the buffer as a repeated signed 64-bit
1156 * int field.
1157 * @param {number} field The field number.
1158 * @param {?Array<string>} value The array of ints to write.
1159 */
1160jspb.BinaryWriter.prototype.writeRepeatedSintHash64 = function(field, value) {
1161  if (value == null) return;
1162  for (var i = 0; i < value.length; i++) {
1163    this.writeZigzagVarintHash64_(field, value[i]);
1164  }
1165};
1166
1167
1168/**
1169 * Writes an array of numbers to the buffer as a repeated fixed32 field. This
1170 * works for both signed and unsigned fixed32s.
1171 * @param {number} field The field number.
1172 * @param {?Array<number>} value The array of ints to write.
1173 */
1174jspb.BinaryWriter.prototype.writeRepeatedFixed32 = function(field, value) {
1175  if (value == null) return;
1176  for (var i = 0; i < value.length; i++) {
1177    this.writeFixed32(field, value[i]);
1178  }
1179};
1180
1181
1182/**
1183 * Writes an array of numbers to the buffer as a repeated fixed64 field. This
1184 * works for both signed and unsigned fixed64s.
1185 * @param {number} field The field number.
1186 * @param {?Array<number>} value The array of ints to write.
1187 */
1188jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(field, value) {
1189  if (value == null) return;
1190  for (var i = 0; i < value.length; i++) {
1191    this.writeFixed64(field, value[i]);
1192  }
1193};
1194
1195
1196/**
1197 * Writes an array of numbers to the buffer as a repeated fixed64 field. This
1198 * works for both signed and unsigned fixed64s.
1199 * @param {number} field The field number.
1200 * @param {?Array<string>} value The array of decimal strings to write.
1201 */
1202jspb.BinaryWriter.prototype.writeRepeatedFixed64String = function(
1203    field, value) {
1204  if (value == null) return;
1205  for (var i = 0; i < value.length; i++) {
1206    this.writeFixed64String(field, value[i]);
1207  }
1208};
1209
1210
1211/**
1212 * Writes an array of numbers to the buffer as a repeated sfixed32 field.
1213 * @param {number} field The field number.
1214 * @param {?Array<number>} value The array of ints to write.
1215 */
1216jspb.BinaryWriter.prototype.writeRepeatedSfixed32 = function(field, value) {
1217  if (value == null) return;
1218  for (var i = 0; i < value.length; i++) {
1219    this.writeSfixed32(field, value[i]);
1220  }
1221};
1222
1223
1224/**
1225 * Writes an array of numbers to the buffer as a repeated sfixed64 field.
1226 * @param {number} field The field number.
1227 * @param {?Array<number>} value The array of ints to write.
1228 */
1229jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(field, value) {
1230  if (value == null) return;
1231  for (var i = 0; i < value.length; i++) {
1232    this.writeSfixed64(field, value[i]);
1233  }
1234};
1235
1236
1237/**
1238 * Writes an array of decimal strings to the buffer as a repeated sfixed64
1239 * field.
1240 * @param {number} field The field number.
1241 * @param {?Array<string>} value The array of decimal strings to write.
1242 */
1243jspb.BinaryWriter.prototype.writeRepeatedSfixed64String = function(field, value) {
1244  if (value == null) return;
1245  for (var i = 0; i < value.length; i++) {
1246    this.writeSfixed64String(field, value[i]);
1247  }
1248};
1249
1250
1251/**
1252 * Writes an array of numbers to the buffer as a repeated float field.
1253 * @param {number} field The field number.
1254 * @param {?Array<number>} value The array of ints to write.
1255 */
1256jspb.BinaryWriter.prototype.writeRepeatedFloat = function(field, value) {
1257  if (value == null) return;
1258  for (var i = 0; i < value.length; i++) {
1259    this.writeFloat(field, value[i]);
1260  }
1261};
1262
1263
1264/**
1265 * Writes an array of numbers to the buffer as a repeated double field.
1266 * @param {number} field The field number.
1267 * @param {?Array<number>} value The array of ints to write.
1268 */
1269jspb.BinaryWriter.prototype.writeRepeatedDouble = function(field, value) {
1270  if (value == null) return;
1271  for (var i = 0; i < value.length; i++) {
1272    this.writeDouble(field, value[i]);
1273  }
1274};
1275
1276
1277/**
1278 * Writes an array of booleans to the buffer as a repeated bool field.
1279 * @param {number} field The field number.
1280 * @param {?Array<boolean>} value The array of ints to write.
1281 */
1282jspb.BinaryWriter.prototype.writeRepeatedBool = function(field, value) {
1283  if (value == null) return;
1284  for (var i = 0; i < value.length; i++) {
1285    this.writeBool(field, value[i]);
1286  }
1287};
1288
1289
1290/**
1291 * Writes an array of enums to the buffer as a repeated enum field.
1292 * @param {number} field The field number.
1293 * @param {?Array<number>} value The array of ints to write.
1294 */
1295jspb.BinaryWriter.prototype.writeRepeatedEnum = function(field, value) {
1296  if (value == null) return;
1297  for (var i = 0; i < value.length; i++) {
1298    this.writeEnum(field, value[i]);
1299  }
1300};
1301
1302
1303/**
1304 * Writes an array of strings to the buffer as a repeated string field.
1305 * @param {number} field The field number.
1306 * @param {?Array<string>} value The array of strings to write.
1307 */
1308jspb.BinaryWriter.prototype.writeRepeatedString = function(field, value) {
1309  if (value == null) return;
1310  for (var i = 0; i < value.length; i++) {
1311    this.writeString(field, value[i]);
1312  }
1313};
1314
1315
1316/**
1317 * Writes an array of arbitrary byte fields to the buffer.
1318 * @param {number} field The field number.
1319 * @param {?Array<!jspb.ByteSource>} value The arrays of arrays of bytes to
1320 *     write.
1321 */
1322jspb.BinaryWriter.prototype.writeRepeatedBytes = function(field, value) {
1323  if (value == null) return;
1324  for (var i = 0; i < value.length; i++) {
1325    this.writeBytes(field, value[i]);
1326  }
1327};
1328
1329
1330/**
1331 * Writes an array of messages to the buffer.
1332 * @template MessageType
1333 * @param {number} field The field number.
1334 * @param {?Array<MessageType>} value The array of messages to
1335 *    write.
1336 * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
1337 *     Will be invoked with the value to write and the writer to write it with.
1338 */
1339jspb.BinaryWriter.prototype.writeRepeatedMessage = function(
1340    field, value, writerCallback) {
1341  if (value == null) return;
1342  for (var i = 0; i < value.length; i++) {
1343    var bookmark = this.beginDelimited_(field);
1344    writerCallback(value[i], this);
1345    this.endDelimited_(bookmark);
1346  }
1347};
1348
1349
1350/**
1351 * Writes an array of group messages to the buffer.
1352 * @template MessageType
1353 * @param {number} field The field number.
1354 * @param {?Array<MessageType>} value The array of messages to
1355 *    write.
1356 * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
1357 *     Will be invoked with the value to write and the writer to write it with.
1358 */
1359jspb.BinaryWriter.prototype.writeRepeatedGroup = function(
1360    field, value, writerCallback) {
1361  if (value == null) return;
1362  for (var i = 0; i < value.length; i++) {
1363    this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP);
1364    writerCallback(value[i], this);
1365    this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP);
1366  }
1367};
1368
1369
1370/**
1371 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
1372 * the buffer.
1373 * @param {number} field The field number.
1374 * @param {?Array<string>} value The array of hashes to write.
1375 */
1376jspb.BinaryWriter.prototype.writeRepeatedFixedHash64 =
1377    function(field, value) {
1378  if (value == null) return;
1379  for (var i = 0; i < value.length; i++) {
1380    this.writeFixedHash64(field, value[i]);
1381  }
1382};
1383
1384
1385/**
1386 * Writes a repeated 64-bit hash string field (8 characters @ 8 bits of data
1387 * each) to the buffer.
1388 * @param {number} field The field number.
1389 * @param {?Array<string>} value The array of hashes to write.
1390 */
1391jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 =
1392    function(field, value) {
1393  if (value == null) return;
1394  for (var i = 0; i < value.length; i++) {
1395    this.writeVarintHash64(field, value[i]);
1396  }
1397};
1398
1399
1400/**
1401 * Writes an array of numbers to the buffer as a packed 32-bit int field.
1402 * @param {number} field The field number.
1403 * @param {?Array<number>} value The array of ints to write.
1404 */
1405jspb.BinaryWriter.prototype.writePackedInt32 = function(field, value) {
1406  if (value == null || !value.length) return;
1407  var bookmark = this.beginDelimited_(field);
1408  for (var i = 0; i < value.length; i++) {
1409    this.encoder_.writeSignedVarint32(value[i]);
1410  }
1411  this.endDelimited_(bookmark);
1412};
1413
1414
1415/**
1416 * Writes an array of numbers represented as strings to the buffer as a packed
1417 * 32-bit int field.
1418 * @param {number} field
1419 * @param {?Array<string>} value
1420 */
1421jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
1422  if (value == null || !value.length) return;
1423  var bookmark = this.beginDelimited_(field);
1424  for (var i = 0; i < value.length; i++) {
1425    this.encoder_.writeSignedVarint32(parseInt(value[i], 10));
1426  }
1427  this.endDelimited_(bookmark);
1428};
1429
1430
1431/**
1432 * Writes an array of numbers to the buffer as a packed 64-bit int field.
1433 * @param {number} field The field number.
1434 * @param {?Array<number>} value The array of ints to write.
1435 */
1436jspb.BinaryWriter.prototype.writePackedInt64 = function(field, value) {
1437  if (value == null || !value.length) return;
1438  var bookmark = this.beginDelimited_(field);
1439  for (var i = 0; i < value.length; i++) {
1440    this.encoder_.writeSignedVarint64(value[i]);
1441  }
1442  this.endDelimited_(bookmark);
1443};
1444
1445
1446/**
1447 * Writes an array of 64-bit values to the buffer as a fixed64.
1448 * @param {number} field The field number.
1449 * @param {?Array<T>} value The value.
1450 * @param {function(T): number} lo Function to get low bits.
1451 * @param {function(T): number} hi Function to get high bits.
1452 * @template T
1453 */
1454jspb.BinaryWriter.prototype.writePackedSplitFixed64 = function(
1455    field, value, lo, hi) {
1456  if (value == null) return;
1457  var bookmark = this.beginDelimited_(field);
1458  for (var i = 0; i < value.length; i++) {
1459    this.encoder_.writeSplitFixed64(lo(value[i]), hi(value[i]));
1460  }
1461  this.endDelimited_(bookmark);
1462};
1463
1464
1465/**
1466 * Writes an array of 64-bit values to the buffer as a varint.
1467 * @param {number} field The field number.
1468 * @param {?Array<T>} value The value.
1469 * @param {function(T): number} lo Function to get low bits.
1470 * @param {function(T): number} hi Function to get high bits.
1471 * @template T
1472 */
1473jspb.BinaryWriter.prototype.writePackedSplitVarint64 = function(
1474    field, value, lo, hi) {
1475  if (value == null) return;
1476  var bookmark = this.beginDelimited_(field);
1477  for (var i = 0; i < value.length; i++) {
1478    this.encoder_.writeSplitVarint64(lo(value[i]), hi(value[i]));
1479  }
1480  this.endDelimited_(bookmark);
1481};
1482
1483
1484/**
1485 * Writes an array of 64-bit values to the buffer as a zigzag varint.
1486 * @param {number} field The field number.
1487 * @param {?Array<T>} value The value.
1488 * @param {function(T): number} lo Function to get low bits.
1489 * @param {function(T): number} hi Function to get high bits.
1490 * @template T
1491 */
1492jspb.BinaryWriter.prototype.writePackedSplitZigzagVarint64 = function(
1493    field, value, lo, hi) {
1494  if (value == null) return;
1495  var bookmark = this.beginDelimited_(field);
1496  var encoder = this.encoder_;
1497  for (var i = 0; i < value.length; i++) {
1498    jspb.utils.toZigzag64(
1499        lo(value[i]), hi(value[i]), function(bitsLow, bitsHigh) {
1500          encoder.writeSplitVarint64(bitsLow >>> 0, bitsHigh >>> 0);
1501        });
1502  }
1503  this.endDelimited_(bookmark);
1504};
1505
1506
1507/**
1508 * Writes an array of numbers represented as strings to the buffer as a packed
1509 * 64-bit int field.
1510 * @param {number} field
1511 * @param {?Array<string>} value
1512 */
1513jspb.BinaryWriter.prototype.writePackedInt64String = function(field, value) {
1514  if (value == null || !value.length) return;
1515  var bookmark = this.beginDelimited_(field);
1516  for (var i = 0; i < value.length; i++) {
1517    var num = jspb.arith.Int64.fromString(value[i]);
1518    this.encoder_.writeSplitVarint64(num.lo, num.hi);
1519  }
1520  this.endDelimited_(bookmark);
1521};
1522
1523
1524/**
1525 * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
1526 * @param {number} field The field number.
1527 * @param {?Array<number>} value The array of ints to write.
1528 */
1529jspb.BinaryWriter.prototype.writePackedUint32 = function(field, value) {
1530  if (value == null || !value.length) return;
1531  var bookmark = this.beginDelimited_(field);
1532  for (var i = 0; i < value.length; i++) {
1533    this.encoder_.writeUnsignedVarint32(value[i]);
1534  }
1535  this.endDelimited_(bookmark);
1536};
1537
1538
1539/**
1540 * Writes an array of numbers represented as strings to the buffer as a packed
1541 * unsigned 32-bit int field.
1542 * @param {number} field
1543 * @param {?Array<string>} value
1544 */
1545jspb.BinaryWriter.prototype.writePackedUint32String =
1546    function(field, value) {
1547  if (value == null || !value.length) return;
1548  var bookmark = this.beginDelimited_(field);
1549  for (var i = 0; i < value.length; i++) {
1550    this.encoder_.writeUnsignedVarint32(parseInt(value[i], 10));
1551  }
1552  this.endDelimited_(bookmark);
1553};
1554
1555
1556/**
1557 * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
1558 * @param {number} field The field number.
1559 * @param {?Array<number>} value The array of ints to write.
1560 */
1561jspb.BinaryWriter.prototype.writePackedUint64 = function(field, value) {
1562  if (value == null || !value.length) return;
1563  var bookmark = this.beginDelimited_(field);
1564  for (var i = 0; i < value.length; i++) {
1565    this.encoder_.writeUnsignedVarint64(value[i]);
1566  }
1567  this.endDelimited_(bookmark);
1568};
1569
1570
1571/**
1572 * Writes an array of numbers represented as strings to the buffer as a packed
1573 * unsigned 64-bit int field.
1574 * @param {number} field
1575 * @param {?Array<string>} value
1576 */
1577jspb.BinaryWriter.prototype.writePackedUint64String =
1578    function(field, value) {
1579  if (value == null || !value.length) return;
1580  var bookmark = this.beginDelimited_(field);
1581  for (var i = 0; i < value.length; i++) {
1582    var num = jspb.arith.UInt64.fromString(value[i]);
1583    this.encoder_.writeSplitVarint64(num.lo, num.hi);
1584  }
1585  this.endDelimited_(bookmark);
1586};
1587
1588
1589/**
1590 * Writes an array numbers to the buffer as a packed signed 32-bit int field.
1591 * @param {number} field The field number.
1592 * @param {?Array<number>} value The array of ints to write.
1593 */
1594jspb.BinaryWriter.prototype.writePackedSint32 = function(field, value) {
1595  if (value == null || !value.length) return;
1596  var bookmark = this.beginDelimited_(field);
1597  for (var i = 0; i < value.length; i++) {
1598    this.encoder_.writeZigzagVarint32(value[i]);
1599  }
1600  this.endDelimited_(bookmark);
1601};
1602
1603
1604/**
1605 * Writes an array of numbers to the buffer as a packed signed 64-bit int field.
1606 * @param {number} field The field number.
1607 * @param {?Array<number>} value The array of ints to write.
1608 */
1609jspb.BinaryWriter.prototype.writePackedSint64 = function(field, value) {
1610  if (value == null || !value.length) return;
1611  var bookmark = this.beginDelimited_(field);
1612  for (var i = 0; i < value.length; i++) {
1613    this.encoder_.writeZigzagVarint64(value[i]);
1614  }
1615  this.endDelimited_(bookmark);
1616};
1617
1618
1619/**
1620 * Writes an array of decimal strings to the buffer as a packed signed 64-bit
1621 * int field.
1622 * @param {number} field The field number.
1623 * @param {?Array<string>} value The array of decimal strings to write.
1624 */
1625jspb.BinaryWriter.prototype.writePackedSint64String = function(field, value) {
1626  if (value == null || !value.length) return;
1627  var bookmark = this.beginDelimited_(field);
1628  for (var i = 0; i < value.length; i++) {
1629    this.encoder_.writeZigzagVarintHash64(
1630        jspb.utils.decimalStringToHash64(value[i]));
1631  }
1632  this.endDelimited_(bookmark);
1633};
1634
1635
1636/**
1637 * Writes an array of hash 64 strings to the buffer as a packed signed 64-bit
1638 * int field.
1639 * @param {number} field The field number.
1640 * @param {?Array<string>} value The array of decimal strings to write.
1641 */
1642jspb.BinaryWriter.prototype.writePackedSintHash64 = function(field, value) {
1643  if (value == null || !value.length) return;
1644  var bookmark = this.beginDelimited_(field);
1645  for (var i = 0; i < value.length; i++) {
1646    this.encoder_.writeZigzagVarintHash64(value[i]);
1647  }
1648  this.endDelimited_(bookmark);
1649};
1650
1651
1652/**
1653 * Writes an array of numbers to the buffer as a packed fixed32 field.
1654 * @param {number} field The field number.
1655 * @param {?Array<number>} value The array of ints to write.
1656 */
1657jspb.BinaryWriter.prototype.writePackedFixed32 = function(field, value) {
1658  if (value == null || !value.length) return;
1659  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1660  this.encoder_.writeUnsignedVarint32(value.length * 4);
1661  for (var i = 0; i < value.length; i++) {
1662    this.encoder_.writeUint32(value[i]);
1663  }
1664};
1665
1666
1667/**
1668 * Writes an array of numbers to the buffer as a packed fixed64 field.
1669 * @param {number} field The field number.
1670 * @param {?Array<number>} value The array of ints to write.
1671 */
1672jspb.BinaryWriter.prototype.writePackedFixed64 = function(field, value) {
1673  if (value == null || !value.length) return;
1674  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1675  this.encoder_.writeUnsignedVarint32(value.length * 8);
1676  for (var i = 0; i < value.length; i++) {
1677    this.encoder_.writeUint64(value[i]);
1678  }
1679};
1680
1681
1682/**
1683 * Writes an array of numbers represented as strings to the buffer as a packed
1684 * fixed64 field.
1685 * @param {number} field The field number.
1686 * @param {?Array<string>} value The array of strings to write.
1687 */
1688jspb.BinaryWriter.prototype.writePackedFixed64String = function(field, value) {
1689  if (value == null || !value.length) return;
1690  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1691  this.encoder_.writeUnsignedVarint32(value.length * 8);
1692  for (var i = 0; i < value.length; i++) {
1693    var num = jspb.arith.UInt64.fromString(value[i]);
1694    this.encoder_.writeSplitFixed64(num.lo, num.hi);
1695  }
1696};
1697
1698
1699/**
1700 * Writes an array of numbers to the buffer as a packed sfixed32 field.
1701 * @param {number} field The field number.
1702 * @param {?Array<number>} value The array of ints to write.
1703 */
1704jspb.BinaryWriter.prototype.writePackedSfixed32 = function(field, value) {
1705  if (value == null || !value.length) return;
1706  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1707  this.encoder_.writeUnsignedVarint32(value.length * 4);
1708  for (var i = 0; i < value.length; i++) {
1709    this.encoder_.writeInt32(value[i]);
1710  }
1711};
1712
1713
1714/**
1715 * Writes an array of numbers to the buffer as a packed sfixed64 field.
1716 * @param {number} field The field number.
1717 * @param {?Array<number>} value The array of ints to write.
1718 */
1719jspb.BinaryWriter.prototype.writePackedSfixed64 = function(field, value) {
1720  if (value == null || !value.length) return;
1721  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1722  this.encoder_.writeUnsignedVarint32(value.length * 8);
1723  for (var i = 0; i < value.length; i++) {
1724    this.encoder_.writeInt64(value[i]);
1725  }
1726};
1727
1728
1729/**
1730 * Writes an array of numbers to the buffer as a packed sfixed64 field.
1731 * @param {number} field The field number.
1732 * @param {?Array<string>} value The array of decimal strings to write.
1733 */
1734jspb.BinaryWriter.prototype.writePackedSfixed64String = function(field, value) {
1735  if (value == null || !value.length) return;
1736  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1737  this.encoder_.writeUnsignedVarint32(value.length * 8);
1738  for (var i = 0; i < value.length; i++) {
1739    this.encoder_.writeInt64String(value[i]);
1740  }
1741};
1742
1743
1744/**
1745 * Writes an array of numbers to the buffer as a packed float field.
1746 * @param {number} field The field number.
1747 * @param {?Array<number>} value The array of ints to write.
1748 */
1749jspb.BinaryWriter.prototype.writePackedFloat = function(field, value) {
1750  if (value == null || !value.length) return;
1751  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1752  this.encoder_.writeUnsignedVarint32(value.length * 4);
1753  for (var i = 0; i < value.length; i++) {
1754    this.encoder_.writeFloat(value[i]);
1755  }
1756};
1757
1758
1759/**
1760 * Writes an array of numbers to the buffer as a packed double field.
1761 * @param {number} field The field number.
1762 * @param {?Array<number>} value The array of ints to write.
1763 */
1764jspb.BinaryWriter.prototype.writePackedDouble = function(field, value) {
1765  if (value == null || !value.length) return;
1766  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1767  this.encoder_.writeUnsignedVarint32(value.length * 8);
1768  for (var i = 0; i < value.length; i++) {
1769    this.encoder_.writeDouble(value[i]);
1770  }
1771};
1772
1773
1774/**
1775 * Writes an array of booleans to the buffer as a packed bool field.
1776 * @param {number} field The field number.
1777 * @param {?Array<boolean>} value The array of ints to write.
1778 */
1779jspb.BinaryWriter.prototype.writePackedBool = function(field, value) {
1780  if (value == null || !value.length) return;
1781  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1782  this.encoder_.writeUnsignedVarint32(value.length);
1783  for (var i = 0; i < value.length; i++) {
1784    this.encoder_.writeBool(value[i]);
1785  }
1786};
1787
1788
1789/**
1790 * Writes an array of enums to the buffer as a packed enum field.
1791 * @param {number} field The field number.
1792 * @param {?Array<number>} value The array of ints to write.
1793 */
1794jspb.BinaryWriter.prototype.writePackedEnum = function(field, value) {
1795  if (value == null || !value.length) return;
1796  var bookmark = this.beginDelimited_(field);
1797  for (var i = 0; i < value.length; i++) {
1798    this.encoder_.writeEnum(value[i]);
1799  }
1800  this.endDelimited_(bookmark);
1801};
1802
1803
1804/**
1805 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
1806 * the buffer.
1807 * @param {number} field The field number.
1808 * @param {?Array<string>} value The array of hashes to write.
1809 */
1810jspb.BinaryWriter.prototype.writePackedFixedHash64 = function(field, value) {
1811  if (value == null || !value.length) return;
1812  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1813  this.encoder_.writeUnsignedVarint32(value.length * 8);
1814  for (var i = 0; i < value.length; i++) {
1815    this.encoder_.writeFixedHash64(value[i]);
1816  }
1817};
1818
1819
1820/**
1821 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
1822 * the buffer.
1823 * @param {number} field The field number.
1824 * @param {?Array<string>} value The array of hashes to write.
1825 */
1826jspb.BinaryWriter.prototype.writePackedVarintHash64 = function(field, value) {
1827  if (value == null || !value.length) return;
1828  var bookmark = this.beginDelimited_(field);
1829  for (var i = 0; i < value.length; i++) {
1830    this.encoder_.writeVarintHash64(value[i]);
1831  }
1832  this.endDelimited_(bookmark);
1833};
1834