744 lines
21 KiB
JavaScript
744 lines
21 KiB
JavaScript
/**
|
|
* @fileoverview Implements Writer for writing data as the binary wire format
|
|
* bytes array.
|
|
*/
|
|
goog.module('protobuf.binary.Writer');
|
|
|
|
const BufferDecoder = goog.require('protobuf.binary.BufferDecoder');
|
|
const ByteString = goog.require('protobuf.ByteString');
|
|
const Int64 = goog.require('protobuf.Int64');
|
|
const WireType = goog.require('protobuf.binary.WireType');
|
|
const {POLYFILL_TEXT_ENCODING, checkFieldNumber, checkTypeUnsignedInt32, checkWireType} = goog.require('protobuf.internal.checks');
|
|
const {concatenateByteArrays} = goog.require('protobuf.binary.uint8arrays');
|
|
const {createTag, getTagLength} = goog.require('protobuf.binary.tag');
|
|
const {encode} = goog.require('protobuf.binary.textencoding');
|
|
|
|
/**
|
|
* Returns a valid utf-8 encoder function based on TextEncoder if available or
|
|
* a polyfill.
|
|
* Some of the environments we run in do not have TextEncoder defined.
|
|
* TextEncoder is faster than our polyfill so we prefer it over the polyfill.
|
|
* @return {function(string):!Uint8Array}
|
|
*/
|
|
function getEncoderFunction() {
|
|
if (goog.global['TextEncoder']) {
|
|
const textEncoder = new goog.global['TextEncoder']('utf-8');
|
|
return s => s.length === 0 ? new Uint8Array(0) : textEncoder.encode(s);
|
|
}
|
|
if (POLYFILL_TEXT_ENCODING) {
|
|
return encode;
|
|
} else {
|
|
throw new Error(
|
|
'TextEncoder is missing. ' +
|
|
'Enable protobuf.defines.POLYFILL_TEXT_ENCODING');
|
|
}
|
|
}
|
|
|
|
/** @const {function(string): !Uint8Array} */
|
|
const encoderFunction = getEncoderFunction();
|
|
|
|
/**
|
|
* Writer provides methods for encoding all protobuf supported type into a
|
|
* binary format bytes array.
|
|
* Check https://developers.google.com/protocol-buffers/docs/encoding for binary
|
|
* format definition.
|
|
* @final
|
|
* @package
|
|
*/
|
|
class Writer {
|
|
constructor() {
|
|
/**
|
|
* Blocks of data that needs to be serialized. After writing all the data,
|
|
* the blocks are concatenated into a single Uint8Array.
|
|
* @private {!Array<!Uint8Array>}
|
|
*/
|
|
this.blocks_ = [];
|
|
|
|
/**
|
|
* A buffer for writing varint data (tag number + field number for each
|
|
* field, int32, uint32 etc.). Before writing a non-varint data block
|
|
* (string, fixed32 etc.), the buffer is appended to the block array as a
|
|
* new block, and a new buffer is started.
|
|
*
|
|
* We could've written each varint as a new block instead of writing
|
|
* multiple varints in this buffer. But this will increase the number of
|
|
* blocks, and concatenating many small blocks is slower than concatenating
|
|
* few large blocks.
|
|
*
|
|
* TODO: Experiment with writing data in a fixed-length
|
|
* Uint8Array instead of using a growing buffer.
|
|
*
|
|
* @private {!Array<number>}
|
|
*/
|
|
this.currentBuffer_ = [];
|
|
}
|
|
|
|
/**
|
|
* Converts the encoded data into a Uint8Array.
|
|
* The writer is also reset.
|
|
* @return {!ArrayBuffer}
|
|
*/
|
|
getAndResetResultBuffer() {
|
|
this.closeAndStartNewBuffer_();
|
|
const result = concatenateByteArrays(this.blocks_);
|
|
this.blocks_ = [];
|
|
return result.buffer;
|
|
}
|
|
|
|
/**
|
|
* Encodes a (field number, wire type) tuple into a wire-format field header.
|
|
* @param {number} fieldNumber
|
|
* @param {!WireType} wireType
|
|
*/
|
|
writeTag(fieldNumber, wireType) {
|
|
checkFieldNumber(fieldNumber);
|
|
checkWireType(wireType);
|
|
const tag = createTag(wireType, fieldNumber);
|
|
this.writeUnsignedVarint32_(tag);
|
|
}
|
|
|
|
/**
|
|
* Appends the current buffer into the blocks array and starts a new buffer.
|
|
* @private
|
|
*/
|
|
closeAndStartNewBuffer_() {
|
|
this.blocks_.push(new Uint8Array(this.currentBuffer_));
|
|
this.currentBuffer_ = [];
|
|
}
|
|
|
|
/**
|
|
* Encodes a 32-bit integer into its wire-format varint representation and
|
|
* stores it in the buffer.
|
|
* @param {number} value
|
|
* @private
|
|
*/
|
|
writeUnsignedVarint32_(value) {
|
|
checkTypeUnsignedInt32(value);
|
|
while (value > 0x7f) {
|
|
this.currentBuffer_.push((value & 0x7f) | 0x80);
|
|
value = value >>> 7;
|
|
}
|
|
this.currentBuffer_.push(value);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* OPTIONAL METHODS
|
|
****************************************************************************/
|
|
|
|
/**
|
|
* Writes a boolean value field to the buffer as a varint.
|
|
* @param {boolean} value
|
|
* @private
|
|
*/
|
|
writeBoolValue_(value) {
|
|
this.currentBuffer_.push(value ? 1 : 0);
|
|
}
|
|
|
|
/**
|
|
* Writes a boolean value field to the buffer as a varint.
|
|
* @param {number} fieldNumber
|
|
* @param {boolean} value
|
|
*/
|
|
writeBool(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.VARINT);
|
|
this.writeBoolValue_(value);
|
|
}
|
|
|
|
/**
|
|
* Writes a bytes value field to the buffer as a length delimited field.
|
|
* @param {number} fieldNumber
|
|
* @param {!ByteString} value
|
|
*/
|
|
writeBytes(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.DELIMITED);
|
|
const buffer = value.toArrayBuffer();
|
|
this.writeUnsignedVarint32_(buffer.byteLength);
|
|
this.writeRaw_(buffer);
|
|
}
|
|
|
|
/**
|
|
* Writes a double value field to the buffer without tag.
|
|
* @param {number} value
|
|
* @private
|
|
*/
|
|
writeDoubleValue_(value) {
|
|
const buffer = new ArrayBuffer(8);
|
|
const view = new DataView(buffer);
|
|
view.setFloat64(0, value, true);
|
|
this.writeRaw_(buffer);
|
|
}
|
|
|
|
/**
|
|
* Writes a double value field to the buffer.
|
|
* @param {number} fieldNumber
|
|
* @param {number} value
|
|
*/
|
|
writeDouble(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.FIXED64);
|
|
this.writeDoubleValue_(value);
|
|
}
|
|
|
|
/**
|
|
* Writes a fixed32 value field to the buffer without tag.
|
|
* @param {number} value
|
|
* @private
|
|
*/
|
|
writeFixed32Value_(value) {
|
|
const buffer = new ArrayBuffer(4);
|
|
const view = new DataView(buffer);
|
|
view.setUint32(0, value, true);
|
|
this.writeRaw_(buffer);
|
|
}
|
|
|
|
/**
|
|
* Writes a fixed32 value field to the buffer.
|
|
* @param {number} fieldNumber
|
|
* @param {number} value
|
|
*/
|
|
writeFixed32(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.FIXED32);
|
|
this.writeFixed32Value_(value);
|
|
}
|
|
|
|
/**
|
|
* Writes a float value field to the buffer without tag.
|
|
* @param {number} value
|
|
* @private
|
|
*/
|
|
writeFloatValue_(value) {
|
|
const buffer = new ArrayBuffer(4);
|
|
const view = new DataView(buffer);
|
|
view.setFloat32(0, value, true);
|
|
this.writeRaw_(buffer);
|
|
}
|
|
|
|
/**
|
|
* Writes a float value field to the buffer.
|
|
* @param {number} fieldNumber
|
|
* @param {number} value
|
|
*/
|
|
writeFloat(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.FIXED32);
|
|
this.writeFloatValue_(value);
|
|
}
|
|
|
|
/**
|
|
* Writes a int32 value field to the buffer as a varint without tag.
|
|
* @param {number} value
|
|
* @private
|
|
*/
|
|
writeInt32Value_(value) {
|
|
if (value >= 0) {
|
|
this.writeVarint64_(0, value);
|
|
} else {
|
|
this.writeVarint64_(0xFFFFFFFF, value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Writes a int32 value field to the buffer as a varint.
|
|
* @param {number} fieldNumber
|
|
* @param {number} value
|
|
*/
|
|
writeInt32(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.VARINT);
|
|
this.writeInt32Value_(value);
|
|
}
|
|
|
|
/**
|
|
* Writes a int64 value field to the buffer as a varint.
|
|
* @param {number} fieldNumber
|
|
* @param {!Int64} value
|
|
*/
|
|
writeInt64(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.VARINT);
|
|
this.writeVarint64_(value.getHighBits(), value.getLowBits());
|
|
}
|
|
|
|
/**
|
|
* Writes a sfixed32 value field to the buffer.
|
|
* @param {number} value
|
|
* @private
|
|
*/
|
|
writeSfixed32Value_(value) {
|
|
const buffer = new ArrayBuffer(4);
|
|
const view = new DataView(buffer);
|
|
view.setInt32(0, value, true);
|
|
this.writeRaw_(buffer);
|
|
}
|
|
|
|
/**
|
|
* Writes a sfixed32 value field to the buffer.
|
|
* @param {number} fieldNumber
|
|
* @param {number} value
|
|
*/
|
|
writeSfixed32(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.FIXED32);
|
|
this.writeSfixed32Value_(value);
|
|
}
|
|
|
|
/**
|
|
* Writes a sfixed64 value field to the buffer without tag.
|
|
* @param {!Int64} value
|
|
* @private
|
|
*/
|
|
writeSfixed64Value_(value) {
|
|
const buffer = new ArrayBuffer(8);
|
|
const view = new DataView(buffer);
|
|
view.setInt32(0, value.getLowBits(), true);
|
|
view.setInt32(4, value.getHighBits(), true);
|
|
this.writeRaw_(buffer);
|
|
}
|
|
|
|
/**
|
|
* Writes a sfixed64 value field to the buffer.
|
|
* @param {number} fieldNumber
|
|
* @param {!Int64} value
|
|
*/
|
|
writeSfixed64(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.FIXED64);
|
|
this.writeSfixed64Value_(value);
|
|
}
|
|
|
|
/**
|
|
* Writes a sfixed64 value field to the buffer.
|
|
* @param {number} fieldNumber
|
|
*/
|
|
writeStartGroup(fieldNumber) {
|
|
this.writeTag(fieldNumber, WireType.START_GROUP);
|
|
}
|
|
|
|
/**
|
|
* Writes a sfixed64 value field to the buffer.
|
|
* @param {number} fieldNumber
|
|
*/
|
|
writeEndGroup(fieldNumber) {
|
|
this.writeTag(fieldNumber, WireType.END_GROUP);
|
|
}
|
|
|
|
/**
|
|
* Writes a uint32 value field to the buffer as a varint without tag.
|
|
* @param {number} value
|
|
* @private
|
|
*/
|
|
writeUint32Value_(value) {
|
|
this.writeVarint64_(0, value);
|
|
}
|
|
|
|
/**
|
|
* Writes a uint32 value field to the buffer as a varint.
|
|
* @param {number} fieldNumber
|
|
* @param {number} value
|
|
*/
|
|
writeUint32(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.VARINT);
|
|
this.writeUint32Value_(value);
|
|
}
|
|
|
|
/**
|
|
* Writes the bits of a 64 bit number to the buffer as a varint.
|
|
* @param {number} highBits
|
|
* @param {number} lowBits
|
|
* @private
|
|
*/
|
|
writeVarint64_(highBits, lowBits) {
|
|
for (let i = 0; i < 28; i = i + 7) {
|
|
const shift = lowBits >>> i;
|
|
const hasNext = !((shift >>> 7) === 0 && highBits === 0);
|
|
const byte = (hasNext ? shift | 0x80 : shift) & 0xFF;
|
|
this.currentBuffer_.push(byte);
|
|
if (!hasNext) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
const splitBits = ((lowBits >>> 28) & 0x0F) | ((highBits & 0x07) << 4);
|
|
const hasMoreBits = !((highBits >> 3) === 0);
|
|
this.currentBuffer_.push(
|
|
(hasMoreBits ? splitBits | 0x80 : splitBits) & 0xFF);
|
|
|
|
if (!hasMoreBits) {
|
|
return;
|
|
}
|
|
|
|
for (let i = 3; i < 31; i = i + 7) {
|
|
const shift = highBits >>> i;
|
|
const hasNext = !((shift >>> 7) === 0);
|
|
const byte = (hasNext ? shift | 0x80 : shift) & 0xFF;
|
|
this.currentBuffer_.push(byte);
|
|
if (!hasNext) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.currentBuffer_.push((highBits >>> 31) & 0x01);
|
|
}
|
|
|
|
/**
|
|
* Writes a sint32 value field to the buffer as a varint without tag.
|
|
* @param {number} value
|
|
* @private
|
|
*/
|
|
writeSint32Value_(value) {
|
|
value = (value << 1) ^ (value >> 31);
|
|
this.writeVarint64_(0, value);
|
|
}
|
|
|
|
/**
|
|
* Writes a sint32 value field to the buffer as a varint.
|
|
* @param {number} fieldNumber
|
|
* @param {number} value
|
|
*/
|
|
writeSint32(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.VARINT);
|
|
this.writeSint32Value_(value);
|
|
}
|
|
|
|
/**
|
|
* Writes a sint64 value field to the buffer as a varint without tag.
|
|
* @param {!Int64} value
|
|
* @private
|
|
*/
|
|
writeSint64Value_(value) {
|
|
const highBits = value.getHighBits();
|
|
const lowBits = value.getLowBits();
|
|
|
|
const sign = highBits >> 31;
|
|
const encodedLowBits = (lowBits << 1) ^ sign;
|
|
const encodedHighBits = ((highBits << 1) | (lowBits >>> 31)) ^ sign;
|
|
this.writeVarint64_(encodedHighBits, encodedLowBits);
|
|
}
|
|
|
|
/**
|
|
* Writes a sint64 value field to the buffer as a varint.
|
|
* @param {number} fieldNumber
|
|
* @param {!Int64} value
|
|
*/
|
|
writeSint64(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.VARINT);
|
|
this.writeSint64Value_(value);
|
|
}
|
|
|
|
/**
|
|
* Writes a string value field to the buffer as a varint.
|
|
* @param {number} fieldNumber
|
|
* @param {string} value
|
|
*/
|
|
writeString(fieldNumber, value) {
|
|
this.writeTag(fieldNumber, WireType.DELIMITED);
|
|
const array = encoderFunction(value);
|
|
this.writeUnsignedVarint32_(array.length);
|
|
this.closeAndStartNewBuffer_();
|
|
this.blocks_.push(array);
|
|
}
|
|
|
|
/**
|
|
* Writes raw bytes to the buffer.
|
|
* @param {!ArrayBuffer} arrayBuffer
|
|
* @private
|
|
*/
|
|
writeRaw_(arrayBuffer) {
|
|
this.closeAndStartNewBuffer_();
|
|
this.blocks_.push(new Uint8Array(arrayBuffer));
|
|
}
|
|
|
|
/**
|
|
* Writes raw bytes to the buffer.
|
|
* @param {!BufferDecoder} bufferDecoder
|
|
* @param {number} start
|
|
* @param {!WireType} wireType
|
|
* @param {number} fieldNumber
|
|
* @package
|
|
*/
|
|
writeBufferDecoder(bufferDecoder, start, wireType, fieldNumber) {
|
|
this.closeAndStartNewBuffer_();
|
|
const dataLength =
|
|
getTagLength(bufferDecoder, start, wireType, fieldNumber);
|
|
this.blocks_.push(
|
|
bufferDecoder.subBufferDecoder(start, dataLength).asUint8Array());
|
|
}
|
|
|
|
/**
|
|
* Write the whole bytes as a length delimited field.
|
|
* @param {number} fieldNumber
|
|
* @param {!ArrayBuffer} arrayBuffer
|
|
*/
|
|
writeDelimited(fieldNumber, arrayBuffer) {
|
|
this.writeTag(fieldNumber, WireType.DELIMITED);
|
|
this.writeUnsignedVarint32_(arrayBuffer.byteLength);
|
|
this.writeRaw_(arrayBuffer);
|
|
}
|
|
|
|
/****************************************************************************
|
|
* REPEATED METHODS
|
|
****************************************************************************/
|
|
|
|
/**
|
|
* Writes repeated boolean values to the buffer as unpacked varints.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<boolean>} values
|
|
*/
|
|
writeRepeatedBool(fieldNumber, values) {
|
|
values.forEach(val => this.writeBool(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated boolean values to the buffer as packed varints.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<boolean>} values
|
|
*/
|
|
writePackedBool(fieldNumber, values) {
|
|
this.writeFixedPacked_(
|
|
fieldNumber, values, val => this.writeBoolValue_(val), 1);
|
|
}
|
|
|
|
/**
|
|
* Writes repeated double values to the buffer as unpacked fixed64.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writeRepeatedDouble(fieldNumber, values) {
|
|
values.forEach(val => this.writeDouble(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated double values to the buffer as packed fixed64.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writePackedDouble(fieldNumber, values) {
|
|
this.writeFixedPacked_(
|
|
fieldNumber, values, val => this.writeDoubleValue_(val), 8);
|
|
}
|
|
|
|
/**
|
|
* Writes repeated fixed32 values to the buffer as unpacked fixed32.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writeRepeatedFixed32(fieldNumber, values) {
|
|
values.forEach(val => this.writeFixed32(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated fixed32 values to the buffer as packed fixed32.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writePackedFixed32(fieldNumber, values) {
|
|
this.writeFixedPacked_(
|
|
fieldNumber, values, val => this.writeFixed32Value_(val), 4);
|
|
}
|
|
|
|
/**
|
|
* Writes repeated float values to the buffer as unpacked fixed64.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writeRepeatedFloat(fieldNumber, values) {
|
|
values.forEach(val => this.writeFloat(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated float values to the buffer as packed fixed64.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writePackedFloat(fieldNumber, values) {
|
|
this.writeFixedPacked_(
|
|
fieldNumber, values, val => this.writeFloatValue_(val), 4);
|
|
}
|
|
|
|
/**
|
|
* Writes repeated int32 values to the buffer as unpacked int32.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writeRepeatedInt32(fieldNumber, values) {
|
|
values.forEach(val => this.writeInt32(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated int32 values to the buffer as packed int32.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writePackedInt32(fieldNumber, values) {
|
|
this.writeVariablePacked_(
|
|
fieldNumber, values, (writer, val) => writer.writeInt32Value_(val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated int64 values to the buffer as unpacked varint.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<!Int64>} values
|
|
*/
|
|
writeRepeatedInt64(fieldNumber, values) {
|
|
values.forEach(val => this.writeInt64(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated int64 values to the buffer as packed varint.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<!Int64>} values
|
|
*/
|
|
writePackedInt64(fieldNumber, values) {
|
|
this.writeVariablePacked_(
|
|
fieldNumber, values,
|
|
(writer, val) =>
|
|
writer.writeVarint64_(val.getHighBits(), val.getLowBits()));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated sfixed32 values to the buffer as unpacked fixed32.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writeRepeatedSfixed32(fieldNumber, values) {
|
|
values.forEach(val => this.writeSfixed32(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated sfixed32 values to the buffer as packed fixed32.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writePackedSfixed32(fieldNumber, values) {
|
|
this.writeFixedPacked_(
|
|
fieldNumber, values, val => this.writeSfixed32Value_(val), 4);
|
|
}
|
|
|
|
/**
|
|
* Writes repeated sfixed64 values to the buffer as unpacked fixed64.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<!Int64>} values
|
|
*/
|
|
writeRepeatedSfixed64(fieldNumber, values) {
|
|
values.forEach(val => this.writeSfixed64(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated sfixed64 values to the buffer as packed fixed64.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<!Int64>} values
|
|
*/
|
|
writePackedSfixed64(fieldNumber, values) {
|
|
this.writeFixedPacked_(
|
|
fieldNumber, values, val => this.writeSfixed64Value_(val), 8);
|
|
}
|
|
|
|
/**
|
|
* Writes repeated sint32 values to the buffer as unpacked sint32.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writeRepeatedSint32(fieldNumber, values) {
|
|
values.forEach(val => this.writeSint32(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated sint32 values to the buffer as packed sint32.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writePackedSint32(fieldNumber, values) {
|
|
this.writeVariablePacked_(
|
|
fieldNumber, values, (writer, val) => writer.writeSint32Value_(val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated sint64 values to the buffer as unpacked varint.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<!Int64>} values
|
|
*/
|
|
writeRepeatedSint64(fieldNumber, values) {
|
|
values.forEach(val => this.writeSint64(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated sint64 values to the buffer as packed varint.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<!Int64>} values
|
|
*/
|
|
writePackedSint64(fieldNumber, values) {
|
|
this.writeVariablePacked_(
|
|
fieldNumber, values, (writer, val) => writer.writeSint64Value_(val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated uint32 values to the buffer as unpacked uint32.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writeRepeatedUint32(fieldNumber, values) {
|
|
values.forEach(val => this.writeUint32(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated uint32 values to the buffer as packed uint32.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<number>} values
|
|
*/
|
|
writePackedUint32(fieldNumber, values) {
|
|
this.writeVariablePacked_(
|
|
fieldNumber, values, (writer, val) => writer.writeUint32Value_(val));
|
|
}
|
|
|
|
/**
|
|
* Writes repeated bytes values to the buffer.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<!ByteString>} values
|
|
*/
|
|
writeRepeatedBytes(fieldNumber, values) {
|
|
values.forEach(val => this.writeBytes(fieldNumber, val));
|
|
}
|
|
|
|
/**
|
|
* Writes packed fields with fixed length.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<T>} values
|
|
* @param {function(T)} valueWriter
|
|
* @param {number} entitySize
|
|
* @template T
|
|
* @private
|
|
*/
|
|
writeFixedPacked_(fieldNumber, values, valueWriter, entitySize) {
|
|
if (values.length === 0) {
|
|
return;
|
|
}
|
|
this.writeTag(fieldNumber, WireType.DELIMITED);
|
|
this.writeUnsignedVarint32_(values.length * entitySize);
|
|
this.closeAndStartNewBuffer_();
|
|
values.forEach(value => valueWriter(value));
|
|
}
|
|
|
|
/**
|
|
* Writes packed fields with variable length.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<T>} values
|
|
* @param {function(!Writer, T)} valueWriter
|
|
* @template T
|
|
* @private
|
|
*/
|
|
writeVariablePacked_(fieldNumber, values, valueWriter) {
|
|
if (values.length === 0) {
|
|
return;
|
|
}
|
|
const writer = new Writer();
|
|
values.forEach(val => valueWriter(writer, val));
|
|
const bytes = writer.getAndResetResultBuffer();
|
|
this.writeDelimited(fieldNumber, bytes);
|
|
}
|
|
|
|
/**
|
|
* Writes repeated string values to the buffer.
|
|
* @param {number} fieldNumber
|
|
* @param {!Array<string>} values
|
|
*/
|
|
writeRepeatedString(fieldNumber, values) {
|
|
values.forEach(val => this.writeString(fieldNumber, val));
|
|
}
|
|
}
|
|
|
|
exports = Writer;
|