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