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 * @author aappleby@google.com (Austin Appleby)
56 */
57
58goog.provide('jspb.BinaryWriter');
59
60goog.require('goog.asserts');
61goog.require('goog.crypt.base64');
62goog.require('jspb.BinaryConstants');
63goog.require('jspb.BinaryEncoder');
64goog.require('jspb.arith.Int64');
65goog.require('jspb.arith.UInt64');
66goog.require('jspb.utils');
67
68
69
70/**
71 * BinaryWriter implements encoders for all the wire types specified in
72 * https://developers.google.com/protocol-buffers/docs/encoding.
73 *
74 * @constructor
75 * @struct
76 */
77jspb.BinaryWriter = function() {
78  /**
79   * Blocks of serialized data that will be concatenated once all messages have
80   * been written.
81   * @private {!Array<!Uint8Array|!Array<number>>}
82   */
83  this.blocks_ = [];
84
85  /**
86   * Total number of bytes in the blocks_ array. Does _not_ include bytes in
87   * the encoder below.
88   * @private {number}
89   */
90  this.totalLength_ = 0;
91
92  /**
93   * Binary encoder holding pieces of a message that we're still serializing.
94   * When we get to a stopping point (either the start of a new submessage, or
95   * when we need to append a raw Uint8Array), the encoder's buffer will be
96   * added to the block array above and the encoder will be reset.
97   * @private {!jspb.BinaryEncoder}
98   */
99  this.encoder_ = new jspb.BinaryEncoder();
100
101  /**
102   * A stack of bookmarks containing the parent blocks for each message started
103   * via beginSubMessage(), needed as bookkeeping for endSubMessage().
104   * TODO(aappleby): Deprecated, users should be calling writeMessage().
105   * @private {!Array.<!Array.<number>>}
106   */
107  this.bookmarks_ = [];
108};
109
110
111/**
112 * Append a typed array of bytes onto the buffer.
113 *
114 * @param {!Uint8Array} arr The byte array to append.
115 * @private
116 */
117jspb.BinaryWriter.prototype.appendUint8Array_ = function(arr) {
118  var temp = this.encoder_.end();
119  this.blocks_.push(temp);
120  this.blocks_.push(arr);
121  this.totalLength_ += temp.length + arr.length;
122};
123
124
125/**
126 * Begins a new message by writing the field header and returning a bookmark
127 * which we will use to patch in the message length to in endDelimited_ below.
128 * @param {number} field
129 * @return {!Array.<number>}
130 * @private
131 */
132jspb.BinaryWriter.prototype.beginDelimited_ = function(field) {
133  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
134  var bookmark = this.encoder_.end();
135  this.blocks_.push(bookmark);
136  this.totalLength_ += bookmark.length;
137  bookmark.push(this.totalLength_);
138  return bookmark;
139};
140
141
142/**
143 * Ends a message by encoding the _change_ in length of the buffer to the
144 * parent block and adds the number of bytes needed to encode that length to
145 * the total byte length.
146 * @param {!Array.<number>} bookmark
147 * @private
148 */
149jspb.BinaryWriter.prototype.endDelimited_ = function(bookmark) {
150  var oldLength = bookmark.pop();
151  var messageLength = this.totalLength_ + this.encoder_.length() - oldLength;
152  goog.asserts.assert(messageLength >= 0);
153
154  while (messageLength > 127) {
155    bookmark.push((messageLength & 0x7f) | 0x80);
156    messageLength = messageLength >>> 7;
157    this.totalLength_++;
158  }
159
160  bookmark.push(messageLength);
161  this.totalLength_++;
162};
163
164
165/**
166 * Writes a pre-serialized message to the buffer.
167 * @param {!Uint8Array} bytes The array of bytes to write.
168 * @param {number} start The start of the range to write.
169 * @param {number} end The end of the range to write.
170 */
171jspb.BinaryWriter.prototype.writeSerializedMessage = function(
172    bytes, start, end) {
173  this.appendUint8Array_(bytes.subarray(start, end));
174};
175
176
177/**
178 * Writes a pre-serialized message to the buffer if the message and endpoints
179 * are non-null.
180 * @param {?Uint8Array} bytes The array of bytes to write.
181 * @param {?number} start The start of the range to write.
182 * @param {?number} end The end of the range to write.
183 */
184jspb.BinaryWriter.prototype.maybeWriteSerializedMessage = function(
185    bytes, start, end) {
186  if (bytes != null && start != null && end != null) {
187    this.writeSerializedMessage(bytes, start, end);
188  }
189};
190
191
192/**
193 * Resets the writer, throwing away any accumulated buffers.
194 */
195jspb.BinaryWriter.prototype.reset = function() {
196  this.blocks_ = [];
197  this.encoder_.end();
198  this.totalLength_ = 0;
199  this.bookmarks_ = [];
200};
201
202
203/**
204 * Converts the encoded data into a Uint8Array.
205 * @return {!Uint8Array}
206 */
207jspb.BinaryWriter.prototype.getResultBuffer = function() {
208  goog.asserts.assert(this.bookmarks_.length == 0);
209
210  var flat = new Uint8Array(this.totalLength_ + this.encoder_.length());
211
212  var blocks = this.blocks_;
213  var blockCount = blocks.length;
214  var offset = 0;
215
216  for (var i = 0; i < blockCount; i++) {
217    var block = blocks[i];
218    flat.set(block, offset);
219    offset += block.length;
220  }
221
222  var tail = this.encoder_.end();
223  flat.set(tail, offset);
224  offset += tail.length;
225
226  // Post condition: `flattened` must have had every byte written.
227  goog.asserts.assert(offset == flat.length);
228
229  // Replace our block list with the flattened block, which lets GC reclaim
230  // the temp blocks sooner.
231  this.blocks_ = [flat];
232
233  return flat;
234};
235
236
237/**
238 * Converts the encoded data into a bas64-encoded string.
239 * @return {string}
240 */
241jspb.BinaryWriter.prototype.getResultBase64String = function() {
242  return goog.crypt.base64.encodeByteArray(this.getResultBuffer());
243};
244
245
246/**
247 * Begins a new sub-message. The client must call endSubMessage() when they're
248 * done.
249 * TODO(aappleby): Deprecated. Move callers to writeMessage().
250 * @param {number} field The field number of the sub-message.
251 */
252jspb.BinaryWriter.prototype.beginSubMessage = function(field) {
253  this.bookmarks_.push(this.beginDelimited_(field));
254};
255
256
257/**
258 * Finishes a sub-message and packs it into the parent messages' buffer.
259 * TODO(aappleby): Deprecated. Move callers to writeMessage().
260 */
261jspb.BinaryWriter.prototype.endSubMessage = function() {
262  goog.asserts.assert(this.bookmarks_.length >= 0);
263  this.endDelimited_(this.bookmarks_.pop());
264};
265
266
267/**
268 * Encodes a (field number, wire type) tuple into a wire-format field header
269 * and stores it in the buffer as a varint.
270 * @param {number} field The field number.
271 * @param {number} wireType The wire-type of the field, as specified in the
272 *     protocol buffer documentation.
273 * @private
274 */
275jspb.BinaryWriter.prototype.writeFieldHeader_ =
276    function(field, wireType) {
277  goog.asserts.assert(field >= 1 && field == Math.floor(field));
278  var x = field * 8 + wireType;
279  this.encoder_.writeUnsignedVarint32(x);
280};
281
282
283/**
284 * Writes a field of any valid scalar type to the binary stream.
285 * @param {jspb.BinaryConstants.FieldType} fieldType
286 * @param {number} field
287 * @param {jspb.AnyFieldType} value
288 */
289jspb.BinaryWriter.prototype.writeAny = function(fieldType, field, value) {
290  var fieldTypes = jspb.BinaryConstants.FieldType;
291  switch (fieldType) {
292    case fieldTypes.DOUBLE:
293      this.writeDouble(field, /** @type {number} */(value));
294      return;
295    case fieldTypes.FLOAT:
296      this.writeFloat(field, /** @type {number} */(value));
297      return;
298    case fieldTypes.INT64:
299      this.writeInt64(field, /** @type {number} */(value));
300      return;
301    case fieldTypes.UINT64:
302      this.writeUint64(field, /** @type {number} */(value));
303      return;
304    case fieldTypes.INT32:
305      this.writeInt32(field, /** @type {number} */(value));
306      return;
307    case fieldTypes.FIXED64:
308      this.writeFixed64(field, /** @type {number} */(value));
309      return;
310    case fieldTypes.FIXED32:
311      this.writeFixed32(field, /** @type {number} */(value));
312      return;
313    case fieldTypes.BOOL:
314      this.writeBool(field, /** @type {boolean} */(value));
315      return;
316    case fieldTypes.STRING:
317      this.writeString(field, /** @type {string} */(value));
318      return;
319    case fieldTypes.GROUP:
320      goog.asserts.fail('Group field type not supported in writeAny()');
321      return;
322    case fieldTypes.MESSAGE:
323      goog.asserts.fail('Message field type not supported in writeAny()');
324      return;
325    case fieldTypes.BYTES:
326      this.writeBytes(field, /** @type {?Uint8Array} */(value));
327      return;
328    case fieldTypes.UINT32:
329      this.writeUint32(field, /** @type {number} */(value));
330      return;
331    case fieldTypes.ENUM:
332      this.writeEnum(field, /** @type {number} */(value));
333      return;
334    case fieldTypes.SFIXED32:
335      this.writeSfixed32(field, /** @type {number} */(value));
336      return;
337    case fieldTypes.SFIXED64:
338      this.writeSfixed64(field, /** @type {number} */(value));
339      return;
340    case fieldTypes.SINT32:
341      this.writeSint32(field, /** @type {number} */(value));
342      return;
343    case fieldTypes.SINT64:
344      this.writeSint64(field, /** @type {number} */(value));
345      return;
346    case fieldTypes.FHASH64:
347      this.writeFixedHash64(field, /** @type {string} */(value));
348      return;
349    case fieldTypes.VHASH64:
350      this.writeVarintHash64(field, /** @type {string} */(value));
351      return;
352    default:
353      goog.asserts.fail('Invalid field type in writeAny()');
354      return;
355  }
356};
357
358
359/**
360 * Writes a varint field to the buffer without range checking.
361 * @param {number} field The field number.
362 * @param {number?} value The value to write.
363 * @private
364 */
365jspb.BinaryWriter.prototype.writeUnsignedVarint32_ = function(field, value) {
366  if (value == null) return;
367  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
368  this.encoder_.writeUnsignedVarint32(value);
369};
370
371
372/**
373 * Writes a varint field to the buffer without range checking.
374 * @param {number} field The field number.
375 * @param {number?} value The value to write.
376 * @private
377 */
378jspb.BinaryWriter.prototype.writeSignedVarint32_ = function(field, value) {
379  if (value == null) return;
380  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
381  this.encoder_.writeSignedVarint32(value);
382};
383
384
385/**
386 * Writes a varint field to the buffer without range checking.
387 * @param {number} field The field number.
388 * @param {number?} value The value to write.
389 * @private
390 */
391jspb.BinaryWriter.prototype.writeUnsignedVarint64_ = function(field, value) {
392  if (value == null) return;
393  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
394  this.encoder_.writeUnsignedVarint64(value);
395};
396
397
398/**
399 * Writes a varint field to the buffer without range checking.
400 * @param {number} field The field number.
401 * @param {number?} value The value to write.
402 * @private
403 */
404jspb.BinaryWriter.prototype.writeSignedVarint64_ = function(field, value) {
405  if (value == null) return;
406  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
407  this.encoder_.writeSignedVarint64(value);
408};
409
410
411/**
412 * Writes a zigzag varint field to the buffer without range checking.
413 * @param {number} field The field number.
414 * @param {number?} value The value to write.
415 * @private
416 */
417jspb.BinaryWriter.prototype.writeZigzagVarint32_ = function(field, value) {
418  if (value == null) return;
419  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
420  this.encoder_.writeZigzagVarint32(value);
421};
422
423
424/**
425 * Writes a zigzag varint field to the buffer without range checking.
426 * @param {number} field The field number.
427 * @param {number?} value The value to write.
428 * @private
429 */
430jspb.BinaryWriter.prototype.writeZigzagVarint64_ = function(field, value) {
431  if (value == null) return;
432  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
433  this.encoder_.writeZigzagVarint64(value);
434};
435
436
437/**
438 * Writes an int32 field to the buffer. Numbers outside the range [-2^31,2^31)
439 * will be truncated.
440 * @param {number} field The field number.
441 * @param {number?} value The value to write.
442 */
443jspb.BinaryWriter.prototype.writeInt32 = function(field, value) {
444  if (value == null) return;
445  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
446                      (value < jspb.BinaryConstants.TWO_TO_31));
447  this.writeSignedVarint32_(field, value);
448};
449
450
451/**
452 * Writes an int32 field represented as a string to the buffer. Numbers outside
453 * the range [-2^31,2^31) will be truncated.
454 * @param {number} field The field number.
455 * @param {string?} value The value to write.
456 */
457jspb.BinaryWriter.prototype.writeInt32String = function(field, value) {
458  if (value == null) return;
459  var intValue = /** {number} */ parseInt(value, 10);
460  goog.asserts.assert((intValue >= -jspb.BinaryConstants.TWO_TO_31) &&
461                      (intValue < jspb.BinaryConstants.TWO_TO_31));
462  this.writeSignedVarint32_(field, intValue);
463};
464
465
466/**
467 * Writes an int64 field to the buffer. Numbers outside the range [-2^63,2^63)
468 * will be truncated.
469 * @param {number} field The field number.
470 * @param {number?} value The value to write.
471 */
472jspb.BinaryWriter.prototype.writeInt64 = function(field, value) {
473  if (value == null) return;
474  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
475                      (value < jspb.BinaryConstants.TWO_TO_63));
476  this.writeSignedVarint64_(field, value);
477};
478
479
480/**
481 * Writes a int64 field (with value as a string) to the buffer.
482 * @param {number} field The field number.
483 * @param {string?} value The value to write.
484 */
485jspb.BinaryWriter.prototype.writeInt64String = function(field, value) {
486  if (value == null) return;
487  var num = jspb.arith.Int64.fromString(value);
488  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
489  this.encoder_.writeSplitVarint64(num.lo, num.hi);
490};
491
492
493/**
494 * Writes a uint32 field to the buffer. Numbers outside the range [0,2^32)
495 * will be truncated.
496 * @param {number} field The field number.
497 * @param {number?} value The value to write.
498 */
499jspb.BinaryWriter.prototype.writeUint32 = function(field, value) {
500  if (value == null) return;
501  goog.asserts.assert((value >= 0) &&
502                      (value < jspb.BinaryConstants.TWO_TO_32));
503  this.writeUnsignedVarint32_(field, value);
504};
505
506
507/**
508 * Writes a uint32 field represented as a string to the buffer. Numbers outside
509 * the range [0,2^32) will be truncated.
510 * @param {number} field The field number.
511 * @param {string?} value The value to write.
512 */
513jspb.BinaryWriter.prototype.writeUint32String = function(field, value) {
514  if (value == null) return;
515  var intValue = /** {number} */ parseInt(value, 10);
516  goog.asserts.assert((intValue >= 0) &&
517                      (intValue < jspb.BinaryConstants.TWO_TO_32));
518  this.writeUnsignedVarint32_(field, intValue);
519};
520
521
522/**
523 * Writes a uint64 field to the buffer. Numbers outside the range [0,2^64)
524 * will be truncated.
525 * @param {number} field The field number.
526 * @param {number?} value The value to write.
527 */
528jspb.BinaryWriter.prototype.writeUint64 = function(field, value) {
529  if (value == null) return;
530  goog.asserts.assert((value >= 0) &&
531                      (value < jspb.BinaryConstants.TWO_TO_64));
532  this.writeUnsignedVarint64_(field, value);
533};
534
535
536/**
537 * Writes a uint64 field (with value as a string) to the buffer.
538 * @param {number} field The field number.
539 * @param {string?} value The value to write.
540 */
541jspb.BinaryWriter.prototype.writeUint64String = function(field, value) {
542  if (value == null) return;
543  var num = jspb.arith.UInt64.fromString(value);
544  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
545  this.encoder_.writeSplitVarint64(num.lo, num.hi);
546};
547
548
549/**
550 * Writes a sint32 field to the buffer. Numbers outside the range [-2^31,2^31)
551 * will be truncated.
552 * @param {number} field The field number.
553 * @param {number?} value The value to write.
554 */
555jspb.BinaryWriter.prototype.writeSint32 = function(field, value) {
556  if (value == null) return;
557  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
558                      (value < jspb.BinaryConstants.TWO_TO_31));
559  this.writeZigzagVarint32_(field, value);
560};
561
562
563/**
564 * Writes a sint64 field to the buffer. Numbers outside the range [-2^63,2^63)
565 * will be truncated.
566 * @param {number} field The field number.
567 * @param {number?} value The value to write.
568 */
569jspb.BinaryWriter.prototype.writeSint64 = function(field, value) {
570  if (value == null) return;
571  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
572                      (value < jspb.BinaryConstants.TWO_TO_63));
573  this.writeZigzagVarint64_(field, value);
574};
575
576
577/**
578 * Writes a fixed32 field to the buffer. Numbers outside the range [0,2^32)
579 * will be truncated.
580 * @param {number} field The field number.
581 * @param {number?} value The value to write.
582 */
583jspb.BinaryWriter.prototype.writeFixed32 = function(field, value) {
584  if (value == null) return;
585  goog.asserts.assert((value >= 0) &&
586                      (value < jspb.BinaryConstants.TWO_TO_32));
587  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
588  this.encoder_.writeUint32(value);
589};
590
591
592/**
593 * Writes a fixed64 field to the buffer. Numbers outside the range [0,2^64)
594 * will be truncated.
595 * @param {number} field The field number.
596 * @param {number?} value The value to write.
597 */
598jspb.BinaryWriter.prototype.writeFixed64 = function(field, value) {
599  if (value == null) return;
600  goog.asserts.assert((value >= 0) &&
601                      (value < jspb.BinaryConstants.TWO_TO_64));
602  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
603  this.encoder_.writeUint64(value);
604};
605
606
607/**
608 * Writes a sfixed32 field to the buffer. Numbers outside the range
609 * [-2^31,2^31) will be truncated.
610 * @param {number} field The field number.
611 * @param {number?} value The value to write.
612 */
613jspb.BinaryWriter.prototype.writeSfixed32 = function(field, value) {
614  if (value == null) return;
615  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
616                      (value < jspb.BinaryConstants.TWO_TO_31));
617  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
618  this.encoder_.writeInt32(value);
619};
620
621
622/**
623 * Writes a sfixed64 field to the buffer. Numbers outside the range
624 * [-2^63,2^63) will be truncated.
625 * @param {number} field The field number.
626 * @param {number?} value The value to write.
627 */
628jspb.BinaryWriter.prototype.writeSfixed64 = function(field, value) {
629  if (value == null) return;
630  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
631                      (value < jspb.BinaryConstants.TWO_TO_63));
632  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
633  this.encoder_.writeInt64(value);
634};
635
636
637/**
638 * Writes a single-precision floating point field to the buffer. Numbers
639 * requiring more than 32 bits of precision will be truncated.
640 * @param {number} field The field number.
641 * @param {number?} value The value to write.
642 */
643jspb.BinaryWriter.prototype.writeFloat = function(field, value) {
644  if (value == null) return;
645  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
646  this.encoder_.writeFloat(value);
647};
648
649
650/**
651 * Writes a double-precision floating point field to the buffer. As this is the
652 * native format used by JavaScript, no precision will be lost.
653 * @param {number} field The field number.
654 * @param {number?} value The value to write.
655 */
656jspb.BinaryWriter.prototype.writeDouble = function(field, value) {
657  if (value == null) return;
658  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
659  this.encoder_.writeDouble(value);
660};
661
662
663/**
664 * Writes a boolean field to the buffer.
665 * @param {number} field The field number.
666 * @param {boolean?} value The value to write.
667 */
668jspb.BinaryWriter.prototype.writeBool = function(field, value) {
669  if (value == null) return;
670  goog.asserts.assert(goog.isBoolean(value));
671  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
672  this.encoder_.writeBool(value);
673};
674
675
676/**
677 * Writes an enum field to the buffer.
678 * @param {number} field The field number.
679 * @param {number?} value The value to write.
680 */
681jspb.BinaryWriter.prototype.writeEnum = function(field, value) {
682  if (value == null) return;
683  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
684                      (value < jspb.BinaryConstants.TWO_TO_31));
685  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
686  this.encoder_.writeSignedVarint32(value);
687};
688
689
690/**
691 * Writes a string field to the buffer.
692 * @param {number} field The field number.
693 * @param {string?} value The string to write.
694 */
695jspb.BinaryWriter.prototype.writeString = function(field, value) {
696  if (value == null) return;
697  var bookmark = this.beginDelimited_(field);
698  this.encoder_.writeString(value);
699  this.endDelimited_(bookmark);
700};
701
702
703/**
704 * Writes an arbitrary byte field to the buffer. Note - to match the behavior
705 * of the C++ implementation, empty byte arrays _are_ serialized.
706 * @param {number} field The field number.
707 * @param {?jspb.ByteSource} value The array of bytes to write.
708 */
709jspb.BinaryWriter.prototype.writeBytes = function(field, value) {
710  if (value == null) return;
711  var bytes = jspb.utils.byteSourceToUint8Array(value);
712  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
713  this.encoder_.writeUnsignedVarint32(bytes.length);
714  this.appendUint8Array_(bytes);
715};
716
717
718/**
719 * Writes a message to the buffer.
720 * @param {number} field The field number.
721 * @param {?MessageType} value The message to write.
722 * @param {function(MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
723 *     Will be invoked with the value to write and the writer to write it with.
724 * @template MessageType
725 * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
726 * the null in blah|null with none.  This is necessary because the compiler will
727 * infer MessageType to be nullable if the value parameter is nullable.
728 * @template MessageTypeNonNull :=
729 *     cond(isUnknown(MessageType), unknown(),
730 *       mapunion(MessageType, (X) =>
731 *         cond(eq(X, 'null'), none(), X)))
732 * =:
733 */
734jspb.BinaryWriter.prototype.writeMessage = function(
735    field, value, writerCallback) {
736  if (value == null) return;
737  var bookmark = this.beginDelimited_(field);
738  writerCallback(value, this);
739  this.endDelimited_(bookmark);
740};
741
742
743/**
744 * Writes a group message to the buffer.
745 *
746 * @param {number} field The field number.
747 * @param {?MessageType} value The message to write, wrapped with START_GROUP /
748 *     END_GROUP tags. Will be a no-op if 'value' is null.
749 * @param {function(MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
750 *     Will be invoked with the value to write and the writer to write it with.
751 * @template MessageType
752 * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
753 * the null in blah|null with none.  This is necessary because the compiler will
754 * infer MessageType to be nullable if the value parameter is nullable.
755 * @template MessageTypeNonNull :=
756 *     cond(isUnknown(MessageType), unknown(),
757 *       mapunion(MessageType, (X) =>
758 *         cond(eq(X, 'null'), none(), X)))
759 * =:
760 */
761jspb.BinaryWriter.prototype.writeGroup = function(
762    field, value, writerCallback) {
763  if (value == null) return;
764  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP);
765  writerCallback(value, this);
766  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP);
767};
768
769
770/**
771 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
772 * the buffer.
773 * @param {number} field The field number.
774 * @param {string?} value The hash string.
775 */
776jspb.BinaryWriter.prototype.writeFixedHash64 = function(field, value) {
777  if (value == null) return;
778  goog.asserts.assert(value.length == 8);
779  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
780  this.encoder_.writeFixedHash64(value);
781};
782
783
784/**
785 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
786 * the buffer.
787 * @param {number} field The field number.
788 * @param {string?} value The hash string.
789 */
790jspb.BinaryWriter.prototype.writeVarintHash64 = function(field, value) {
791  if (value == null) return;
792  goog.asserts.assert(value.length == 8);
793  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
794  this.encoder_.writeVarintHash64(value);
795};
796
797
798/**
799 * Writes an array of numbers to the buffer as a repeated varint field.
800 * @param {number} field The field number.
801 * @param {?Array.<number>} value The array of ints to write.
802 * @private
803 */
804jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint32_ =
805    function(field, value) {
806  if (value == null) return;
807  for (var i = 0; i < value.length; i++) {
808    this.writeUnsignedVarint32_(field, value[i]);
809  }
810};
811
812
813/**
814 * Writes an array of numbers to the buffer as a repeated varint field.
815 * @param {number} field The field number.
816 * @param {?Array.<number>} value The array of ints to write.
817 * @private
818 */
819jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_ =
820    function(field, value) {
821  if (value == null) return;
822  for (var i = 0; i < value.length; i++) {
823    this.writeSignedVarint32_(field, value[i]);
824  }
825};
826
827
828/**
829 * Writes an array of numbers to the buffer as a repeated varint field.
830 * @param {number} field The field number.
831 * @param {?Array.<number>} value The array of ints to write.
832 * @private
833 */
834jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint64_ =
835    function(field, value) {
836  if (value == null) return;
837  for (var i = 0; i < value.length; i++) {
838    this.writeUnsignedVarint64_(field, value[i]);
839  }
840};
841
842
843/**
844 * Writes an array of numbers to the buffer as a repeated varint field.
845 * @param {number} field The field number.
846 * @param {?Array.<number>} value The array of ints to write.
847 * @private
848 */
849jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_ =
850    function(field, value) {
851  if (value == null) return;
852  for (var i = 0; i < value.length; i++) {
853    this.writeSignedVarint64_(field, value[i]);
854  }
855};
856
857
858/**
859 * Writes an array of numbers to the buffer as a repeated zigzag field.
860 * @param {number} field The field number.
861 * @param {?Array.<number>} value The array of ints to write.
862 * @private
863 */
864jspb.BinaryWriter.prototype.writeRepeatedZigzag32_ = function(field, value) {
865  if (value == null) return;
866  for (var i = 0; i < value.length; i++) {
867    this.writeZigzagVarint32_(field, value[i]);
868  }
869};
870
871
872/**
873 * Writes an array of numbers to the buffer as a repeated zigzag field.
874 * @param {number} field The field number.
875 * @param {?Array.<number>} value The array of ints to write.
876 * @private
877 */
878jspb.BinaryWriter.prototype.writeRepeatedZigzag_ = function(field, value) {
879  if (value == null) return;
880  for (var i = 0; i < value.length; i++) {
881    this.writeZigzagVarint64_(field, value[i]);
882  }
883};
884
885
886/**
887 * Writes an array of numbers to the buffer as a repeated 32-bit int field.
888 * @param {number} field The field number.
889 * @param {?Array.<number>} value The array of ints to write.
890 */
891jspb.BinaryWriter.prototype.writeRepeatedInt32 =
892    jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_;
893
894
895/**
896 * Writes an array of numbers formatted as strings to the buffer as a repeated
897 * 32-bit int field.
898 * @param {number} field The field number.
899 * @param {?Array.<string>} value The array of ints to write.
900 */
901jspb.BinaryWriter.prototype.writeRepeatedInt32String =
902    function(field, value) {
903  if (value == null) return;
904  for (var i = 0; i < value.length; i++) {
905    this.writeInt32String(field, value[i]);
906  }
907};
908
909
910/**
911 * Writes an array of numbers to the buffer as a repeated 64-bit int field.
912 * @param {number} field The field number.
913 * @param {?Array.<number>} value The array of ints to write.
914 */
915jspb.BinaryWriter.prototype.writeRepeatedInt64 =
916    jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_;
917
918
919/**
920 * Writes an array of numbers formatted as strings to the buffer as a repeated
921 * 64-bit int field.
922 * @param {number} field The field number.
923 * @param {?Array.<string>} value The array of ints to write.
924 */
925jspb.BinaryWriter.prototype.writeRepeatedInt64String =
926    function(field, value) {
927  if (value == null) return;
928  for (var i = 0; i < value.length; i++) {
929    this.writeInt64String(field, value[i]);
930  }
931};
932
933
934/**
935 * Writes an array numbers to the buffer as a repeated unsigned 32-bit int
936 *     field.
937 * @param {number} field The field number.
938 * @param {?Array.<number>} value The array of ints to write.
939 */
940jspb.BinaryWriter.prototype.writeRepeatedUint32 =
941    jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint32_;
942
943
944/**
945 * Writes an array of numbers formatted as strings to the buffer as a repeated
946 * unsigned 32-bit int field.
947 * @param {number} field The field number.
948 * @param {?Array.<string>} value The array of ints to write.
949 */
950jspb.BinaryWriter.prototype.writeRepeatedUint32String =
951    function(field, value) {
952  if (value == null) return;
953  for (var i = 0; i < value.length; i++) {
954    this.writeUint32String(field, value[i]);
955  }
956};
957
958
959/**
960 * Writes an array numbers to the buffer as a repeated unsigned 64-bit int
961 *     field.
962 * @param {number} field The field number.
963 * @param {?Array.<number>} value The array of ints to write.
964 */
965jspb.BinaryWriter.prototype.writeRepeatedUint64 =
966    jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint64_;
967
968
969/**
970 * Writes an array of numbers formatted as strings to the buffer as a repeated
971 * unsigned 64-bit int field.
972 * @param {number} field The field number.
973 * @param {?Array.<string>} value The array of ints to write.
974 */
975jspb.BinaryWriter.prototype.writeRepeatedUint64String =
976    function(field, value) {
977  if (value == null) return;
978  for (var i = 0; i < value.length; i++) {
979    this.writeUint64String(field, value[i]);
980  }
981};
982
983
984/**
985 * Writes an array numbers to the buffer as a repeated signed 32-bit int field.
986 * @param {number} field The field number.
987 * @param {?Array.<number>} value The array of ints to write.
988 */
989jspb.BinaryWriter.prototype.writeRepeatedSint32 =
990    jspb.BinaryWriter.prototype.writeRepeatedZigzag32_;
991
992
993/**
994 * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
995 * @param {number} field The field number.
996 * @param {?Array.<number>} value The array of ints to write.
997 */
998jspb.BinaryWriter.prototype.writeRepeatedSint64 =
999    jspb.BinaryWriter.prototype.writeRepeatedZigzag_;
1000
1001
1002/**
1003 * Writes an array of numbers to the buffer as a repeated fixed32 field. This
1004 * works for both signed and unsigned fixed32s.
1005 * @param {number} field The field number.
1006 * @param {?Array.<number>} value The array of ints to write.
1007 */
1008jspb.BinaryWriter.prototype.writeRepeatedFixed32 = function(field, value) {
1009  if (value == null) return;
1010  for (var i = 0; i < value.length; i++) {
1011    this.writeFixed32(field, value[i]);
1012  }
1013};
1014
1015
1016/**
1017 * Writes an array of numbers to the buffer as a repeated fixed64 field. This
1018 * works for both signed and unsigned fixed64s.
1019 * @param {number} field The field number.
1020 * @param {?Array.<number>} value The array of ints to write.
1021 */
1022jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(field, value) {
1023  if (value == null) return;
1024  for (var i = 0; i < value.length; i++) {
1025    this.writeFixed64(field, value[i]);
1026  }
1027};
1028
1029
1030/**
1031 * Writes an array of numbers to the buffer as a repeated sfixed32 field.
1032 * @param {number} field The field number.
1033 * @param {?Array.<number>} value The array of ints to write.
1034 */
1035jspb.BinaryWriter.prototype.writeRepeatedSfixed32 = function(field, value) {
1036  if (value == null) return;
1037  for (var i = 0; i < value.length; i++) {
1038    this.writeSfixed32(field, value[i]);
1039  }
1040};
1041
1042
1043/**
1044 * Writes an array of numbers to the buffer as a repeated sfixed64 field.
1045 * @param {number} field The field number.
1046 * @param {?Array.<number>} value The array of ints to write.
1047 */
1048jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(field, value) {
1049  if (value == null) return;
1050  for (var i = 0; i < value.length; i++) {
1051    this.writeSfixed64(field, value[i]);
1052  }
1053};
1054
1055
1056/**
1057 * Writes an array of numbers to the buffer as a repeated float field.
1058 * @param {number} field The field number.
1059 * @param {?Array.<number>} value The array of ints to write.
1060 */
1061jspb.BinaryWriter.prototype.writeRepeatedFloat = function(field, value) {
1062  if (value == null) return;
1063  for (var i = 0; i < value.length; i++) {
1064    this.writeFloat(field, value[i]);
1065  }
1066};
1067
1068
1069/**
1070 * Writes an array of numbers to the buffer as a repeated double field.
1071 * @param {number} field The field number.
1072 * @param {?Array.<number>} value The array of ints to write.
1073 */
1074jspb.BinaryWriter.prototype.writeRepeatedDouble = function(field, value) {
1075  if (value == null) return;
1076  for (var i = 0; i < value.length; i++) {
1077    this.writeDouble(field, value[i]);
1078  }
1079};
1080
1081
1082/**
1083 * Writes an array of booleans to the buffer as a repeated bool field.
1084 * @param {number} field The field number.
1085 * @param {?Array.<boolean>} value The array of ints to write.
1086 */
1087jspb.BinaryWriter.prototype.writeRepeatedBool = function(field, value) {
1088  if (value == null) return;
1089  for (var i = 0; i < value.length; i++) {
1090    this.writeBool(field, value[i]);
1091  }
1092};
1093
1094
1095/**
1096 * Writes an array of enums to the buffer as a repeated enum field.
1097 * @param {number} field The field number.
1098 * @param {?Array.<number>} value The array of ints to write.
1099 */
1100jspb.BinaryWriter.prototype.writeRepeatedEnum = function(field, value) {
1101  if (value == null) return;
1102  for (var i = 0; i < value.length; i++) {
1103    this.writeEnum(field, value[i]);
1104  }
1105};
1106
1107
1108/**
1109 * Writes an array of strings to the buffer as a repeated string field.
1110 * @param {number} field The field number.
1111 * @param {?Array.<string>} value The array of strings to write.
1112 */
1113jspb.BinaryWriter.prototype.writeRepeatedString = function(field, value) {
1114  if (value == null) return;
1115  for (var i = 0; i < value.length; i++) {
1116    this.writeString(field, value[i]);
1117  }
1118};
1119
1120
1121/**
1122 * Writes an array of arbitrary byte fields to the buffer.
1123 * @param {number} field The field number.
1124 * @param {?Array.<!jspb.ByteSource>} value The arrays of arrays of bytes to
1125 *     write.
1126 */
1127jspb.BinaryWriter.prototype.writeRepeatedBytes = function(field, value) {
1128  if (value == null) return;
1129  for (var i = 0; i < value.length; i++) {
1130    this.writeBytes(field, value[i]);
1131  }
1132};
1133
1134
1135/**
1136 * Writes an array of messages to the buffer.
1137 * @template MessageType
1138 * @param {number} field The field number.
1139 * @param {?Array.<MessageType>} value The array of messages to
1140 *    write.
1141 * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
1142 *     Will be invoked with the value to write and the writer to write it with.
1143 */
1144jspb.BinaryWriter.prototype.writeRepeatedMessage = function(
1145    field, value, writerCallback) {
1146  if (value == null) return;
1147  for (var i = 0; i < value.length; i++) {
1148    var bookmark = this.beginDelimited_(field);
1149    writerCallback(value[i], this);
1150    this.endDelimited_(bookmark);
1151  }
1152};
1153
1154
1155/**
1156 * Writes an array of group messages to the buffer.
1157 * @template MessageType
1158 * @param {number} field The field number.
1159 * @param {?Array.<MessageType>} value The array of messages to
1160 *    write.
1161 * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
1162 *     Will be invoked with the value to write and the writer to write it with.
1163 */
1164jspb.BinaryWriter.prototype.writeRepeatedGroup = function(
1165    field, value, writerCallback) {
1166  if (value == null) return;
1167  for (var i = 0; i < value.length; i++) {
1168    this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP);
1169    writerCallback(value[i], this);
1170    this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP);
1171  }
1172};
1173
1174
1175/**
1176 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
1177 * the buffer.
1178 * @param {number} field The field number.
1179 * @param {?Array.<string>} value The array of hashes to write.
1180 */
1181jspb.BinaryWriter.prototype.writeRepeatedFixedHash64 =
1182    function(field, value) {
1183  if (value == null) return;
1184  for (var i = 0; i < value.length; i++) {
1185    this.writeFixedHash64(field, value[i]);
1186  }
1187};
1188
1189
1190/**
1191 * Writes a repeated 64-bit hash string field (8 characters @ 8 bits of data
1192 * each) to the buffer.
1193 * @param {number} field The field number.
1194 * @param {?Array.<string>} value The array of hashes to write.
1195 */
1196jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 =
1197    function(field, value) {
1198  if (value == null) return;
1199  for (var i = 0; i < value.length; i++) {
1200    this.writeVarintHash64(field, value[i]);
1201  }
1202};
1203
1204
1205/**
1206 * Writes an array of numbers to the buffer as a packed varint field.
1207 * @param {number} field The field number.
1208 * @param {?Array.<number>} value The array of ints to write.
1209 * @private
1210 */
1211jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_ = function(
1212    field, value) {
1213  if (value == null || !value.length) return;
1214  var bookmark = this.beginDelimited_(field);
1215  for (var i = 0; i < value.length; i++) {
1216    this.encoder_.writeUnsignedVarint32(value[i]);
1217  }
1218  this.endDelimited_(bookmark);
1219};
1220
1221
1222/**
1223 * Writes an array of numbers to the buffer as a packed varint field.
1224 * @param {number} field The field number.
1225 * @param {?Array.<number>} value The array of ints to write.
1226 * @private
1227 */
1228jspb.BinaryWriter.prototype.writePackedSignedVarint32_ = function(
1229    field, value) {
1230  if (value == null || !value.length) return;
1231  var bookmark = this.beginDelimited_(field);
1232  for (var i = 0; i < value.length; i++) {
1233    this.encoder_.writeSignedVarint32(value[i]);
1234  }
1235  this.endDelimited_(bookmark);
1236};
1237
1238
1239/**
1240 * Writes an array of numbers to the buffer as a packed varint field.
1241 * @param {number} field The field number.
1242 * @param {?Array.<number>} value The array of ints to write.
1243 * @private
1244 */
1245jspb.BinaryWriter.prototype.writePackedUnsignedVarint64_ = function(
1246    field, value) {
1247  if (value == null || !value.length) return;
1248  var bookmark = this.beginDelimited_(field);
1249  for (var i = 0; i < value.length; i++) {
1250    this.encoder_.writeUnsignedVarint64(value[i]);
1251  }
1252  this.endDelimited_(bookmark);
1253};
1254
1255
1256/**
1257 * Writes an array of numbers to the buffer as a packed varint field.
1258 * @param {number} field The field number.
1259 * @param {?Array.<number>} value The array of ints to write.
1260 * @private
1261 */
1262jspb.BinaryWriter.prototype.writePackedSignedVarint64_ = function(
1263    field, value) {
1264  if (value == null || !value.length) return;
1265  var bookmark = this.beginDelimited_(field);
1266  for (var i = 0; i < value.length; i++) {
1267    this.encoder_.writeSignedVarint64(value[i]);
1268  }
1269  this.endDelimited_(bookmark);
1270};
1271
1272
1273/**
1274 * Writes an array of numbers to the buffer as a packed zigzag field.
1275 * @param {number} field The field number.
1276 * @param {?Array.<number>} value The array of ints to write.
1277 * @private
1278 */
1279jspb.BinaryWriter.prototype.writePackedZigzag32_ = function(field, value) {
1280  if (value == null || !value.length) return;
1281  var bookmark = this.beginDelimited_(field);
1282  for (var i = 0; i < value.length; i++) {
1283    this.encoder_.writeZigzagVarint32(value[i]);
1284  }
1285  this.endDelimited_(bookmark);
1286};
1287
1288
1289/**
1290 * Writes an array of numbers to the buffer as a packed zigzag field.
1291 * @param {number} field The field number.
1292 * @param {?Array.<number>} value The array of ints to write.
1293 * @private
1294 */
1295jspb.BinaryWriter.prototype.writePackedZigzag64_ = function(field, value) {
1296  if (value == null || !value.length) return;
1297  var bookmark = this.beginDelimited_(field);
1298  for (var i = 0; i < value.length; i++) {
1299    this.encoder_.writeZigzagVarint64(value[i]);
1300  }
1301  this.endDelimited_(bookmark);
1302};
1303
1304
1305/**
1306 * Writes an array of numbers to the buffer as a packed 32-bit int field.
1307 * @param {number} field The field number.
1308 * @param {?Array.<number>} value The array of ints to write.
1309 */
1310jspb.BinaryWriter.prototype.writePackedInt32 =
1311    jspb.BinaryWriter.prototype.writePackedSignedVarint32_;
1312
1313
1314/**
1315 * Writes an array of numbers represented as strings to the buffer as a packed
1316 * 32-bit int field.
1317 * @param {number} field
1318 * @param {?Array.<string>} value
1319 */
1320jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
1321  if (value == null || !value.length) return;
1322  var bookmark = this.beginDelimited_(field);
1323  for (var i = 0; i < value.length; i++) {
1324    this.encoder_.writeSignedVarint32(parseInt(value[i], 10));
1325  }
1326  this.endDelimited_(bookmark);
1327};
1328
1329
1330/**
1331 * Writes an array of numbers to the buffer as a packed 64-bit int field.
1332 * @param {number} field The field number.
1333 * @param {?Array.<number>} value The array of ints to write.
1334 */
1335jspb.BinaryWriter.prototype.writePackedInt64 =
1336    jspb.BinaryWriter.prototype.writePackedSignedVarint64_;
1337
1338
1339/**
1340 * Writes an array of numbers represented as strings to the buffer as a packed
1341 * 64-bit int field.
1342 * @param {number} field
1343 * @param {?Array.<string>} value
1344 */
1345jspb.BinaryWriter.prototype.writePackedInt64String =
1346    function(field, value) {
1347  if (value == null || !value.length) return;
1348  var bookmark = this.beginDelimited_(field);
1349  for (var i = 0; i < value.length; i++) {
1350    var num = jspb.arith.Int64.fromString(value[i]);
1351    this.encoder_.writeSplitVarint64(num.lo, num.hi);
1352  }
1353  this.endDelimited_(bookmark);
1354};
1355
1356
1357/**
1358 * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
1359 * @param {number} field The field number.
1360 * @param {?Array.<number>} value The array of ints to write.
1361 */
1362jspb.BinaryWriter.prototype.writePackedUint32 =
1363    jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_;
1364
1365
1366/**
1367 * Writes an array of numbers represented as strings to the buffer as a packed
1368 * unsigned 32-bit int field.
1369 * @param {number} field
1370 * @param {?Array.<string>} value
1371 */
1372jspb.BinaryWriter.prototype.writePackedUint32String =
1373    function(field, value) {
1374  if (value == null || !value.length) return;
1375  var bookmark = this.beginDelimited_(field);
1376  for (var i = 0; i < value.length; i++) {
1377    this.encoder_.writeUnsignedVarint32(parseInt(value[i], 10));
1378  }
1379  this.endDelimited_(bookmark);
1380};
1381
1382
1383/**
1384 * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
1385 * @param {number} field The field number.
1386 * @param {?Array.<number>} value The array of ints to write.
1387 */
1388jspb.BinaryWriter.prototype.writePackedUint64 =
1389    jspb.BinaryWriter.prototype.writePackedUnsignedVarint64_;
1390
1391
1392/**
1393 * Writes an array of numbers represented as strings to the buffer as a packed
1394 * unsigned 64-bit int field.
1395 * @param {number} field
1396 * @param {?Array.<string>} value
1397 */
1398jspb.BinaryWriter.prototype.writePackedUint64String =
1399    function(field, value) {
1400  if (value == null || !value.length) return;
1401  var bookmark = this.beginDelimited_(field);
1402  for (var i = 0; i < value.length; i++) {
1403    var num = jspb.arith.UInt64.fromString(value[i]);
1404    this.encoder_.writeSplitVarint64(num.lo, num.hi);
1405  }
1406  this.endDelimited_(bookmark);
1407};
1408
1409
1410/**
1411 * Writes an array numbers to the buffer as a packed signed 32-bit int field.
1412 * @param {number} field The field number.
1413 * @param {?Array.<number>} value The array of ints to write.
1414 */
1415jspb.BinaryWriter.prototype.writePackedSint32 =
1416    jspb.BinaryWriter.prototype.writePackedZigzag32_;
1417
1418
1419/**
1420 * Writes an array numbers to the buffer as a packed signed 64-bit int field.
1421 * @param {number} field The field number.
1422 * @param {?Array.<number>} value The array of ints to write.
1423 */
1424jspb.BinaryWriter.prototype.writePackedSint64 =
1425    jspb.BinaryWriter.prototype.writePackedZigzag64_;
1426
1427
1428/**
1429 * Writes an array of numbers to the buffer as a packed fixed32 field.
1430 * @param {number} field The field number.
1431 * @param {?Array.<number>} value The array of ints to write.
1432 */
1433jspb.BinaryWriter.prototype.writePackedFixed32 = function(field, value) {
1434  if (value == null || !value.length) return;
1435  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1436  this.encoder_.writeUnsignedVarint32(value.length * 4);
1437  for (var i = 0; i < value.length; i++) {
1438    this.encoder_.writeUint32(value[i]);
1439  }
1440};
1441
1442
1443/**
1444 * Writes an array of numbers to the buffer as a packed fixed64 field.
1445 * @param {number} field The field number.
1446 * @param {?Array.<number>} value The array of ints to write.
1447 */
1448jspb.BinaryWriter.prototype.writePackedFixed64 = function(field, value) {
1449  if (value == null || !value.length) return;
1450  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1451  this.encoder_.writeUnsignedVarint32(value.length * 8);
1452  for (var i = 0; i < value.length; i++) {
1453    this.encoder_.writeUint64(value[i]);
1454  }
1455};
1456
1457
1458/**
1459 * Writes an array of numbers to the buffer as a packed sfixed32 field.
1460 * @param {number} field The field number.
1461 * @param {?Array.<number>} value The array of ints to write.
1462 */
1463jspb.BinaryWriter.prototype.writePackedSfixed32 = function(field, value) {
1464  if (value == null || !value.length) return;
1465  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1466  this.encoder_.writeUnsignedVarint32(value.length * 4);
1467  for (var i = 0; i < value.length; i++) {
1468    this.encoder_.writeInt32(value[i]);
1469  }
1470};
1471
1472
1473/**
1474 * Writes an array of numbers to the buffer as a packed sfixed64 field.
1475 * @param {number} field The field number.
1476 * @param {?Array.<number>} value The array of ints to write.
1477 */
1478jspb.BinaryWriter.prototype.writePackedSfixed64 = function(field, value) {
1479  if (value == null || !value.length) return;
1480  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1481  this.encoder_.writeUnsignedVarint32(value.length * 8);
1482  for (var i = 0; i < value.length; i++) {
1483    this.encoder_.writeInt64(value[i]);
1484  }
1485};
1486
1487
1488/**
1489 * Writes an array of numbers to the buffer as a packed float field.
1490 * @param {number} field The field number.
1491 * @param {?Array.<number>} value The array of ints to write.
1492 */
1493jspb.BinaryWriter.prototype.writePackedFloat = function(field, value) {
1494  if (value == null || !value.length) return;
1495  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1496  this.encoder_.writeUnsignedVarint32(value.length * 4);
1497  for (var i = 0; i < value.length; i++) {
1498    this.encoder_.writeFloat(value[i]);
1499  }
1500};
1501
1502
1503/**
1504 * Writes an array of numbers to the buffer as a packed double field.
1505 * @param {number} field The field number.
1506 * @param {?Array.<number>} value The array of ints to write.
1507 */
1508jspb.BinaryWriter.prototype.writePackedDouble = function(field, value) {
1509  if (value == null || !value.length) return;
1510  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1511  this.encoder_.writeUnsignedVarint32(value.length * 8);
1512  for (var i = 0; i < value.length; i++) {
1513    this.encoder_.writeDouble(value[i]);
1514  }
1515};
1516
1517
1518/**
1519 * Writes an array of booleans to the buffer as a packed bool field.
1520 * @param {number} field The field number.
1521 * @param {?Array.<boolean>} value The array of ints to write.
1522 */
1523jspb.BinaryWriter.prototype.writePackedBool = function(field, value) {
1524  if (value == null || !value.length) return;
1525  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1526  this.encoder_.writeUnsignedVarint32(value.length);
1527  for (var i = 0; i < value.length; i++) {
1528    this.encoder_.writeBool(value[i]);
1529  }
1530};
1531
1532
1533/**
1534 * Writes an array of enums to the buffer as a packed enum field.
1535 * @param {number} field The field number.
1536 * @param {?Array.<number>} value The array of ints to write.
1537 */
1538jspb.BinaryWriter.prototype.writePackedEnum = function(field, value) {
1539  if (value == null || !value.length) return;
1540  var bookmark = this.beginDelimited_(field);
1541  for (var i = 0; i < value.length; i++) {
1542    this.encoder_.writeEnum(value[i]);
1543  }
1544  this.endDelimited_(bookmark);
1545};
1546
1547
1548/**
1549 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
1550 * the buffer.
1551 * @param {number} field The field number.
1552 * @param {?Array.<string>} value The array of hashes to write.
1553 */
1554jspb.BinaryWriter.prototype.writePackedFixedHash64 = function(field, value) {
1555  if (value == null || !value.length) return;
1556  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1557  this.encoder_.writeUnsignedVarint32(value.length * 8);
1558  for (var i = 0; i < value.length; i++) {
1559    this.encoder_.writeFixedHash64(value[i]);
1560  }
1561};
1562
1563
1564/**
1565 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
1566 * the buffer.
1567 * @param {number} field The field number.
1568 * @param {?Array.<string>} value The array of hashes to write.
1569 */
1570jspb.BinaryWriter.prototype.writePackedVarintHash64 = function(field, value) {
1571  if (value == null || !value.length) return;
1572  var bookmark = this.beginDelimited_(field);
1573  for (var i = 0; i < value.length; i++) {
1574    this.encoder_.writeVarintHash64(value[i]);
1575  }
1576  this.endDelimited_(bookmark);
1577};
1578