| /** |
| * @fileoverview This file contains utilities for encoding Javascript objects |
| * into binary, wire-format protocol buffers (in the form of Uint8Arrays) that |
| * a server can consume directly. |
| * |
| * jspb's BinaryWriter class defines methods for efficiently encoding |
| * Javascript objects into binary, wire-format protocol buffers and supports |
| * all the fundamental field types used in protocol buffers. |
| * |
| * Major caveat 1 - Users of this library _must_ keep their Javascript proto |
| * parsing code in sync with the original .proto file - presumably you'll be |
| * using the typed jspb code generator, but if you bypass that you'll need |
| * to keep things in sync by hand. |
| * |
| * Major caveat 2 - Javascript is unable to accurately represent integers |
| * larger than 2^53 due to its use of a double-precision floating point format |
| * for all numbers. BinaryWriter does not make any special effort to preserve |
| * precision for values above this limit - if you need to pass 64-bit integers |
| * (hash codes, for example) between the client and server without precision |
| * loss, do _not_ use this library. |
| * |
| * Major caveat 3 - This class uses typed arrays and must not be used on older |
| * browsers that do not support them. |
| * |
| * @author aappleby@google.com (Austin Appleby) |
| */ |
| |
| goog.module('jspb.binary.writer'); |
| goog.module.declareLegacyNamespace(); |
| |
| const { Alphabet, encodeByteArray: encodeByteArraySlow } = goog.require('goog.crypt.base64'); |
| const { AnyFieldType } = goog.requireType('jspb.binary.any_field_type'); |
| const { BinaryEncoder } = goog.require('jspb.binary.encoder'); |
| const { ByteSource } = goog.requireType('jspb.binary.bytesource'); |
| const { ByteString } = goog.require('jspb.bytestring'); |
| const { FieldType, TWO_TO_31, TWO_TO_32, TWO_TO_63, TWO_TO_64, WireType } = goog.require('jspb.BinaryConstants'); |
| const { Int64, UInt64 } = goog.require('jspb.arith'); |
| const { assert, fail } = goog.require('goog.asserts'); |
| const { bufferFromSource } = goog.require('jspb.binary.internal_buffer'); |
| const { encodeByteArray } = goog.require('jspb.internal_bytes'); |
| const { encodeUtf8 } = goog.require('jspb.binary.utf8'); |
| const { makeTag } = goog.require('jspb.utils'); |
| const { unsafeByteStringFromUint8Array, unsafeUint8ArrayFromByteString } = goog.require('jspb.unsafe_bytestring'); |
| /** |
| * Whether to reject unpaired surrogates when encoding strings to utf8. |
| * |
| * <p>Currently set to `goog.DEBUG`, but can be disabled if needed. |
| * |
| * @define {boolean} |
| */ |
| const REJECT_UNPAIRED_SURROGATES = |
| goog.define('jspb.binary.REJECT_UNPAIRED_SURROGATES', goog.DEBUG); |
| |
| /** |
| * BinaryWriter implements encoders for all the wire types specified in |
| * https://developers.google.com/protocol-buffers/docs/encoding. |
| */ |
| class BinaryWriter { |
| constructor() { |
| /** |
| * Blocks of serialized data that will be concatenated once all messages |
| * have been written. |
| * @private {!Array<!Uint8Array|!Array<number>>} |
| */ |
| this.blocks_ = []; |
| |
| /** |
| * Total number of bytes in the blocks_ array. Does _not_ include bytes in |
| * the encoder below. |
| * @private {number} |
| */ |
| this.totalLength_ = 0; |
| |
| /** |
| * Binary encoder holding pieces of a message that we're still serializing. |
| * When we get to a stopping point (either the start of a new submessage, or |
| * when we need to append a raw Uint8Array), the encoder's buffer will be |
| * added to the block array above and the encoder will be reset. |
| * @private @const {!BinaryEncoder} |
| */ |
| this.encoder_ = new BinaryEncoder(); |
| } |
| |
| /** @private*/ |
| pushBlock(/** !Array<number>|!Uint8Array */ buffer) { |
| // Repeated calls to appendUint8Arrays may produce empty arrays from the |
| // encoder, avoid storing these in our list of blocks. |
| if (buffer.length !== 0) { |
| this.blocks_.push(buffer); |
| this.totalLength_ += buffer.length; |
| } |
| } |
| |
| /** |
| * Append a typed array of bytes onto the buffer. |
| * |
| * @param {!Uint8Array} arr The byte array to append. |
| * @private |
| */ |
| appendUint8Array_(arr) { |
| this.pushBlock(this.encoder_.end()); |
| this.pushBlock(arr); |
| } |
| |
| /** |
| * Begins a new message by writing the field header and returning a bookmark |
| * which we will use to patch in the message length to in endDelimited_ below. |
| * @param {number} field |
| * @return {!Array<number>} |
| * @private |
| */ |
| beginDelimited_(field) { |
| this.writeFieldHeader_(field, WireType.DELIMITED); |
| const bookmark = this.encoder_.end(); |
| this.pushBlock(bookmark); |
| bookmark.push( |
| this.totalLength_); // store the current length in the bookmark |
| return bookmark; |
| } |
| |
| /** |
| * Ends a message by encoding the _change_ in length of the buffer to the |
| * parent block and adds the number of bytes needed to encode that length to |
| * the total byte length. |
| * @param {!Array<number>} bookmark |
| * @private |
| */ |
| endDelimited_(bookmark) { |
| const oldLength = bookmark.pop(); |
| let messageLength = this.totalLength_ + this.encoder_.length() - oldLength; |
| assert(messageLength >= 0); |
| |
| while (messageLength > 127) { |
| bookmark.push((messageLength & 0x7f) | 0x80); |
| messageLength = messageLength >>> 7; |
| this.totalLength_++; |
| } |
| |
| bookmark.push(messageLength); |
| this.totalLength_++; |
| } |
| |
| /** |
| * Writes unknown fields to the output if there are any. |
| */ |
| writeUnknownFields(/** !Array<!ByteString> */ unknownFields) { |
| this.pushBlock(this.encoder_.end()); |
| for (let i = 0; i < unknownFields.length; i++) { |
| // Unsafe access is ok here since arrays added to our output are always |
| // copied before returning to the user. |
| this.pushBlock(unsafeUint8ArrayFromByteString(unknownFields[i])); |
| } |
| } |
| |
| /** |
| * Writes a pre-serialized message to the buffer. |
| * @param {!Uint8Array} bytes The array of bytes to write. |
| * @param {number} start The start of the range to write. |
| * @param {number} end The end of the range to write. |
| */ |
| writeSerializedMessage(bytes, start, end) { |
| this.appendUint8Array_(bytes.subarray(start, end)); |
| } |
| |
| /** |
| * Writes a pre-serialized message to the buffer if the message and endpoints |
| * are non-null. |
| * @param {?Uint8Array} bytes The array of bytes to write. |
| * @param {?number} start The start of the range to write. |
| * @param {?number} end The end of the range to write. |
| */ |
| maybeWriteSerializedMessage(bytes, start, end) { |
| if (bytes != null && start != null && end != null) { |
| this.writeSerializedMessage(bytes, start, end); |
| } |
| } |
| |
| /** |
| * Resets the writer, throwing away any accumulated buffers. |
| */ |
| reset() { |
| this.blocks_ = []; |
| this.encoder_.end(); |
| this.totalLength_ = 0; |
| } |
| |
| /** |
| * Converts the encoded data into a Uint8Array. |
| * @return {!Uint8Array} |
| */ |
| getResultBuffer() { |
| // flush the encoder to avoid a special case below. |
| this.pushBlock(this.encoder_.end()); |
| const resultLength = this.totalLength_; |
| // NOTE: some of the Uint8Arrays stored in blocks_ are backing stores for |
| // ByteString objects and so we should be careful not to leak references to |
| // them from here. i.o.w. don't add an optimization that directly returns |
| // references to things in blocks. |
| const flat = new Uint8Array(resultLength); |
| const blocks = this.blocks_; |
| const blockCount = blocks.length; |
| let offset = 0; |
| |
| for (let i = 0; i < blockCount; i++) { |
| const block = blocks[i]; |
| flat.set(block, offset); |
| offset += block.length; |
| } |
| |
| // Post condition: `flattened` must have had every byte written. |
| assert(offset == flat.length); |
| |
| // Replace our block list with the flattened block, which lets GC reclaim |
| // the temp blocks sooner. |
| this.blocks_ = [flat]; |
| |
| return flat; |
| } |
| |
| /** |
| * Converts the encoded data into a ByteString. |
| * @return {!ByteString} |
| */ |
| getResultBufferAsByteString() { |
| // Note that this is safe because we never leak or mutate the Uint8Array |
| // returned by getResultBuffer even though it's stored in `blocks_`. |
| return unsafeByteStringFromUint8Array(this.getResultBuffer()); |
| } |
| |
| /** |
| * Converts the encoded data into a base64-encoded string. |
| * @param {!Alphabet=} alphabet Which flavor of base64 to |
| * use. |
| * @return {string} |
| */ |
| getResultBase64String(alphabet) { |
| if (alphabet === undefined) { |
| return encodeByteArray(this.getResultBuffer()); |
| } else { |
| return encodeByteArraySlow(this.getResultBuffer(), alphabet); |
| } |
| } |
| |
| /** |
| * Encodes a (field number, wire type) tuple into a wire-format field header |
| * and stores it in the buffer as a varint. |
| * @param {number} field The field number. |
| * @param {!WireType} wireType The wire-type of the field, as specified in the |
| * protocol buffer documentation. |
| * @private |
| */ |
| writeFieldHeader_(field, wireType) { |
| assert(field >= 1 && field == Math.floor(field)); |
| this.encoder_.writeUnsignedVarint32(makeTag(field, wireType)); |
| } |
| |
| // TODO(b/221101646): Maybe update AnyFieldType to include ByteString. |
| /** |
| * Writes a field of any valid scalar type to the binary stream. |
| * @param {!FieldType} fieldType |
| * @param {number} field |
| * @param {!AnyFieldType|!ByteString} value |
| */ |
| writeAny(fieldType, field, value) { |
| switch (fieldType) { |
| case FieldType.DOUBLE: |
| this.writeDouble(field, /** @type {number} */(value)); |
| return; |
| case FieldType.FLOAT: |
| this.writeFloat(field, /** @type {number} */(value)); |
| return; |
| case FieldType.INT64: |
| this.writeInt64(field, /** @type {number} */(value)); |
| return; |
| case FieldType.UINT64: |
| this.writeUint64(field, /** @type {number} */(value)); |
| return; |
| case FieldType.INT32: |
| this.writeInt32(field, /** @type {number} */(value)); |
| return; |
| case FieldType.FIXED64: |
| this.writeFixed64(field, /** @type {number} */(value)); |
| return; |
| case FieldType.FIXED32: |
| this.writeFixed32(field, /** @type {number} */(value)); |
| return; |
| case FieldType.BOOL: |
| this.writeBool(field, /** @type {boolean} */(value)); |
| return; |
| case FieldType.STRING: |
| this.writeString(field, /** @type {string} */(value)); |
| return; |
| case FieldType.GROUP: |
| fail('Group field type not supported in writeAny()'); |
| return; |
| case FieldType.MESSAGE: |
| fail('Message field type not supported in writeAny()'); |
| return; |
| case FieldType.BYTES: |
| this.writeBytes(field, /** @type {?ByteSource|?ByteString} */(value)); |
| return; |
| case FieldType.UINT32: |
| this.writeUint32(field, /** @type {number} */(value)); |
| return; |
| case FieldType.ENUM: |
| this.writeEnum(field, /** @type {number} */(value)); |
| return; |
| case FieldType.SFIXED32: |
| this.writeSfixed32(field, /** @type {number} */(value)); |
| return; |
| case FieldType.SFIXED64: |
| this.writeSfixed64(field, /** @type {number} */(value)); |
| return; |
| case FieldType.SINT32: |
| this.writeSint32(field, /** @type {number} */(value)); |
| return; |
| case FieldType.SINT64: |
| this.writeSint64(field, /** @type {number} */(value)); |
| return; |
| default: |
| fail('Invalid field type in writeAny()'); |
| return; |
| } |
| } |
| |
| /** |
| * Writes a varint field to the buffer without range checking. |
| * @param {number} field The field number. |
| * @param {number|null|undefined} value The value to write. |
| * @private |
| */ |
| writeUnsignedVarint32_(field, value) { |
| if (value == null) return; |
| this.writeFieldHeader_(field, WireType.VARINT); |
| this.encoder_.writeUnsignedVarint32(value); |
| } |
| |
| /** |
| * Writes a varint field to the buffer without range checking. |
| * @param {number} field The field number. |
| * @param {number|null|undefined} value The value to write. |
| * @private |
| */ |
| writeSignedVarint32_(field, value) { |
| if (value == null) return; |
| assertSignedInteger(field, value); |
| this.writeFieldHeader_(field, WireType.VARINT); |
| this.encoder_.writeSignedVarint32(value); |
| } |
| |
| /** |
| * Writes a varint field to the buffer without range checking. |
| * @param {number} field The field number. |
| * @param {number|string|!bigint|null|undefined} value The value to write. |
| * @private |
| */ |
| writeUnsignedVarint64_(field, value) { |
| if (value == null) return; |
| this.writeFieldHeader_(field, WireType.VARINT); |
| switch (typeof value) { |
| case 'number': |
| this.encoder_.writeUnsignedVarint64(value); |
| break; |
| |
| case 'bigint': { |
| const num = UInt64.fromBigInt(/** @type {bigint} */(value)); |
| this.encoder_.writeSplitVarint64(num.lo, num.hi); |
| break; |
| } |
| |
| default: { |
| const num = UInt64.fromString(/** @type {string} */(value)); |
| this.encoder_.writeSplitVarint64(num.lo, num.hi); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Writes a varint field to the buffer without range checking. |
| * @param {number} field The field number. |
| * @param {number|string?|!bigint|null|undefined} value The value to write. |
| * @private |
| */ |
| writeSignedVarint64_(field, value) { |
| if (value == null) return; |
| this.writeFieldHeader_(field, WireType.VARINT); |
| switch (typeof value) { |
| case 'number': |
| this.encoder_.writeSignedVarint64(value); |
| break; |
| |
| case 'bigint': { |
| const num = Int64.fromBigInt(/** @type {bigint} */(value)); |
| this.encoder_.writeSplitVarint64(num.lo, num.hi); |
| break; |
| } |
| |
| default: { |
| const num = Int64.fromString(/** @type {string} */(value)); |
| this.encoder_.writeSplitVarint64(num.lo, num.hi); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Writes a zigzag varint field to the buffer without range checking. |
| * @param {number} field The field number. |
| * @param {number|null|undefined} value The value to write. |
| * @private |
| */ |
| writeZigzagVarint32_(field, value) { |
| if (value == null) return; |
| this.writeFieldHeader_(field, WireType.VARINT); |
| this.encoder_.writeZigzagVarint32(value); |
| } |
| |
| /** |
| * Writes a zigzag varint field to the buffer without range checking. |
| * @param {number} field The field number. |
| * @param {number|string|!bigint|null|undefined} value The value to write. |
| * @private |
| */ |
| writeZigzagVarint64_(field, value) { |
| if (value == null) return; |
| this.writeFieldHeader_(field, WireType.VARINT); |
| switch (typeof value) { |
| case 'number': |
| this.encoder_.writeZigzagVarint64(/** @type {number} */(value)); |
| break; |
| |
| default: |
| this.encoder_.writeZigzagVarint64String(/** @type {string} */(value)); |
| break; |
| } |
| } |
| |
| /** |
| * Writes an int32 field to the buffer. Numbers outside the range [-2^31,2^31) |
| * will be truncated. |
| * @param {number} field The field number. |
| * @param {number|null|undefined} value The value to write. |
| */ |
| writeInt32(field, value) { |
| if (value == null) return; |
| assertThat(field, value, (value >= -TWO_TO_31) && (value < TWO_TO_31)); |
| this.writeSignedVarint32_(field, value); |
| } |
| |
| /** |
| * Writes an int64 field to the buffer. Numbers outside the range [-2^63,2^63) |
| * will be truncated. |
| * @param {number} field The field number. |
| * @param {number|string|!bigint|null|undefined} value The value to write. |
| */ |
| writeInt64(field, value) { |
| if (value == null) return; |
| assertSignedInt64(field, value); |
| this.writeSignedVarint64_(field, value); |
| } |
| |
| /** |
| * Writes a int64 field (with value as a string) to the buffer. |
| * @param {number} field The field number. |
| * @param {string|null|undefined} value The value to write. |
| * @deprecated Use writeInt64() |
| */ |
| writeInt64String(field, value) { |
| this.writeInt64(field, value); |
| } |
| |
| /** |
| * Writes a uint32 field to the buffer. Numbers outside the range [0,2^32) |
| * will be truncated. |
| * @param {number} field The field number. |
| * @param {number|null|undefined} value The value to write. |
| */ |
| writeUint32(field, value) { |
| if (value == null) return; |
| assertThat(field, value, (value >= 0) && (value < TWO_TO_32)); |
| this.writeUnsignedVarint32_(field, value); |
| } |
| |
| |
| /** |
| * Writes a uint64 field to the buffer. Numbers outside the range [0,2^64) |
| * will be truncated. |
| * @param {number} field The field number. |
| * @param {number|string|!bigint|null|undefined} value The value to write. |
| */ |
| writeUint64(field, value) { |
| if (value == null) return; |
| assertUnsignedInt64(field, value); |
| this.writeUnsignedVarint64_(field, value); |
| } |
| |
| /** |
| * Writes a uint64 field (with value as a string) to the buffer. |
| * @param {number} field The field number. |
| * @param {string|null|undefined} value The value to write. |
| * @deprecated Use writeUint64() |
| */ |
| writeUint64String(field, value) { |
| this.writeUint64(field, value); |
| } |
| |
| /** |
| * Writes an sint32 field to the buffer. Numbers outside the range |
| * [-2^31,2^31) will be truncated. |
| * @param {number} field The field number. |
| * @param {number|null|undefined} value The value to write. |
| */ |
| writeSint32(field, value) { |
| if (value == null) return; |
| assertThat(field, value, (value >= -TWO_TO_31) && (value < TWO_TO_31)); |
| this.writeZigzagVarint32_(field, value); |
| } |
| |
| /** |
| * Writes an sint64 field to the buffer. Numbers outside the range |
| * [-2^63,2^63) will be truncated. |
| * @param {number} field The field number. |
| * @param {number|string|!bigint|null|undefined} value The value to write. |
| */ |
| writeSint64(field, value) { |
| if (value == null) return; |
| assertSignedInt64(field, value); |
| this.writeZigzagVarint64_(field, value); |
| } |
| |
| /** |
| * Writes an sint64 field to the buffer. Numbers outside the range |
| * [-2^63,2^63) will be truncated. |
| * @param {number} field The field number. |
| * @param {string|null|undefined} value The decimal string to write. |
| * @deprecated Use writeSint64(); |
| */ |
| writeSint64String(field, value) { |
| this.writeSint64(field, value); |
| } |
| |
| /** |
| * Writes a fixed32 field to the buffer. Numbers outside the range [0,2^32) |
| * will be truncated. |
| * @param {number} field The field number. |
| * @param {number|null|undefined} value The value to write. |
| */ |
| writeFixed32(field, value) { |
| if (value == null) return; |
| assertThat(field, value, (value >= 0) && (value < TWO_TO_32)); |
| this.writeFieldHeader_(field, WireType.FIXED32); |
| this.encoder_.writeUint32(value); |
| } |
| |
| /** |
| * Writes a fixed64 field to the buffer. Numbers outside the range [0,2^64) |
| * will be truncated. |
| * @param {number} field The field number. |
| * @param {number|string|!bigint|null|undefined} value The value to write. |
| */ |
| writeFixed64(field, value) { |
| if (value == null) return; |
| assertUnsignedInt64(field, value); |
| this.writeFieldHeader_(field, WireType.FIXED64); |
| switch (typeof value) { |
| case 'number': |
| this.encoder_.writeUint64(value); |
| break; |
| case 'bigint': { |
| const num = UInt64.fromBigInt(/** @type {bigint} */(value)); |
| this.encoder_.writeSplitFixed64(num.lo, num.hi); |
| break; |
| } |
| default: { |
| const num = UInt64.fromString(/** @type {string} */(value)); |
| this.encoder_.writeSplitFixed64(num.lo, num.hi); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Writes a fixed64 field (with value as a string) to the buffer. |
| * @param {number} field The field number. |
| * @param {string|null|undefined} value The value to write. |
| * @deprecated Use writeFixed64(). |
| */ |
| writeFixed64String(field, value) { |
| this.writeFixed64(field, value); |
| } |
| |
| /** |
| * Writes a sfixed32 field to the buffer. Numbers outside the range |
| * [-2^31,2^31) will be truncated. |
| * @param {number} field The field number. |
| * @param {number|null|undefined} value The value to write. |
| */ |
| writeSfixed32(field, value) { |
| if (value == null) return; |
| assertThat(field, value, (value >= -TWO_TO_31) && (value < TWO_TO_31)); |
| this.writeFieldHeader_(field, WireType.FIXED32); |
| this.encoder_.writeInt32(value); |
| } |
| |
| /** |
| * Writes a sfixed64 field to the buffer. Numbers outside the range |
| * [-2^63,2^63) will be truncated. |
| * @param {number} field The field number. |
| * @param {number|string|!bigint|null|undefined} value The value to write. |
| */ |
| writeSfixed64(field, value) { |
| if (value == null) return; |
| assertSignedInt64(field, value); |
| this.writeFieldHeader_(field, WireType.FIXED64); |
| switch (typeof value) { |
| case 'number': |
| this.encoder_.writeInt64(value); |
| break; |
| case 'bigint': |
| const int64Big = Int64.fromBigInt(/** @type {bigint} */(value)); |
| this.encoder_.writeSplitFixed64(int64Big.lo, int64Big.hi); |
| break; |
| default: |
| const int64Str = Int64.fromString(/** @type {string} */(value)); |
| this.encoder_.writeSplitFixed64(int64Str.lo, int64Str.hi); |
| break; |
| } |
| } |
| |
| /** |
| * Writes a sfixed64 string field to the buffer. Numbers outside the range |
| * [-2^63,2^63) will be truncated. |
| * @param {number} field The field number. |
| * @param {string|null|undefined} value The value to write. |
| * @deprecated Use writeSfixed64(). |
| */ |
| writeSfixed64String(field, value) { |
| this.writeSfixed64(field, value); |
| } |
| |
| /** |
| * Writes a single-precision floating point field to the buffer. Numbers |
| * requiring more than 32 bits of precision will be truncated. |
| * @param {number} field The field number. |
| * @param {number?|string|null|undefined} value The value to write, accepts |
| * 'Infinity'/'-Infinity'/'NaN' for JSPB wire format compatibility. |
| */ |
| writeFloat(field, value) { |
| if (value == null) return; |
| this.writeFieldHeader_(field, WireType.FIXED32); |
| this.encoder_.writeFloat(value); |
| } |
| |
| /** |
| * Writes a double-precision floating point field to the buffer. As this is |
| * the native format used by JavaScript, no precision will be lost. |
| * @param {number} field The field number. |
| * @param {number?|string|null|undefined} value The value to write, accepts |
| * 'Infinity'/'-Infinity'/'NaN' for JSPB wire format compatibility. |
| */ |
| writeDouble(field, value) { |
| if (value == null) return; |
| this.writeFieldHeader_(field, WireType.FIXED64); |
| this.encoder_.writeDouble(value); |
| } |
| |
| /** |
| * Writes a boolean field to the buffer. We allow numbers as input |
| * because the JSPB code generator uses 0/1 instead of true/false to save |
| * space in the string representation of the proto. |
| * @param {number} field The field number. |
| * @param {boolean?|number|null|undefined} value The value to write. |
| */ |
| writeBool(field, value) { |
| if (value == null) return; |
| assertThat( |
| field, value, typeof value === 'boolean' || typeof value === 'number'); |
| this.writeFieldHeader_(field, WireType.VARINT); |
| this.encoder_.writeBool(value); |
| } |
| |
| /** |
| * Writes an enum field to the buffer. |
| * @param {number} field The field number. |
| * @param {number|null|undefined} value The value to write. |
| */ |
| writeEnum(field, value) { |
| if (value == null) return; |
| // Converting since value might be object typed integer here. |
| const intValue = /** number */ parseInt(value, 10); |
| assertSignedInteger(field, intValue); |
| this.writeFieldHeader_(field, WireType.VARINT); |
| this.encoder_.writeSignedVarint32(intValue); |
| } |
| |
| /** |
| * Writes a string field to the buffer. |
| * @param {number} field The field number. |
| * @param {string|null|undefined} value The string to write. |
| */ |
| writeString(field, value) { |
| if (value == null) return; |
| this.writeUint8Array( |
| field, |
| encodeUtf8( |
| value, /** rejectUnpairedSurrogates=*/ REJECT_UNPAIRED_SURROGATES)); |
| } |
| |
| /** |
| * Writes an arbitrary byte field to the buffer. Note - to match the behavior |
| * of the C++ implementation, empty byte arrays _are_ serialized. |
| * @param {number} field The field number. |
| * @param {?ByteSource|?ByteString|undefined} value The array of bytes to |
| * write. |
| */ |
| writeBytes(field, value) { |
| if (value == null) return; |
| this.writeUint8Array( |
| field, |
| bufferFromSource(value, /* treatNewDataAsImmutable= */ true).buffer); |
| } |
| |
| /** |
| * @param {number} field The field number. |
| * @param {!Uint8Array} value The array of bytes to write. |
| * @private |
| */ |
| writeUint8Array(field, value) { |
| this.writeFieldHeader_(field, WireType.DELIMITED); |
| this.encoder_.writeUnsignedVarint32(value.length); |
| this.appendUint8Array_(value); |
| } |
| |
| /** |
| * Writes a message to the buffer. |
| * @param {number} field The field number. |
| * @param {?MessageType|undefined} value The message to write. |
| * @param {function(MessageTypeNonNull, !BinaryWriter)} writerCallback |
| * Will be invoked with the value to write and the writer to write it |
| * with. |
| * @template MessageType |
| * Use go/closure-ttl to declare a non-nullable version of MessageType. |
| * Replace the null in blah|null with none. This is necessary because the |
| * compiler will infer MessageType to be nullable if the value parameter is |
| * nullable. |
| * @template MessageTypeNonNull := |
| * cond(isUnknown(MessageType), unknown(), |
| * mapunion(MessageType, (X) => |
| * cond(eq(X, 'undefined'), none(), cond(eq(X, 'null'), none(), X)))) |
| * =: |
| */ |
| writeMessage(field, value, writerCallback) { |
| if (value == null) return; |
| const bookmark = this.beginDelimited_(field); |
| writerCallback(value, this); |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes a message set extension to the buffer. |
| * @param {number} field The field number for the extension. |
| * @param {?MessageType|undefined} value The extension message object to |
| * write. Note that message set can only have extensions with type of |
| * optional message. |
| * @param {function(!MessageTypeNonNull, !BinaryWriter)} writerCallback |
| * Will be invoked with the value to write and the writer to write it |
| * with. |
| * @template MessageType |
| * Use go/closure-ttl to declare a non-nullable version of MessageType. |
| * Replace the null in blah|null with none. This is necessary because the |
| * compiler will infer MessageType to be nullable if the value parameter is |
| * nullable. |
| * @template MessageTypeNonNull := |
| * cond(isUnknown(MessageType), unknown(), |
| * mapunion(MessageType, (X) => |
| * cond(eq(X, 'undefined'), none(), cond(eq(X, 'null'), none(), X)))) |
| * =: |
| */ |
| writeMessageSet(field, value, writerCallback) { |
| if (value == null) return; |
| // The wire format for a message set is defined by |
| // google3/net/proto/message_set.proto |
| this.writeFieldHeader_(1, WireType.START_GROUP); |
| this.writeFieldHeader_(2, WireType.VARINT); |
| this.encoder_.writeSignedVarint32(field); |
| const bookmark = this.beginDelimited_(3); |
| writerCallback(value, this); |
| this.endDelimited_(bookmark); |
| this.writeFieldHeader_(1, WireType.END_GROUP); |
| } |
| |
| /** |
| * Writes a group message to the buffer. |
| * |
| * @param {number} field The field number. |
| * @param {?MessageType|undefined} value The message to write, wrapped with |
| * START_GROUP / END_GROUP tags. Will be a no-op if 'value' is null. |
| * @param {function(MessageTypeNonNull, !BinaryWriter)} writerCallback |
| * Will be invoked with the value to write and the writer to write it |
| * with. |
| * @template MessageType |
| * Use go/closure-ttl to declare a non-nullable version of MessageType. |
| * Replace the null in blah|null with none. This is necessary because the |
| * compiler will infer MessageType to be nullable if the value parameter is |
| * nullable. |
| * @template MessageTypeNonNull := |
| * cond(isUnknown(MessageType), unknown(), |
| * mapunion(MessageType, (X) => |
| * cond(eq(X, 'undefined'), none(), cond(eq(X, 'null'), none(), X)))) |
| * =: |
| */ |
| writeGroup(field, value, writerCallback) { |
| if (value == null) return; |
| this.writeFieldHeader_(field, WireType.START_GROUP); |
| writerCallback(value, this); |
| this.writeFieldHeader_(field, WireType.END_GROUP); |
| } |
| |
| /** |
| * Writes a 64-bit field to the buffer as a fixed64. |
| * @param {number} field The field number. |
| * @param {number} lowBits The low 32 bits. |
| * @param {number} highBits The high 32 bits. |
| */ |
| writeSplitFixed64(field, lowBits, highBits) { |
| this.writeFieldHeader_(field, WireType.FIXED64); |
| this.encoder_.writeSplitFixed64(lowBits, highBits); |
| } |
| |
| /** |
| * Writes a 64-bit field to the buffer as a varint. |
| * @param {number} field The field number. |
| * @param {number} lowBits The low 32 bits. |
| * @param {number} highBits The high 32 bits. |
| */ |
| writeSplitVarint64(field, lowBits, highBits) { |
| this.writeFieldHeader_(field, WireType.VARINT); |
| this.encoder_.writeSplitVarint64(lowBits, highBits); |
| } |
| |
| /** |
| * Writes a 64-bit field to the buffer as a zigzag encoded varint. |
| * @param {number} field The field number. |
| * @param {number} lowBits The low 32 bits. |
| * @param {number} highBits The high 32 bits. |
| */ |
| writeSplitZigzagVarint64(field, lowBits, highBits) { |
| this.writeFieldHeader_(field, WireType.VARINT); |
| this.encoder_.writeSplitZigzagVarint64(lowBits >>> 0, highBits >>> 0); |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a repeated 32-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writeRepeatedInt32(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeSignedVarint32_(field, value[i]); |
| } |
| } |
| |
| |
| /** |
| * Writes an array of numbers to the buffer as a repeated 64-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string|!bigint>|undefined} value The array of ints |
| * to write. |
| */ |
| writeRepeatedInt64(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeSignedVarint64_(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of 64-bit values to the buffer as a fixed64. |
| * @param {number} field The field number. |
| * @param {?Array<T>|undefined} value The value. |
| * @param {function(T): number} lo Function to get low bits. |
| * @param {function(T): number} hi Function to get high bits. |
| * @template T |
| */ |
| writeRepeatedSplitFixed64(field, value, lo, hi) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeSplitFixed64(field, lo(value[i]), hi(value[i])); |
| } |
| } |
| |
| /** |
| * Writes an array of 64-bit values to the buffer as a varint. |
| * @param {number} field The field number. |
| * @param {?Array<T>|undefined} value The value. |
| * @param {function(T): number} lo Function to get low bits. |
| * @param {function(T): number} hi Function to get high bits. |
| * @template T |
| */ |
| writeRepeatedSplitVarint64(field, value, lo, hi) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeSplitVarint64(field, lo(value[i]), hi(value[i])); |
| } |
| } |
| |
| /** |
| * Writes an array of 64-bit values to the buffer as a zigzag varint. |
| * @param {number} field The field number. |
| * @param {?Array<T>|undefined} value The value. |
| * @param {function(T): number} lo Function to get low bits. |
| * @param {function(T): number} hi Function to get high bits. |
| * @template T |
| */ |
| writeRepeatedSplitZigzagVarint64(field, value, lo, hi) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeSplitZigzagVarint64(field, lo(value[i]), hi(value[i])); |
| } |
| } |
| |
| /** |
| * Writes an array of numbers formatted as strings to the buffer as a repeated |
| * 64-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<string>|undefined} value The array of ints to write. |
| * @deprecated use writeRepeatedInt64(). |
| */ |
| writeRepeatedInt64String(field, value) { |
| this.writeRepeatedInt64(field, value); |
| } |
| |
| /** |
| * Writes an array numbers to the buffer as a repeated unsigned 32-bit int |
| * field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writeRepeatedUint32(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeUnsignedVarint32_(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array numbers or decimal strings to the buffer as a repeated |
| * unsigned 64-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string|!bigint>|undefined} value The array of ints |
| * to write. |
| */ |
| writeRepeatedUint64(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeUnsignedVarint64_(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of numbers formatted as strings to the buffer as a repeated |
| * unsigned 64-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<string>|undefined} value The array of ints to write. |
| * @deprecated Use writeRepeatedUint64(). |
| */ |
| writeRepeatedUint64String(field, value) { |
| this.writeRepeatedUint64(field, value); |
| } |
| |
| /** |
| * Writes an array numbers to the buffer as a repeated signed 32-bit int |
| * field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writeRepeatedSint32(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeZigzagVarint32_(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array numbers or decimal strings to the buffer as a repeated |
| * signed 64-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string|!bigint>|undefined} value The array of ints |
| * to write. |
| */ |
| writeRepeatedSint64(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeZigzagVarint64_(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array numbers to the buffer as a repeated signed 64-bit int |
| * field. |
| * @param {number} field The field number. |
| * @param {?Array<string>|undefined} value The array of ints to write. |
| * @deprecated Use writeRepeatedSint64(). |
| */ |
| writeRepeatedSint64String(field, value) { |
| this.writeRepeatedSint64(field, value); |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a repeated fixed32 field. This |
| * works for both signed and unsigned fixed32s. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writeRepeatedFixed32(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeFixed32(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of numbers or decimal strings to the buffer as a repeated |
| * fixed64 field. This works for both signed and unsigned fixed64s. |
| * @param {number} field The field number. |
| * @param {?Array<number|string|!bigint>|undefined} value The array of ints |
| * to write. |
| */ |
| writeRepeatedFixed64(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeFixed64(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a repeated fixed64 field. This |
| * works for both signed and unsigned fixed64s. |
| * @param {number} field The field number. |
| * @param {?Array<string>|undefined} value The array of decimal strings to |
| * write. |
| * @deprecated Use writeRepeatedFixed64(). |
| */ |
| writeRepeatedFixed64String(field, value) { |
| this.writeRepeatedFixed64(field, value); |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a repeated sfixed32 field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writeRepeatedSfixed32(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeSfixed32(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of numbers or decimal strings to the buffer as a repeated |
| * sfixed64 field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string>|undefined} value The array of ints to write. |
| */ |
| writeRepeatedSfixed64(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeSfixed64(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of decimal strings to the buffer as a repeated sfixed64 |
| * field. |
| * @param {number} field The field number. |
| * @param {?Array<string>|undefined} value The array of decimal strings to |
| * write. |
| * @deprecated Use writeRepeatedSfixed64(). |
| */ |
| writeRepeatedSfixed64String(field, value) { |
| this.writeRepeatedSfixed64(field, value); |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a repeated float field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string>|undefined} value The array of floats to |
| * write, accepts 'Infinity'/'-Infinity'/'NaN' for JSPB wire format |
| * compatibility. |
| */ |
| writeRepeatedFloat(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeFloat(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a repeated double field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string>|undefined} value The array of doubles to |
| * write, accepts 'Infinity'/'-Infinity'/'NaN' for JSPB wire format |
| * compatibility. |
| */ |
| writeRepeatedDouble(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeDouble(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of booleans to the buffer as a repeated bool field. |
| * @param {number} field The field number. |
| * @param {?Array<boolean|number>|undefined} value The array of booleans to |
| * write. |
| */ |
| writeRepeatedBool(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeBool(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of enums to the buffer as a repeated enum field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writeRepeatedEnum(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeEnum(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of strings to the buffer as a repeated string field. |
| * @param {number} field The field number. |
| * @param {?Array<string>|undefined} value The array of strings to write. |
| */ |
| writeRepeatedString(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeString(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of arbitrary byte fields to the buffer. |
| * @param {number} field The field number. |
| * @param {?Array<!ByteSource|!ByteString>|undefined} value The arrays of |
| * arrays of bytes to write. |
| */ |
| writeRepeatedBytes(field, value) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeBytes(field, value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of messages to the buffer. |
| * @template MessageType |
| * @param {number} field The field number. |
| * @param {?Array<MessageType>|undefined} value The array of messages to |
| * write. |
| * @param {function(MessageType, !BinaryWriter)} writerCallback |
| * Will be invoked with the value to write and the writer to write it |
| * with. |
| */ |
| writeRepeatedMessage(field, value, writerCallback) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| const bookmark = this.beginDelimited_(field); |
| writerCallback(value[i], this); |
| this.endDelimited_(bookmark); |
| } |
| } |
| |
| /** |
| * Writes an array of group messages to the buffer. |
| * @template MessageType |
| * @param {number} field The field number. |
| * @param {?Array<MessageType>|undefined} value The array of messages to |
| * write. |
| * @param {function(MessageType, !BinaryWriter)} writerCallback |
| * Will be invoked with the value to write and the writer to write it |
| * with. |
| */ |
| writeRepeatedGroup(field, value, writerCallback) { |
| if (value == null) return; |
| for (let i = 0; i < value.length; i++) { |
| this.writeFieldHeader_(field, WireType.START_GROUP); |
| writerCallback(value[i], this); |
| this.writeFieldHeader_(field, WireType.END_GROUP); |
| } |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a packed 32-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writePackedInt32(field, value) { |
| if (value == null || !value.length) return; |
| const bookmark = this.beginDelimited_(field); |
| for (let i = 0; i < value.length; i++) { |
| assertSignedInteger(field, value[i]); |
| this.encoder_.writeSignedVarint32(value[i]); |
| } |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes an array of numbers represented as strings to the buffer as a packed |
| * 32-bit int field. |
| * @param {number} field |
| * @param {?Array<string>|undefined} value |
| */ |
| writePackedInt32String(field, value) { |
| if (value == null || !value.length) return; |
| const bookmark = this.beginDelimited_(field); |
| for (let i = 0; i < value.length; i++) { |
| const intValue = parseInt(value[i], 10); |
| assertSignedInteger(field, intValue); |
| this.encoder_.writeSignedVarint32(intValue); |
| } |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes an array of numbers or decimal strings to the buffer as a packed |
| * 64-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string|!bigint>|undefined} value The array of ints |
| * to write. |
| */ |
| writePackedInt64(field, value) { |
| if (value == null || !value.length) return; |
| const bookmark = this.beginDelimited_(field); |
| for (let i = 0; i < value.length; i++) { |
| const v = value[i]; |
| switch (typeof v) { |
| case 'number': |
| this.encoder_.writeSignedVarint64(v); |
| break; |
| |
| case 'bigint': { |
| const num = Int64.fromBigInt(/** @type {bigint} */(v)); |
| this.encoder_.writeSplitVarint64(num.lo, num.hi); |
| break; |
| } |
| |
| default: { |
| const num = Int64.fromString(/** @type {string} */(v)); |
| this.encoder_.writeSplitVarint64(num.lo, num.hi); |
| break; |
| } |
| } |
| } |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes an array of 64-bit values to the buffer as a fixed64. |
| * @param {number} field The field number. |
| * @param {?Array<T>|undefined} value The value. |
| * @param {function(T): number} lo Function to get low bits. |
| * @param {function(T): number} hi Function to get high bits. |
| * @template T |
| */ |
| writePackedSplitFixed64(field, value, lo, hi) { |
| if (value == null) return; |
| const bookmark = this.beginDelimited_(field); |
| for (let i = 0; i < value.length; i++) { |
| this.encoder_.writeSplitFixed64(lo(value[i]), hi(value[i])); |
| } |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes an array of 64-bit values to the buffer as a varint. |
| * @param {number} field The field number. |
| * @param {?Array<T>|undefined} value The value. |
| * @param {function(T): number} lo Function to get low bits. |
| * @param {function(T): number} hi Function to get high bits. |
| * @template T |
| */ |
| writePackedSplitVarint64(field, value, lo, hi) { |
| if (value == null) return; |
| const bookmark = this.beginDelimited_(field); |
| for (let i = 0; i < value.length; i++) { |
| this.encoder_.writeSplitVarint64(lo(value[i]), hi(value[i])); |
| } |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes an array of 64-bit values to the buffer as a zigzag varint. |
| * @param {number} field The field number. |
| * @param {?Array<T>|undefined} value The value. |
| * @param {function(T): number} lo Function to get low bits. |
| * @param {function(T): number} hi Function to get high bits. |
| * @template T |
| */ |
| writePackedSplitZigzagVarint64(field, value, lo, hi) { |
| if (value == null) return; |
| const bookmark = this.beginDelimited_(field); |
| const encoder = this.encoder_; |
| for (let i = 0; i < value.length; i++) { |
| encoder.writeSplitZigzagVarint64(lo(value[i]), hi(value[i])); |
| } |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes an array of numbers represented as strings to the buffer as a packed |
| * 64-bit int field. |
| * @param {number} field |
| * @param {?Array<string>|undefined} value |
| * @deprecated Use writePackedInt64(). |
| */ |
| writePackedInt64String(field, value) { |
| this.writePackedInt64(field, value); |
| } |
| |
| /** |
| * Writes an array numbers to the buffer as a packed unsigned 32-bit int |
| * field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writePackedUint32(field, value) { |
| if (value == null || !value.length) return; |
| const bookmark = this.beginDelimited_(field); |
| for (let i = 0; i < value.length; i++) { |
| this.encoder_.writeUnsignedVarint32(value[i]); |
| } |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes an array numbers or decimal strings to the buffer as a packed |
| * unsigned 64-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string|!bigint>|undefined} value The array of ints |
| * to write. |
| */ |
| writePackedUint64(field, value) { |
| if (value == null || !value.length) return; |
| const bookmark = this.beginDelimited_(field); |
| for (let i = 0; i < value.length; i++) { |
| const v = value[i]; |
| switch (typeof v) { |
| case 'number': |
| this.encoder_.writeUnsignedVarint64(v); |
| break; |
| |
| case 'bigint': |
| const n = Number(v); |
| if (Number.isSafeInteger(n)) { |
| this.encoder_.writeUnsignedVarint64(n); |
| } else { |
| const num = UInt64.fromBigInt(/** @type {bigint} */(v)); |
| this.encoder_.writeSplitVarint64(num.lo, num.hi); |
| } |
| break; |
| |
| default: |
| const num = UInt64.fromString(/** @type {string} */(v)); |
| this.encoder_.writeSplitVarint64(num.lo, num.hi); |
| break; |
| } |
| } |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes an array of numbers represented as strings to the buffer as a packed |
| * unsigned 64-bit int field. |
| * @param {number} field |
| * @param {?Array<string>|undefined} value |
| * @deprecated Use writePackedUint64() |
| */ |
| writePackedUint64String(field, value) { |
| this.writePackedUint64(field, value); |
| } |
| |
| /** |
| * Writes an array numbers to the buffer as a packed signed 32-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writePackedSint32(field, value) { |
| if (value == null || !value.length) return; |
| const bookmark = this.beginDelimited_(field); |
| for (let i = 0; i < value.length; i++) { |
| this.encoder_.writeZigzagVarint32(value[i]); |
| } |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes an array of numbers or decimal strings to the buffer as a packed |
| * signed 64-bit int field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string|!bigint>|undefined} value The array of ints |
| * to write. |
| */ |
| writePackedSint64(field, value) { |
| if (value == null || !value.length) return; |
| const bookmark = this.beginDelimited_(field); |
| for (let i = 0; i < value.length; i++) { |
| const v = value[i]; |
| switch (typeof v) { |
| case 'number': |
| this.encoder_.writeZigzagVarint64(v); |
| break; |
| |
| default: |
| this.encoder_.writeZigzagVarint64String(/** @type {string} */(v)); |
| break; |
| } |
| } |
| this.endDelimited_(bookmark); |
| } |
| |
| /** |
| * Writes an array of decimal strings to the buffer as a packed signed 64-bit |
| * int field. |
| * @param {number} field The field number. |
| * @param {?Array<string>|undefined} value The array of decimal strings to |
| * write. |
| * @deprecated Use writePackedSint64(). |
| */ |
| writePackedSint64String(field, value) { |
| this.writePackedSint64(field, value); |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a packed fixed32 field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writePackedFixed32(field, value) { |
| if (value == null || !value.length) return; |
| this.writeFieldHeader_(field, WireType.DELIMITED); |
| this.encoder_.writeUnsignedVarint32(value.length * 4); |
| for (let i = 0; i < value.length; i++) { |
| this.encoder_.writeUint32(value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of numbers or decimal strings to the buffer as a packed |
| * fixed64 field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string|!bigint>|undefined} value The array of ints |
| * to write. |
| */ |
| writePackedFixed64(field, value) { |
| if (value == null || !value.length) return; |
| this.writeFieldHeader_(field, WireType.DELIMITED); |
| this.encoder_.writeUnsignedVarint32(value.length * 8); |
| for (let i = 0; i < value.length; i++) { |
| const v = value[i]; |
| switch (typeof v) { |
| case 'number': |
| this.encoder_.writeUint64(/** @type {number} */(v)); |
| break; |
| |
| case 'bigint': |
| const fromBigint = UInt64.fromBigInt(/** @type {bigint} */(v)); |
| this.encoder_.writeSplitFixed64(fromBigint.lo, fromBigint.hi); |
| break; |
| |
| |
| default: |
| const fromString = UInt64.fromString(/** @type {string} */(v)); |
| this.encoder_.writeSplitFixed64(fromString.lo, fromString.hi); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Writes an array of numbers represented as strings to the buffer as a packed |
| * fixed64 field. |
| * @param {number} field The field number. |
| * @param {?Array<string>|undefined} value The array of strings to write. |
| * @deprecated Use writePackedFixed64(). |
| */ |
| writePackedFixed64String(field, value) { |
| this.writePackedFixed64(field, value); |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a packed sfixed32 field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writePackedSfixed32(field, value) { |
| if (value == null || !value.length) return; |
| this.writeFieldHeader_(field, WireType.DELIMITED); |
| this.encoder_.writeUnsignedVarint32(value.length * 4); |
| for (let i = 0; i < value.length; i++) { |
| this.encoder_.writeInt32(value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of numbers or decimal strings to the buffer as a packed |
| * sfixed64 field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string|!bigint>|undefined} value The array of ints |
| * to write. |
| */ |
| writePackedSfixed64(field, value) { |
| if (value == null || !value.length) return; |
| this.writeFieldHeader_(field, WireType.DELIMITED); |
| this.encoder_.writeUnsignedVarint32(value.length * 8); |
| for (let i = 0; i < value.length; i++) { |
| const v = value[i]; |
| switch (typeof v) { |
| case 'number': |
| this.encoder_.writeInt64(v); |
| break; |
| |
| case 'bigint': { |
| const num = Int64.fromBigInt(/** @type {bigint} */(v)); |
| this.encoder_.writeSplitFixed64(num.lo, num.hi); |
| break; |
| } |
| |
| default: { |
| const num = Int64.fromString(/** @type {string} */(v)); |
| this.encoder_.writeSplitFixed64(num.lo, num.hi); |
| break; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Writes an array of numbers or decimal strings to the buffer as a packed |
| * sfixed64 field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string>|undefined} value The array of ints to write. |
| * @deprecated Use writePackedSfixed64() |
| */ |
| writePackedSfixed64String(field, value) { |
| this.writePackedSfixed64(field, value); |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a packed float field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string>|undefined} value The array of floats to |
| * write, accepts 'Infinity'/'-Infinity'/'NaN' for JSPB wire format |
| * compatibility. |
| */ |
| writePackedFloat(field, value) { |
| if (value == null || !value.length) return; |
| this.writeFieldHeader_(field, WireType.DELIMITED); |
| this.encoder_.writeUnsignedVarint32(value.length * 4); |
| for (let i = 0; i < value.length; i++) { |
| this.encoder_.writeFloat(value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of numbers to the buffer as a packed double field. |
| * @param {number} field The field number. |
| * @param {?Array<number|string>|undefined} value The array of doulbe to |
| * write, accepts 'Infinity'/'-Infinity'/'NaN' for JSPB wire format |
| * compatibility. |
| */ |
| writePackedDouble(field, value) { |
| if (value == null || !value.length) return; |
| this.writeFieldHeader_(field, WireType.DELIMITED); |
| this.encoder_.writeUnsignedVarint32(value.length * 8); |
| for (let i = 0; i < value.length; i++) { |
| this.encoder_.writeDouble(value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of booleans to the buffer as a packed bool field. |
| * @param {number} field The field number. |
| * @param {?Array<boolean|number>|undefined} value The array of booleans to |
| * write. |
| */ |
| writePackedBool(field, value) { |
| if (value == null || !value.length) return; |
| this.writeFieldHeader_(field, WireType.DELIMITED); |
| this.encoder_.writeUnsignedVarint32(value.length); |
| for (let i = 0; i < value.length; i++) { |
| this.encoder_.writeBool(value[i]); |
| } |
| } |
| |
| /** |
| * Writes an array of enums to the buffer as a packed enum field. |
| * @param {number} field The field number. |
| * @param {?Array<number>|undefined} value The array of ints to write. |
| */ |
| writePackedEnum(field, value) { |
| if (value == null || !value.length) return; |
| const bookmark = this.beginDelimited_(field); |
| for (let i = 0; i < value.length; i++) { |
| this.encoder_.writeEnum(value[i]); |
| } |
| this.endDelimited_(bookmark); |
| } |
| } |
| |
| /** |
| * Asserts that the value is signed 32-bit integer. |
| * @param {number} field |
| * @param {?} value |
| */ |
| function assertSignedInteger(field, value) { |
| assertThat(field, value, value === Math.floor(value)); |
| assertThat(field, value, value >= -TWO_TO_31 && value < TWO_TO_31); |
| } |
| |
| /** |
| * Asserts that the value is an unsigned 64-bit integer. |
| * NOTE: does not yet validate the range of decimal strings, such a change |
| * would need to be tested before becoming more strict. |
| * @param {number} field |
| * @param {*} value |
| */ |
| function assertSignedInt64(field, value) { |
| const typeofValue = typeof value; |
| switch (typeofValue) { |
| case 'string': { |
| const valueStr = /** @type {string} */ (value); |
| assertThat(field, valueStr, Int64.fromString(valueStr)); |
| break; |
| } |
| |
| case 'number': { |
| const valueNum = /** @type {number} */ (value); |
| assertThat( |
| field, valueNum, valueNum >= -TWO_TO_63 && valueNum < TWO_TO_63); |
| break; |
| } |
| |
| default: { |
| const valueBig = /** @type {bigint} */ (value); |
| assertThat( |
| field, valueBig, |
| valueBig >= BigInt(-TWO_TO_63) && valueBig < BigInt(TWO_TO_63)); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Asserts that the value is signed 64-bit integer. |
| * NOTE: does not yet validate the range of decimal strings, such a change |
| * would need to be tested before becoming more strict. |
| * @param {number} field |
| * @param {*} value |
| */ |
| function assertUnsignedInt64(field, value) { |
| const typeofValue = typeof value; |
| switch (typeofValue) { |
| case 'string': { |
| const valueStr = /** @type {string} */ (value); |
| assertThat(field, valueStr, UInt64.fromString(valueStr)); |
| break; |
| } |
| |
| case 'number': { |
| const valueNum = /** @type {number} */ (value); |
| assertThat(field, valueNum, valueNum >= 0 && valueNum < TWO_TO_64); |
| break; |
| } |
| |
| default: { |
| const valueBig = /** @type {bigint} */ (value); |
| assertThat( |
| field, valueBig, |
| valueBig >= BigInt(0) && valueBig < BigInt(TWO_TO_64)); |
| break; |
| } |
| } |
| } |
| |
| /** |
| * Asserts the condition. |
| * @param {number} field |
| * @param {?} value |
| * @param {?} condition |
| */ |
| function assertThat(field, value, condition) { |
| // Manual assertion here instead of asserts.assert(...) call for perf |
| // reasons, to avoid unnecessary string concatenations. |
| if (!condition) { |
| fail(`for [${value}] at [${field}]`); |
| } |
| } |
| |
| |
| exports = { BinaryWriter }; |