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 base64-encoded string.
239 * @param {boolean=} opt_webSafe True indicates we should use a websafe
240 *     alphabet, which does not require escaping for use in URLs.
241 * @return {string}
242 */
243jspb.BinaryWriter.prototype.getResultBase64String = function(opt_webSafe) {
244  return goog.crypt.base64.encodeByteArray(this.getResultBuffer(), opt_webSafe);
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 an int32 field to the buffer. Numbers outside the range [-2^31,2^31)
455 * will be truncated.
456 * @param {number} field The field number.
457 * @param {number?} value The value to write.
458 */
459jspb.BinaryWriter.prototype.writeInt32 = function(field, value) {
460  if (value == null) return;
461  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
462                      (value < jspb.BinaryConstants.TWO_TO_31));
463  this.writeSignedVarint32_(field, value);
464};
465
466
467/**
468 * Writes an int32 field represented as a string to the buffer. Numbers outside
469 * the range [-2^31,2^31) will be truncated.
470 * @param {number} field The field number.
471 * @param {string?} value The value to write.
472 */
473jspb.BinaryWriter.prototype.writeInt32String = function(field, value) {
474  if (value == null) return;
475  var intValue = /** {number} */ parseInt(value, 10);
476  goog.asserts.assert((intValue >= -jspb.BinaryConstants.TWO_TO_31) &&
477                      (intValue < jspb.BinaryConstants.TWO_TO_31));
478  this.writeSignedVarint32_(field, intValue);
479};
480
481
482/**
483 * Writes an int64 field to the buffer. Numbers outside the range [-2^63,2^63)
484 * will be truncated.
485 * @param {number} field The field number.
486 * @param {number?} value The value to write.
487 */
488jspb.BinaryWriter.prototype.writeInt64 = function(field, value) {
489  if (value == null) return;
490  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
491                      (value < jspb.BinaryConstants.TWO_TO_63));
492  this.writeSignedVarint64_(field, value);
493};
494
495
496/**
497 * Writes a int64 field (with value as a string) to the buffer.
498 * @param {number} field The field number.
499 * @param {string?} value The value to write.
500 */
501jspb.BinaryWriter.prototype.writeInt64String = function(field, value) {
502  if (value == null) return;
503  var num = jspb.arith.Int64.fromString(value);
504  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
505  this.encoder_.writeSplitVarint64(num.lo, num.hi);
506};
507
508
509/**
510 * Writes a uint32 field to the buffer. Numbers outside the range [0,2^32)
511 * will be truncated.
512 * @param {number} field The field number.
513 * @param {number?} value The value to write.
514 */
515jspb.BinaryWriter.prototype.writeUint32 = function(field, value) {
516  if (value == null) return;
517  goog.asserts.assert((value >= 0) &&
518                      (value < jspb.BinaryConstants.TWO_TO_32));
519  this.writeUnsignedVarint32_(field, value);
520};
521
522
523/**
524 * Writes a uint32 field represented as a string to the buffer. Numbers outside
525 * the range [0,2^32) will be truncated.
526 * @param {number} field The field number.
527 * @param {string?} value The value to write.
528 */
529jspb.BinaryWriter.prototype.writeUint32String = function(field, value) {
530  if (value == null) return;
531  var intValue = /** {number} */ parseInt(value, 10);
532  goog.asserts.assert((intValue >= 0) &&
533                      (intValue < jspb.BinaryConstants.TWO_TO_32));
534  this.writeUnsignedVarint32_(field, intValue);
535};
536
537
538/**
539 * Writes a uint64 field to the buffer. Numbers outside the range [0,2^64)
540 * will be truncated.
541 * @param {number} field The field number.
542 * @param {number?} value The value to write.
543 */
544jspb.BinaryWriter.prototype.writeUint64 = function(field, value) {
545  if (value == null) return;
546  goog.asserts.assert((value >= 0) &&
547                      (value < jspb.BinaryConstants.TWO_TO_64));
548  this.writeUnsignedVarint64_(field, value);
549};
550
551
552/**
553 * Writes a uint64 field (with value as a string) to the buffer.
554 * @param {number} field The field number.
555 * @param {string?} value The value to write.
556 */
557jspb.BinaryWriter.prototype.writeUint64String = function(field, value) {
558  if (value == null) return;
559  var num = jspb.arith.UInt64.fromString(value);
560  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
561  this.encoder_.writeSplitVarint64(num.lo, num.hi);
562};
563
564
565/**
566 * Writes a sint32 field to the buffer. Numbers outside the range [-2^31,2^31)
567 * will be truncated.
568 * @param {number} field The field number.
569 * @param {number?} value The value to write.
570 */
571jspb.BinaryWriter.prototype.writeSint32 = function(field, value) {
572  if (value == null) return;
573  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
574                      (value < jspb.BinaryConstants.TWO_TO_31));
575  this.writeZigzagVarint32_(field, value);
576};
577
578
579/**
580 * Writes a sint64 field to the buffer. Numbers outside the range [-2^63,2^63)
581 * will be truncated.
582 * @param {number} field The field number.
583 * @param {number?} value The value to write.
584 */
585jspb.BinaryWriter.prototype.writeSint64 = function(field, value) {
586  if (value == null) return;
587  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
588                      (value < jspb.BinaryConstants.TWO_TO_63));
589  this.writeZigzagVarint64_(field, value);
590};
591
592
593/**
594 * Writes a sint64 field to the buffer. Numbers outside the range [-2^63,2^63)
595 * will be truncated.
596 * @param {number} field The field number.
597 * @param {string?} value The decimal string to write.
598 */
599jspb.BinaryWriter.prototype.writeSint64String = function(field, value) {
600  if (value == null) return;
601  goog.asserts.assert((+value >= -jspb.BinaryConstants.TWO_TO_63) &&
602                      (+value < jspb.BinaryConstants.TWO_TO_63));
603  this.writeZigzagVarint64String_(field, value);
604};
605
606
607/**
608 * Writes a fixed32 field to the buffer. Numbers outside the range [0,2^32)
609 * will be truncated.
610 * @param {number} field The field number.
611 * @param {number?} value The value to write.
612 */
613jspb.BinaryWriter.prototype.writeFixed32 = function(field, value) {
614  if (value == null) return;
615  goog.asserts.assert((value >= 0) &&
616                      (value < jspb.BinaryConstants.TWO_TO_32));
617  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
618  this.encoder_.writeUint32(value);
619};
620
621
622/**
623 * Writes a fixed64 field to the buffer. Numbers outside the range [0,2^64)
624 * will be truncated.
625 * @param {number} field The field number.
626 * @param {number?} value The value to write.
627 */
628jspb.BinaryWriter.prototype.writeFixed64 = function(field, value) {
629  if (value == null) return;
630  goog.asserts.assert((value >= 0) &&
631                      (value < jspb.BinaryConstants.TWO_TO_64));
632  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
633  this.encoder_.writeUint64(value);
634};
635
636
637/**
638 * Writes a fixed64 field (with value as a string) to the buffer.
639 * @param {number} field The field number.
640 * @param {string?} value The value to write.
641 */
642jspb.BinaryWriter.prototype.writeFixed64String = function(field, value) {
643  if (value == null) return;
644  var num = jspb.arith.UInt64.fromString(value);
645  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
646  this.encoder_.writeSplitFixed64(num.lo, num.hi);
647};
648
649
650/**
651 * Writes a sfixed32 field to the buffer. Numbers outside the range
652 * [-2^31,2^31) will be truncated.
653 * @param {number} field The field number.
654 * @param {number?} value The value to write.
655 */
656jspb.BinaryWriter.prototype.writeSfixed32 = function(field, value) {
657  if (value == null) return;
658  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
659                      (value < jspb.BinaryConstants.TWO_TO_31));
660  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
661  this.encoder_.writeInt32(value);
662};
663
664
665/**
666 * Writes a sfixed64 field to the buffer. Numbers outside the range
667 * [-2^63,2^63) will be truncated.
668 * @param {number} field The field number.
669 * @param {number?} value The value to write.
670 */
671jspb.BinaryWriter.prototype.writeSfixed64 = function(field, value) {
672  if (value == null) return;
673  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
674                      (value < jspb.BinaryConstants.TWO_TO_63));
675  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
676  this.encoder_.writeInt64(value);
677};
678
679
680/**
681 * Writes a sfixed64 string field to the buffer. Numbers outside the range
682 * [-2^63,2^63) will be truncated.
683 * @param {number} field The field number.
684 * @param {string?} value The value to write.
685 */
686jspb.BinaryWriter.prototype.writeSfixed64String = function(field, value) {
687  if (value == null) return;
688  var num = jspb.arith.Int64.fromString(value);
689  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
690  this.encoder_.writeSplitFixed64(num.lo, num.hi);
691};
692
693
694/**
695 * Writes a single-precision floating point field to the buffer. Numbers
696 * requiring more than 32 bits of precision will be truncated.
697 * @param {number} field The field number.
698 * @param {number?} value The value to write.
699 */
700jspb.BinaryWriter.prototype.writeFloat = function(field, value) {
701  if (value == null) return;
702  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
703  this.encoder_.writeFloat(value);
704};
705
706
707/**
708 * Writes a double-precision floating point field to the buffer. As this is the
709 * native format used by JavaScript, no precision will be lost.
710 * @param {number} field The field number.
711 * @param {number?} value The value to write.
712 */
713jspb.BinaryWriter.prototype.writeDouble = function(field, value) {
714  if (value == null) return;
715  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
716  this.encoder_.writeDouble(value);
717};
718
719
720/**
721 * Writes a boolean field to the buffer. We allow numbers as input
722 * because the JSPB code generator uses 0/1 instead of true/false to save space
723 * in the string representation of the proto.
724 * @param {number} field The field number.
725 * @param {boolean?|number?} value The value to write.
726 */
727jspb.BinaryWriter.prototype.writeBool = function(field, value) {
728  if (value == null) return;
729  goog.asserts.assert(goog.isBoolean(value) || goog.isNumber(value));
730  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
731  this.encoder_.writeBool(value);
732};
733
734
735/**
736 * Writes an enum field to the buffer.
737 * @param {number} field The field number.
738 * @param {number?} value The value to write.
739 */
740jspb.BinaryWriter.prototype.writeEnum = function(field, value) {
741  if (value == null) return;
742  goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
743                      (value < jspb.BinaryConstants.TWO_TO_31));
744  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
745  this.encoder_.writeSignedVarint32(value);
746};
747
748
749/**
750 * Writes a string field to the buffer.
751 * @param {number} field The field number.
752 * @param {string?} value The string to write.
753 */
754jspb.BinaryWriter.prototype.writeString = function(field, value) {
755  if (value == null) return;
756  var bookmark = this.beginDelimited_(field);
757  this.encoder_.writeString(value);
758  this.endDelimited_(bookmark);
759};
760
761
762/**
763 * Writes an arbitrary byte field to the buffer. Note - to match the behavior
764 * of the C++ implementation, empty byte arrays _are_ serialized.
765 * @param {number} field The field number.
766 * @param {?jspb.ByteSource} value The array of bytes to write.
767 */
768jspb.BinaryWriter.prototype.writeBytes = function(field, value) {
769  if (value == null) return;
770  var bytes = jspb.utils.byteSourceToUint8Array(value);
771  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
772  this.encoder_.writeUnsignedVarint32(bytes.length);
773  this.appendUint8Array_(bytes);
774};
775
776
777/**
778 * Writes a message to the buffer.
779 * @param {number} field The field number.
780 * @param {?MessageType} value The message to write.
781 * @param {function(MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
782 *     Will be invoked with the value to write and the writer to write it with.
783 * @template MessageType
784 * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
785 * the null in blah|null with none.  This is necessary because the compiler will
786 * infer MessageType to be nullable if the value parameter is nullable.
787 * @template MessageTypeNonNull :=
788 *     cond(isUnknown(MessageType), unknown(),
789 *       mapunion(MessageType, (X) =>
790 *         cond(eq(X, 'null'), none(), X)))
791 * =:
792 */
793jspb.BinaryWriter.prototype.writeMessage = function(
794    field, value, writerCallback) {
795  if (value == null) return;
796  var bookmark = this.beginDelimited_(field);
797  writerCallback(value, this);
798  this.endDelimited_(bookmark);
799};
800
801
802/**
803 * Writes a message set extension to the buffer.
804 * @param {number} field The field number for the extension.
805 * @param {?MessageType} value The extension message object to write. Note that
806 *     message set can only have extensions with type of optional message.
807 * @param {function(!MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
808 *     Will be invoked with the value to write and the writer to write it with.
809 * @template MessageType
810 * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
811 * the null in blah|null with none.  This is necessary because the compiler will
812 * infer MessageType to be nullable if the value parameter is nullable.
813 * @template MessageTypeNonNull :=
814 *     cond(isUnknown(MessageType), unknown(),
815 *       mapunion(MessageType, (X) =>
816 *         cond(eq(X, 'null'), none(), X)))
817 * =:
818 */
819jspb.BinaryWriter.prototype.writeMessageSet = function(
820    field, value, writerCallback) {
821  if (value == null) return;
822  // The wire format for a message set is defined by
823  // google3/net/proto/message_set.proto
824  this.writeFieldHeader_(1, jspb.BinaryConstants.WireType.START_GROUP);
825  this.writeFieldHeader_(2, jspb.BinaryConstants.WireType.VARINT);
826  this.encoder_.writeSignedVarint32(field);
827  var bookmark = this.beginDelimited_(3);
828  writerCallback(value, this);
829  this.endDelimited_(bookmark);
830  this.writeFieldHeader_(1, jspb.BinaryConstants.WireType.END_GROUP);
831};
832
833
834/**
835 * Writes a group message to the buffer.
836 *
837 * @param {number} field The field number.
838 * @param {?MessageType} value The message to write, wrapped with START_GROUP /
839 *     END_GROUP tags. Will be a no-op if 'value' is null.
840 * @param {function(MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
841 *     Will be invoked with the value to write and the writer to write it with.
842 * @template MessageType
843 * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
844 * the null in blah|null with none.  This is necessary because the compiler will
845 * infer MessageType to be nullable if the value parameter is nullable.
846 * @template MessageTypeNonNull :=
847 *     cond(isUnknown(MessageType), unknown(),
848 *       mapunion(MessageType, (X) =>
849 *         cond(eq(X, 'null'), none(), X)))
850 * =:
851 */
852jspb.BinaryWriter.prototype.writeGroup = function(
853    field, value, writerCallback) {
854  if (value == null) return;
855  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP);
856  writerCallback(value, this);
857  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP);
858};
859
860
861/**
862 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
863 * the buffer.
864 * @param {number} field The field number.
865 * @param {string?} value The hash string.
866 */
867jspb.BinaryWriter.prototype.writeFixedHash64 = function(field, value) {
868  if (value == null) return;
869  goog.asserts.assert(value.length == 8);
870  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
871  this.encoder_.writeFixedHash64(value);
872};
873
874
875/**
876 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
877 * the buffer.
878 * @param {number} field The field number.
879 * @param {string?} value The hash string.
880 */
881jspb.BinaryWriter.prototype.writeVarintHash64 = function(field, value) {
882  if (value == null) return;
883  goog.asserts.assert(value.length == 8);
884  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
885  this.encoder_.writeVarintHash64(value);
886};
887
888
889/**
890 * Writes an array of numbers to the buffer as a repeated 32-bit int field.
891 * @param {number} field The field number.
892 * @param {?Array<number>} value The array of ints to write.
893 */
894jspb.BinaryWriter.prototype.writeRepeatedInt32 = function(field, value) {
895  if (value == null) return;
896  for (var i = 0; i < value.length; i++) {
897    this.writeSignedVarint32_(field, value[i]);
898  }
899};
900
901
902/**
903 * Writes an array of numbers formatted as strings to the buffer as a repeated
904 * 32-bit int field.
905 * @param {number} field The field number.
906 * @param {?Array<string>} value The array of ints to write.
907 */
908jspb.BinaryWriter.prototype.writeRepeatedInt32String = function(field, value) {
909  if (value == null) return;
910  for (var i = 0; i < value.length; i++) {
911    this.writeInt32String(field, value[i]);
912  }
913};
914
915
916/**
917 * Writes an array of numbers to the buffer as a repeated 64-bit int field.
918 * @param {number} field The field number.
919 * @param {?Array<number>} value The array of ints to write.
920 */
921jspb.BinaryWriter.prototype.writeRepeatedInt64 = function(field, value) {
922  if (value == null) return;
923  for (var i = 0; i < value.length; i++) {
924    this.writeSignedVarint64_(field, value[i]);
925  }
926};
927
928
929/**
930 * Writes an array of numbers formatted as strings to the buffer as a repeated
931 * 64-bit int field.
932 * @param {number} field The field number.
933 * @param {?Array<string>} value The array of ints to write.
934 */
935jspb.BinaryWriter.prototype.writeRepeatedInt64String = function(field, value) {
936  if (value == null) return;
937  for (var i = 0; i < value.length; i++) {
938    this.writeInt64String(field, value[i]);
939  }
940};
941
942
943/**
944 * Writes an array numbers to the buffer as a repeated unsigned 32-bit int
945 *     field.
946 * @param {number} field The field number.
947 * @param {?Array<number>} value The array of ints to write.
948 */
949jspb.BinaryWriter.prototype.writeRepeatedUint32 = function(field, value) {
950  if (value == null) return;
951  for (var i = 0; i < value.length; i++) {
952    this.writeUnsignedVarint32_(field, value[i]);
953  }
954};
955
956
957/**
958 * Writes an array of numbers formatted as strings to the buffer as a repeated
959 * unsigned 32-bit int field.
960 * @param {number} field The field number.
961 * @param {?Array<string>} value The array of ints to write.
962 */
963jspb.BinaryWriter.prototype.writeRepeatedUint32String = function(field, value) {
964  if (value == null) return;
965  for (var i = 0; i < value.length; i++) {
966    this.writeUint32String(field, value[i]);
967  }
968};
969
970
971/**
972 * Writes an array numbers to the buffer as a repeated unsigned 64-bit int
973 *     field.
974 * @param {number} field The field number.
975 * @param {?Array<number>} value The array of ints to write.
976 */
977jspb.BinaryWriter.prototype.writeRepeatedUint64 = function(field, value) {
978  if (value == null) return;
979  for (var i = 0; i < value.length; i++) {
980    this.writeUnsignedVarint64_(field, value[i]);
981  }
982};
983
984
985/**
986 * Writes an array of numbers formatted as strings to the buffer as a repeated
987 * unsigned 64-bit int field.
988 * @param {number} field The field number.
989 * @param {?Array<string>} value The array of ints to write.
990 */
991jspb.BinaryWriter.prototype.writeRepeatedUint64String = function(field, value) {
992  if (value == null) return;
993  for (var i = 0; i < value.length; i++) {
994    this.writeUint64String(field, value[i]);
995  }
996};
997
998
999/**
1000 * Writes an array numbers to the buffer as a repeated signed 32-bit int field.
1001 * @param {number} field The field number.
1002 * @param {?Array<number>} value The array of ints to write.
1003 */
1004jspb.BinaryWriter.prototype.writeRepeatedSint32 = function(field, value) {
1005  if (value == null) return;
1006  for (var i = 0; i < value.length; i++) {
1007    this.writeZigzagVarint32_(field, value[i]);
1008  }
1009};
1010
1011
1012/**
1013 * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
1014 * @param {number} field The field number.
1015 * @param {?Array<number>} value The array of ints to write.
1016 */
1017jspb.BinaryWriter.prototype.writeRepeatedSint64 = function(field, value) {
1018  if (value == null) return;
1019  for (var i = 0; i < value.length; i++) {
1020    this.writeZigzagVarint64_(field, value[i]);
1021  }
1022};
1023
1024
1025/**
1026 * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
1027 * @param {number} field The field number.
1028 * @param {?Array<string>} value The array of ints to write.
1029 */
1030jspb.BinaryWriter.prototype.writeRepeatedSint64String = function(field, value) {
1031  if (value == null) return;
1032  for (var i = 0; i < value.length; i++) {
1033    this.writeZigzagVarint64String_(field, value[i]);
1034  }
1035};
1036
1037
1038/**
1039 * Writes an array of numbers to the buffer as a repeated fixed32 field. This
1040 * works for both signed and unsigned fixed32s.
1041 * @param {number} field The field number.
1042 * @param {?Array<number>} value The array of ints to write.
1043 */
1044jspb.BinaryWriter.prototype.writeRepeatedFixed32 = function(field, value) {
1045  if (value == null) return;
1046  for (var i = 0; i < value.length; i++) {
1047    this.writeFixed32(field, value[i]);
1048  }
1049};
1050
1051
1052/**
1053 * Writes an array of numbers to the buffer as a repeated fixed64 field. This
1054 * works for both signed and unsigned fixed64s.
1055 * @param {number} field The field number.
1056 * @param {?Array<number>} value The array of ints to write.
1057 */
1058jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(field, value) {
1059  if (value == null) return;
1060  for (var i = 0; i < value.length; i++) {
1061    this.writeFixed64(field, value[i]);
1062  }
1063};
1064
1065
1066/**
1067 * Writes an array of numbers to the buffer as a repeated fixed64 field. This
1068 * works for both signed and unsigned fixed64s.
1069 * @param {number} field The field number.
1070 * @param {?Array<string>} value The array of decimal strings to write.
1071 */
1072jspb.BinaryWriter.prototype.writeRepeatedFixed64String = function(
1073    field, value) {
1074  if (value == null) return;
1075  for (var i = 0; i < value.length; i++) {
1076    this.writeFixed64String(field, value[i]);
1077  }
1078};
1079
1080
1081/**
1082 * Writes an array of numbers to the buffer as a repeated sfixed32 field.
1083 * @param {number} field The field number.
1084 * @param {?Array<number>} value The array of ints to write.
1085 */
1086jspb.BinaryWriter.prototype.writeRepeatedSfixed32 = function(field, value) {
1087  if (value == null) return;
1088  for (var i = 0; i < value.length; i++) {
1089    this.writeSfixed32(field, value[i]);
1090  }
1091};
1092
1093
1094/**
1095 * Writes an array of numbers to the buffer as a repeated sfixed64 field.
1096 * @param {number} field The field number.
1097 * @param {?Array<number>} value The array of ints to write.
1098 */
1099jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(field, value) {
1100  if (value == null) return;
1101  for (var i = 0; i < value.length; i++) {
1102    this.writeSfixed64(field, value[i]);
1103  }
1104};
1105
1106
1107/**
1108 * Writes an array of decimal strings to the buffer as a repeated sfixed64
1109 * field.
1110 * @param {number} field The field number.
1111 * @param {?Array<string>} value The array of decimal strings to write.
1112 */
1113jspb.BinaryWriter.prototype.writeRepeatedSfixed64String = function(field, value) {
1114  if (value == null) return;
1115  for (var i = 0; i < value.length; i++) {
1116    this.writeSfixed64String(field, value[i]);
1117  }
1118};
1119
1120
1121/**
1122 * Writes an array of numbers to the buffer as a repeated float field.
1123 * @param {number} field The field number.
1124 * @param {?Array<number>} value The array of ints to write.
1125 */
1126jspb.BinaryWriter.prototype.writeRepeatedFloat = function(field, value) {
1127  if (value == null) return;
1128  for (var i = 0; i < value.length; i++) {
1129    this.writeFloat(field, value[i]);
1130  }
1131};
1132
1133
1134/**
1135 * Writes an array of numbers to the buffer as a repeated double field.
1136 * @param {number} field The field number.
1137 * @param {?Array<number>} value The array of ints to write.
1138 */
1139jspb.BinaryWriter.prototype.writeRepeatedDouble = function(field, value) {
1140  if (value == null) return;
1141  for (var i = 0; i < value.length; i++) {
1142    this.writeDouble(field, value[i]);
1143  }
1144};
1145
1146
1147/**
1148 * Writes an array of booleans to the buffer as a repeated bool field.
1149 * @param {number} field The field number.
1150 * @param {?Array<boolean>} value The array of ints to write.
1151 */
1152jspb.BinaryWriter.prototype.writeRepeatedBool = function(field, value) {
1153  if (value == null) return;
1154  for (var i = 0; i < value.length; i++) {
1155    this.writeBool(field, value[i]);
1156  }
1157};
1158
1159
1160/**
1161 * Writes an array of enums to the buffer as a repeated enum field.
1162 * @param {number} field The field number.
1163 * @param {?Array<number>} value The array of ints to write.
1164 */
1165jspb.BinaryWriter.prototype.writeRepeatedEnum = function(field, value) {
1166  if (value == null) return;
1167  for (var i = 0; i < value.length; i++) {
1168    this.writeEnum(field, value[i]);
1169  }
1170};
1171
1172
1173/**
1174 * Writes an array of strings to the buffer as a repeated string field.
1175 * @param {number} field The field number.
1176 * @param {?Array<string>} value The array of strings to write.
1177 */
1178jspb.BinaryWriter.prototype.writeRepeatedString = function(field, value) {
1179  if (value == null) return;
1180  for (var i = 0; i < value.length; i++) {
1181    this.writeString(field, value[i]);
1182  }
1183};
1184
1185
1186/**
1187 * Writes an array of arbitrary byte fields to the buffer.
1188 * @param {number} field The field number.
1189 * @param {?Array<!jspb.ByteSource>} value The arrays of arrays of bytes to
1190 *     write.
1191 */
1192jspb.BinaryWriter.prototype.writeRepeatedBytes = function(field, value) {
1193  if (value == null) return;
1194  for (var i = 0; i < value.length; i++) {
1195    this.writeBytes(field, value[i]);
1196  }
1197};
1198
1199
1200/**
1201 * Writes an array of messages to the buffer.
1202 * @template MessageType
1203 * @param {number} field The field number.
1204 * @param {?Array<MessageType>} value The array of messages to
1205 *    write.
1206 * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
1207 *     Will be invoked with the value to write and the writer to write it with.
1208 */
1209jspb.BinaryWriter.prototype.writeRepeatedMessage = function(
1210    field, value, writerCallback) {
1211  if (value == null) return;
1212  for (var i = 0; i < value.length; i++) {
1213    var bookmark = this.beginDelimited_(field);
1214    writerCallback(value[i], this);
1215    this.endDelimited_(bookmark);
1216  }
1217};
1218
1219
1220/**
1221 * Writes an array of group messages to the buffer.
1222 * @template MessageType
1223 * @param {number} field The field number.
1224 * @param {?Array<MessageType>} value The array of messages to
1225 *    write.
1226 * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
1227 *     Will be invoked with the value to write and the writer to write it with.
1228 */
1229jspb.BinaryWriter.prototype.writeRepeatedGroup = function(
1230    field, value, writerCallback) {
1231  if (value == null) return;
1232  for (var i = 0; i < value.length; i++) {
1233    this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP);
1234    writerCallback(value[i], this);
1235    this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP);
1236  }
1237};
1238
1239
1240/**
1241 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
1242 * the buffer.
1243 * @param {number} field The field number.
1244 * @param {?Array<string>} value The array of hashes to write.
1245 */
1246jspb.BinaryWriter.prototype.writeRepeatedFixedHash64 =
1247    function(field, value) {
1248  if (value == null) return;
1249  for (var i = 0; i < value.length; i++) {
1250    this.writeFixedHash64(field, value[i]);
1251  }
1252};
1253
1254
1255/**
1256 * Writes a repeated 64-bit hash string field (8 characters @ 8 bits of data
1257 * each) to the buffer.
1258 * @param {number} field The field number.
1259 * @param {?Array<string>} value The array of hashes to write.
1260 */
1261jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 =
1262    function(field, value) {
1263  if (value == null) return;
1264  for (var i = 0; i < value.length; i++) {
1265    this.writeVarintHash64(field, value[i]);
1266  }
1267};
1268
1269
1270/**
1271 * Writes an array of numbers to the buffer as a packed 32-bit int field.
1272 * @param {number} field The field number.
1273 * @param {?Array<number>} value The array of ints to write.
1274 */
1275jspb.BinaryWriter.prototype.writePackedInt32 = function(field, value) {
1276  if (value == null || !value.length) return;
1277  var bookmark = this.beginDelimited_(field);
1278  for (var i = 0; i < value.length; i++) {
1279    this.encoder_.writeSignedVarint32(value[i]);
1280  }
1281  this.endDelimited_(bookmark);
1282};
1283
1284
1285/**
1286 * Writes an array of numbers represented as strings to the buffer as a packed
1287 * 32-bit int field.
1288 * @param {number} field
1289 * @param {?Array<string>} value
1290 */
1291jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
1292  if (value == null || !value.length) return;
1293  var bookmark = this.beginDelimited_(field);
1294  for (var i = 0; i < value.length; i++) {
1295    this.encoder_.writeSignedVarint32(parseInt(value[i], 10));
1296  }
1297  this.endDelimited_(bookmark);
1298};
1299
1300
1301/**
1302 * Writes an array of numbers to the buffer as a packed 64-bit int field.
1303 * @param {number} field The field number.
1304 * @param {?Array<number>} value The array of ints to write.
1305 */
1306jspb.BinaryWriter.prototype.writePackedInt64 = function(field, value) {
1307  if (value == null || !value.length) return;
1308  var bookmark = this.beginDelimited_(field);
1309  for (var i = 0; i < value.length; i++) {
1310    this.encoder_.writeSignedVarint64(value[i]);
1311  }
1312  this.endDelimited_(bookmark);
1313};
1314
1315
1316/**
1317 * Writes an array of numbers represented as strings to the buffer as a packed
1318 * 64-bit int field.
1319 * @param {number} field
1320 * @param {?Array<string>} value
1321 */
1322jspb.BinaryWriter.prototype.writePackedInt64String = function(field, value) {
1323  if (value == null || !value.length) return;
1324  var bookmark = this.beginDelimited_(field);
1325  for (var i = 0; i < value.length; i++) {
1326    var num = jspb.arith.Int64.fromString(value[i]);
1327    this.encoder_.writeSplitVarint64(num.lo, num.hi);
1328  }
1329  this.endDelimited_(bookmark);
1330};
1331
1332
1333/**
1334 * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
1335 * @param {number} field The field number.
1336 * @param {?Array<number>} value The array of ints to write.
1337 */
1338jspb.BinaryWriter.prototype.writePackedUint32 = function(field, value) {
1339  if (value == null || !value.length) return;
1340  var bookmark = this.beginDelimited_(field);
1341  for (var i = 0; i < value.length; i++) {
1342    this.encoder_.writeUnsignedVarint32(value[i]);
1343  }
1344  this.endDelimited_(bookmark);
1345};
1346
1347
1348/**
1349 * Writes an array of numbers represented as strings to the buffer as a packed
1350 * unsigned 32-bit int field.
1351 * @param {number} field
1352 * @param {?Array<string>} value
1353 */
1354jspb.BinaryWriter.prototype.writePackedUint32String =
1355    function(field, value) {
1356  if (value == null || !value.length) return;
1357  var bookmark = this.beginDelimited_(field);
1358  for (var i = 0; i < value.length; i++) {
1359    this.encoder_.writeUnsignedVarint32(parseInt(value[i], 10));
1360  }
1361  this.endDelimited_(bookmark);
1362};
1363
1364
1365/**
1366 * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
1367 * @param {number} field The field number.
1368 * @param {?Array<number>} value The array of ints to write.
1369 */
1370jspb.BinaryWriter.prototype.writePackedUint64 = function(field, value) {
1371  if (value == null || !value.length) return;
1372  var bookmark = this.beginDelimited_(field);
1373  for (var i = 0; i < value.length; i++) {
1374    this.encoder_.writeUnsignedVarint64(value[i]);
1375  }
1376  this.endDelimited_(bookmark);
1377};
1378
1379
1380/**
1381 * Writes an array of numbers represented as strings to the buffer as a packed
1382 * unsigned 64-bit int field.
1383 * @param {number} field
1384 * @param {?Array<string>} value
1385 */
1386jspb.BinaryWriter.prototype.writePackedUint64String =
1387    function(field, value) {
1388  if (value == null || !value.length) return;
1389  var bookmark = this.beginDelimited_(field);
1390  for (var i = 0; i < value.length; i++) {
1391    var num = jspb.arith.UInt64.fromString(value[i]);
1392    this.encoder_.writeSplitVarint64(num.lo, num.hi);
1393  }
1394  this.endDelimited_(bookmark);
1395};
1396
1397
1398/**
1399 * Writes an array numbers to the buffer as a packed signed 32-bit int field.
1400 * @param {number} field The field number.
1401 * @param {?Array<number>} value The array of ints to write.
1402 */
1403jspb.BinaryWriter.prototype.writePackedSint32 = function(field, value) {
1404  if (value == null || !value.length) return;
1405  var bookmark = this.beginDelimited_(field);
1406  for (var i = 0; i < value.length; i++) {
1407    this.encoder_.writeZigzagVarint32(value[i]);
1408  }
1409  this.endDelimited_(bookmark);
1410};
1411
1412
1413/**
1414 * Writes an array of numbers to the buffer as a packed signed 64-bit int field.
1415 * @param {number} field The field number.
1416 * @param {?Array<number>} value The array of ints to write.
1417 */
1418jspb.BinaryWriter.prototype.writePackedSint64 = function(field, value) {
1419  if (value == null || !value.length) return;
1420  var bookmark = this.beginDelimited_(field);
1421  for (var i = 0; i < value.length; i++) {
1422    this.encoder_.writeZigzagVarint64(value[i]);
1423  }
1424  this.endDelimited_(bookmark);
1425};
1426
1427
1428/**
1429 * Writes an array of decimal strings to the buffer as a packed signed 64-bit
1430 * int field.
1431 * @param {number} field The field number.
1432 * @param {?Array<string>} value The array of decimal strings to write.
1433 */
1434jspb.BinaryWriter.prototype.writePackedSint64String = function(field, value) {
1435  if (value == null || !value.length) return;
1436  var bookmark = this.beginDelimited_(field);
1437  for (var i = 0; i < value.length; i++) {
1438    // TODO(haberman): make lossless
1439    this.encoder_.writeZigzagVarint64(parseInt(value[i], 10));
1440  }
1441  this.endDelimited_(bookmark);
1442};
1443
1444
1445/**
1446 * Writes an array of numbers to the buffer as a packed fixed32 field.
1447 * @param {number} field The field number.
1448 * @param {?Array<number>} value The array of ints to write.
1449 */
1450jspb.BinaryWriter.prototype.writePackedFixed32 = function(field, value) {
1451  if (value == null || !value.length) return;
1452  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1453  this.encoder_.writeUnsignedVarint32(value.length * 4);
1454  for (var i = 0; i < value.length; i++) {
1455    this.encoder_.writeUint32(value[i]);
1456  }
1457};
1458
1459
1460/**
1461 * Writes an array of numbers to the buffer as a packed fixed64 field.
1462 * @param {number} field The field number.
1463 * @param {?Array<number>} value The array of ints to write.
1464 */
1465jspb.BinaryWriter.prototype.writePackedFixed64 = function(field, value) {
1466  if (value == null || !value.length) return;
1467  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1468  this.encoder_.writeUnsignedVarint32(value.length * 8);
1469  for (var i = 0; i < value.length; i++) {
1470    this.encoder_.writeUint64(value[i]);
1471  }
1472};
1473
1474
1475/**
1476 * Writes an array of numbers represented as strings to the buffer as a packed
1477 * fixed64 field.
1478 * @param {number} field The field number.
1479 * @param {?Array<string>} value The array of strings to write.
1480 */
1481jspb.BinaryWriter.prototype.writePackedFixed64String = function(field, value) {
1482  if (value == null || !value.length) return;
1483  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1484  this.encoder_.writeUnsignedVarint32(value.length * 8);
1485  for (var i = 0; i < value.length; i++) {
1486    var num = jspb.arith.UInt64.fromString(value[i]);
1487    this.encoder_.writeSplitFixed64(num.lo, num.hi);
1488  }
1489};
1490
1491
1492/**
1493 * Writes an array of numbers to the buffer as a packed sfixed32 field.
1494 * @param {number} field The field number.
1495 * @param {?Array<number>} value The array of ints to write.
1496 */
1497jspb.BinaryWriter.prototype.writePackedSfixed32 = function(field, value) {
1498  if (value == null || !value.length) return;
1499  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1500  this.encoder_.writeUnsignedVarint32(value.length * 4);
1501  for (var i = 0; i < value.length; i++) {
1502    this.encoder_.writeInt32(value[i]);
1503  }
1504};
1505
1506
1507/**
1508 * Writes an array of numbers to the buffer as a packed sfixed64 field.
1509 * @param {number} field The field number.
1510 * @param {?Array<number>} value The array of ints to write.
1511 */
1512jspb.BinaryWriter.prototype.writePackedSfixed64 = function(field, value) {
1513  if (value == null || !value.length) return;
1514  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1515  this.encoder_.writeUnsignedVarint32(value.length * 8);
1516  for (var i = 0; i < value.length; i++) {
1517    this.encoder_.writeInt64(value[i]);
1518  }
1519};
1520
1521
1522/**
1523 * Writes an array of numbers to the buffer as a packed sfixed64 field.
1524 * @param {number} field The field number.
1525 * @param {?Array<string>} value The array of decimal strings to write.
1526 */
1527jspb.BinaryWriter.prototype.writePackedSfixed64String = function(field, value) {
1528  if (value == null || !value.length) return;
1529  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1530  this.encoder_.writeUnsignedVarint32(value.length * 8);
1531  for (var i = 0; i < value.length; i++) {
1532    this.encoder_.writeInt64String(value[i]);
1533  }
1534};
1535
1536
1537/**
1538 * Writes an array of numbers to the buffer as a packed float field.
1539 * @param {number} field The field number.
1540 * @param {?Array<number>} value The array of ints to write.
1541 */
1542jspb.BinaryWriter.prototype.writePackedFloat = function(field, value) {
1543  if (value == null || !value.length) return;
1544  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1545  this.encoder_.writeUnsignedVarint32(value.length * 4);
1546  for (var i = 0; i < value.length; i++) {
1547    this.encoder_.writeFloat(value[i]);
1548  }
1549};
1550
1551
1552/**
1553 * Writes an array of numbers to the buffer as a packed double field.
1554 * @param {number} field The field number.
1555 * @param {?Array<number>} value The array of ints to write.
1556 */
1557jspb.BinaryWriter.prototype.writePackedDouble = function(field, value) {
1558  if (value == null || !value.length) return;
1559  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1560  this.encoder_.writeUnsignedVarint32(value.length * 8);
1561  for (var i = 0; i < value.length; i++) {
1562    this.encoder_.writeDouble(value[i]);
1563  }
1564};
1565
1566
1567/**
1568 * Writes an array of booleans to the buffer as a packed bool field.
1569 * @param {number} field The field number.
1570 * @param {?Array<boolean>} value The array of ints to write.
1571 */
1572jspb.BinaryWriter.prototype.writePackedBool = function(field, value) {
1573  if (value == null || !value.length) return;
1574  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1575  this.encoder_.writeUnsignedVarint32(value.length);
1576  for (var i = 0; i < value.length; i++) {
1577    this.encoder_.writeBool(value[i]);
1578  }
1579};
1580
1581
1582/**
1583 * Writes an array of enums to the buffer as a packed enum field.
1584 * @param {number} field The field number.
1585 * @param {?Array<number>} value The array of ints to write.
1586 */
1587jspb.BinaryWriter.prototype.writePackedEnum = function(field, value) {
1588  if (value == null || !value.length) return;
1589  var bookmark = this.beginDelimited_(field);
1590  for (var i = 0; i < value.length; i++) {
1591    this.encoder_.writeEnum(value[i]);
1592  }
1593  this.endDelimited_(bookmark);
1594};
1595
1596
1597/**
1598 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
1599 * the buffer.
1600 * @param {number} field The field number.
1601 * @param {?Array<string>} value The array of hashes to write.
1602 */
1603jspb.BinaryWriter.prototype.writePackedFixedHash64 = function(field, value) {
1604  if (value == null || !value.length) return;
1605  this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
1606  this.encoder_.writeUnsignedVarint32(value.length * 8);
1607  for (var i = 0; i < value.length; i++) {
1608    this.encoder_.writeFixedHash64(value[i]);
1609  }
1610};
1611
1612
1613/**
1614 * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
1615 * the buffer.
1616 * @param {number} field The field number.
1617 * @param {?Array<string>} value The array of hashes to write.
1618 */
1619jspb.BinaryWriter.prototype.writePackedVarintHash64 = function(field, value) {
1620  if (value == null || !value.length) return;
1621  var bookmark = this.beginDelimited_(field);
1622  for (var i = 0; i < value.length; i++) {
1623    this.encoder_.writeVarintHash64(value[i]);
1624  }
1625  this.endDelimited_(bookmark);
1626};
1627