Project import generated by Copybara
PiperOrigin-RevId: 293911829
diff --git a/js/experimental/runtime/kernel/buffer_decoder.js b/js/experimental/runtime/kernel/buffer_decoder.js
index 614659a..2b4157e 100644
--- a/js/experimental/runtime/kernel/buffer_decoder.js
+++ b/js/experimental/runtime/kernel/buffer_decoder.js
@@ -6,7 +6,7 @@
const ByteString = goog.require('protobuf.ByteString');
const functions = goog.require('goog.functions');
-const {POLYFILL_TEXT_ENCODING, checkCriticalElementIndex, checkCriticalPositionIndex, checkState} = goog.require('protobuf.internal.checks');
+const {POLYFILL_TEXT_ENCODING, checkCriticalPositionIndex, checkCriticalState, checkState} = goog.require('protobuf.internal.checks');
const {byteStringFromUint8ArrayUnsafe} = goog.require('protobuf.byteStringInternal');
const {concatenateByteArrays} = goog.require('protobuf.binary.uint8arrays');
const {decode} = goog.require('protobuf.binary.textencoding');
@@ -72,7 +72,9 @@
/** @private @const {number} */
this.startIndex_ = startIndex;
/** @private @const {number} */
- this.endIndex_ = this.startIndex_ + length;
+ this.endIndex_ = startIndex + length;
+ /** @private {number} */
+ this.cursor_ = startIndex;
}
/**
@@ -100,11 +102,37 @@
}
/**
+ * Returns the start position of the next data, i.e. end position of the last
+ * read data + 1.
+ * @return {number}
+ */
+ cursor() {
+ return this.cursor_;
+ }
+
+ /**
+ * Sets the cursor to the specified position.
+ * @param {number} position
+ */
+ setCursor(position) {
+ this.cursor_ = position;
+ }
+
+ /**
+ * Returns if there is more data to read after the current cursor position.
+ * @return {boolean}
+ */
+ hasNext() {
+ return this.cursor_ < this.endIndex_;
+ }
+
+ /**
* Returns a float32 from a given index
* @param {number} index
* @return {number}
*/
getFloat32(index) {
+ this.cursor_ = index + 4;
return this.dataView_.getFloat32(index, true);
}
@@ -114,6 +142,7 @@
* @return {number}
*/
getFloat64(index) {
+ this.cursor_ = index + 8;
return this.dataView_.getFloat64(index, true);
}
@@ -123,45 +152,40 @@
* @return {number}
*/
getInt32(index) {
+ this.cursor_ = index + 4;
return this.dataView_.getInt32(index, true);
}
/**
- * @param {number} index
- * @return {number}
- */
- getUint8(index) {
- return this.dataView_.getUint8(index);
- }
-
- /**
* Returns a uint32 from a given index
* @param {number} index
* @return {number}
*/
getUint32(index) {
+ this.cursor_ = index + 4;
return this.dataView_.getUint32(index, true);
}
/**
- * Returns two JS numbers each representing 32 bits of a 64 bit number.
+ * Returns two JS numbers each representing 32 bits of a 64 bit number. Also
+ * sets the cursor to the start of the next block of data.
* @param {number} index
- * @return {{lowBits: number, highBits: number, dataStart: number}}
+ * @return {{lowBits: number, highBits: number}}
*/
getVarint(index) {
- let start = index;
+ this.cursor_ = index;
let lowBits = 0;
let highBits = 0;
for (let shift = 0; shift < 28; shift += 7) {
- const b = this.dataView_.getUint8(start++);
+ const b = this.dataView_.getUint8(this.cursor_++);
lowBits |= (b & 0x7F) << shift;
if ((b & 0x80) === 0) {
- return {lowBits, highBits, dataStart: start};
+ return {lowBits, highBits};
}
}
- const middleByte = this.dataView_.getUint8(start++);
+ const middleByte = this.dataView_.getUint8(this.cursor_++);
// last four bits of the first 32 bit number
lowBits |= (middleByte & 0x0F) << 28;
@@ -170,36 +194,100 @@
highBits = (middleByte & 0x70) >> 4;
if ((middleByte & 0x80) === 0) {
- return {lowBits, highBits, dataStart: start};
+ return {lowBits, highBits};
}
for (let shift = 3; shift <= 31; shift += 7) {
- const b = this.dataView_.getUint8(start++);
+ const b = this.dataView_.getUint8(this.cursor_++);
highBits |= (b & 0x7F) << shift;
if ((b & 0x80) === 0) {
- return {lowBits, highBits, dataStart: start};
+ return {lowBits, highBits};
}
}
- checkState(false, 'Data is longer than 10 bytes');
- return {lowBits, highBits, dataStart: start};
+ checkCriticalState(false, 'Data is longer than 10 bytes');
+
+ return {lowBits, highBits};
}
/**
- * Skips over a varint at a given index and returns the next position.
+ * Returns an unsigned int32 number at the current cursor position. The upper
+ * bits are discarded if the varint is longer than 32 bits. Also sets the
+ * cursor to the start of the next block of data.
+ * @return {number}
+ */
+ getUnsignedVarint32() {
+ let b = this.dataView_.getUint8(this.cursor_++);
+ let result = b & 0x7F;
+ if ((b & 0x80) === 0) {
+ return result;
+ }
+
+ b = this.dataView_.getUint8(this.cursor_++);
+ result |= (b & 0x7F) << 7;
+ if ((b & 0x80) === 0) {
+ return result;
+ }
+
+ b = this.dataView_.getUint8(this.cursor_++);
+ result |= (b & 0x7F) << 14;
+ if ((b & 0x80) === 0) {
+ return result;
+ }
+
+ b = this.dataView_.getUint8(this.cursor_++);
+ result |= (b & 0x7F) << 21;
+ if ((b & 0x80) === 0) {
+ return result;
+ }
+
+ // Extract only last 4 bits
+ b = this.dataView_.getUint8(this.cursor_++);
+ result |= (b & 0x0F) << 28;
+
+ for (let readBytes = 5; ((b & 0x80) !== 0) && readBytes < 10; readBytes++) {
+ b = this.dataView_.getUint8(this.cursor_++);
+ }
+
+ checkCriticalState((b & 0x80) === 0, 'Data is longer than 10 bytes');
+
+ // Result can be have 32 bits, convert it to unsigned
+ return result >>> 0;
+ }
+
+ /**
+ * Returns an unsigned int32 number at the specified index. The upper bits are
+ * discarded if the varint is longer than 32 bits. Also sets the cursor to the
+ * start of the next block of data.
+ * @param {number} index
+ * @return {number}
+ */
+ getUnsignedVarint32At(index) {
+ this.cursor_ = index;
+ return this.getUnsignedVarint32();
+ }
+
+ /**
+ * Seeks forward by the given amount.
+ * @param {number} skipAmount
+ * @package
+ */
+ skip(skipAmount) {
+ this.cursor_ += skipAmount;
+ checkCriticalPositionIndex(this.cursor_, this.endIndex_);
+ }
+
+ /**
+ * Skips over a varint at a given index.
* @param {number} index Start of the data.
- * @return {number} Position of the first byte after the varint.
* @package
*/
skipVarint(index) {
- let cursor = index;
- checkCriticalElementIndex(cursor, this.endIndex());
- while (this.dataView_.getUint8(cursor++) & 0x80) {
- checkCriticalElementIndex(cursor, this.endIndex());
+ this.cursor_ = index;
+ while (this.dataView_.getUint8(this.cursor_++) & 0x80) {
}
- checkCriticalPositionIndex(cursor, index + 10);
- return cursor;
+ checkCriticalPositionIndex(this.cursor_, index + 10);
}
/**
diff --git a/js/experimental/runtime/kernel/buffer_decoder_test.js b/js/experimental/runtime/kernel/buffer_decoder_test.js
index aed045a..7c549f8 100644
--- a/js/experimental/runtime/kernel/buffer_decoder_test.js
+++ b/js/experimental/runtime/kernel/buffer_decoder_test.js
@@ -5,7 +5,7 @@
goog.module('protobuf.binary.varintsTest');
const BufferDecoder = goog.require('protobuf.binary.BufferDecoder');
-const {CHECK_CRITICAL_BOUNDS, CHECK_STATE} = goog.require('protobuf.internal.checks');
+const {CHECK_CRITICAL_STATE, CHECK_STATE} = goog.require('protobuf.internal.checks');
goog.setTestOnly();
@@ -17,25 +17,47 @@
return new Uint8Array(bytes).buffer;
}
+describe('setCursor does', () => {
+ it('set the cursor at the position specified', () => {
+ const bufferDecoder =
+ BufferDecoder.fromArrayBuffer(createArrayBuffer(0x0, 0x1));
+ expect(bufferDecoder.cursor()).toBe(0);
+ bufferDecoder.setCursor(1);
+ expect(bufferDecoder.cursor()).toBe(1);
+ });
+});
+
+describe('skip does', () => {
+ it('advance the cursor', () => {
+ const bufferDecoder =
+ BufferDecoder.fromArrayBuffer(createArrayBuffer(0x0, 0x1, 0x2));
+ bufferDecoder.setCursor(1);
+ bufferDecoder.skip(1);
+ expect(bufferDecoder.cursor()).toBe(2);
+ });
+});
+
describe('Skip varint does', () => {
it('skip a varint', () => {
const bufferDecoder =
BufferDecoder.fromArrayBuffer(createArrayBuffer(0x01));
- expect(bufferDecoder.skipVarint(0)).toBe(1);
+ bufferDecoder.skipVarint(0);
+ expect(bufferDecoder.cursor()).toBe(1);
});
it('fail when varint is larger than 10 bytes', () => {
const bufferDecoder = BufferDecoder.fromArrayBuffer(createArrayBuffer(
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00));
- if (CHECK_CRITICAL_BOUNDS) {
+ if (CHECK_CRITICAL_STATE) {
expect(() => bufferDecoder.skipVarint(0)).toThrow();
} else {
// Note in unchecked mode we produce invalid output for invalid inputs.
// This test just documents our behavior in those cases.
// These values might change at any point and are not considered
// what the implementation should be doing here.
- expect(bufferDecoder.skipVarint(0)).toBe(11);
+ bufferDecoder.skipVarint(0);
+ expect(bufferDecoder.cursor()).toBe(11);
}
});
@@ -50,28 +72,144 @@
it('read zero', () => {
const bufferDecoder =
BufferDecoder.fromArrayBuffer(createArrayBuffer(0x00));
- const {dataStart, lowBits, highBits} = bufferDecoder.getVarint(0);
- expect(dataStart).toBe(1);
+ const {lowBits, highBits} = bufferDecoder.getVarint(0);
expect(lowBits).toBe(0);
expect(highBits).toBe(0);
+ expect(bufferDecoder.cursor()).toBe(1);
});
it('read one', () => {
const bufferDecoder =
BufferDecoder.fromArrayBuffer(createArrayBuffer(0x01));
- const {dataStart, lowBits, highBits} = bufferDecoder.getVarint(0);
- expect(dataStart).toBe(1);
+ const {lowBits, highBits} = bufferDecoder.getVarint(0);
expect(lowBits).toBe(1);
expect(highBits).toBe(0);
+ expect(bufferDecoder.cursor()).toBe(1);
});
it('read max value', () => {
const bufferDecoder = BufferDecoder.fromArrayBuffer(createArrayBuffer(
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01));
- const {dataStart, lowBits, highBits} = bufferDecoder.getVarint(0);
- expect(dataStart).toBe(10);
+ const {lowBits, highBits} = bufferDecoder.getVarint(0);
expect(lowBits).toBe(-1);
expect(highBits).toBe(-1);
+ expect(bufferDecoder.cursor()).toBe(10);
+ });
+});
+
+describe('readUnsignedVarint32 does', () => {
+ it('read zero', () => {
+ const bufferDecoder =
+ BufferDecoder.fromArrayBuffer(createArrayBuffer(0x00));
+ const result = bufferDecoder.getUnsignedVarint32();
+ expect(result).toBe(0);
+ expect(bufferDecoder.cursor()).toBe(1);
+ });
+
+ it('read one', () => {
+ const bufferDecoder =
+ BufferDecoder.fromArrayBuffer(createArrayBuffer(0x01));
+ const result = bufferDecoder.getUnsignedVarint32();
+ expect(result).toBe(1);
+ expect(bufferDecoder.cursor()).toBe(1);
+ });
+
+ it('read max int32', () => {
+ const bufferDecoder = BufferDecoder.fromArrayBuffer(
+ createArrayBuffer(0xFF, 0xFF, 0xFF, 0xFF, 0x0F));
+ const result = bufferDecoder.getUnsignedVarint32();
+ expect(result).toBe(4294967295);
+ expect(bufferDecoder.cursor()).toBe(5);
+ });
+
+ it('read max value', () => {
+ const bufferDecoder = BufferDecoder.fromArrayBuffer(createArrayBuffer(
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01));
+ const result = bufferDecoder.getUnsignedVarint32();
+ expect(result).toBe(4294967295);
+ expect(bufferDecoder.cursor()).toBe(10);
+ });
+
+ it('fail if data is longer than 10 bytes', () => {
+ const bufferDecoder = BufferDecoder.fromArrayBuffer(createArrayBuffer(
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01));
+ if (CHECK_CRITICAL_STATE) {
+ expect(() => bufferDecoder.getUnsignedVarint32()).toThrow();
+ } else {
+ // Note in unchecked mode we produce invalid output for invalid inputs.
+ // This test just documents our behavior in those cases.
+ // These values might change at any point and are not considered
+ // what the implementation should be doing here.
+ const result = bufferDecoder.getUnsignedVarint32();
+ expect(result).toBe(4294967295);
+ expect(bufferDecoder.cursor()).toBe(10);
+ }
+ });
+});
+
+describe('readUnsignedVarint32At does', () => {
+ it('reads from a specific index', () => {
+ const bufferDecoder =
+ BufferDecoder.fromArrayBuffer(createArrayBuffer(0x1, 0x2));
+ const result = bufferDecoder.getUnsignedVarint32At(1);
+ expect(result).toBe(2);
+ expect(bufferDecoder.cursor()).toBe(2);
+ });
+});
+
+describe('getFloat32 does', () => {
+ it('read one', () => {
+ const bufferDecoder = BufferDecoder.fromArrayBuffer(
+ createArrayBuffer(0x00, 0x00, 0x80, 0x3F));
+ const result = bufferDecoder.getFloat32(0);
+ expect(result).toBe(1);
+ expect(bufferDecoder.cursor()).toBe(4);
+ });
+});
+
+describe('getFloat64 does', () => {
+ it('read one', () => {
+ const bufferDecoder = BufferDecoder.fromArrayBuffer(
+ createArrayBuffer(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x3F));
+ const result = bufferDecoder.getFloat64(0);
+ expect(result).toBe(1);
+ expect(bufferDecoder.cursor()).toBe(8);
+ });
+});
+
+describe('getInt32 does', () => {
+ it('read one', () => {
+ const bufferDecoder = BufferDecoder.fromArrayBuffer(
+ createArrayBuffer(0x01, 0x00, 0x00, 0x00));
+ const result = bufferDecoder.getInt32(0);
+ expect(result).toBe(1);
+ expect(bufferDecoder.cursor()).toBe(4);
+ });
+
+ it('read minus one', () => {
+ const bufferDecoder = BufferDecoder.fromArrayBuffer(
+ createArrayBuffer(0xFF, 0xFF, 0xFF, 0xFF));
+ const result = bufferDecoder.getInt32(0);
+ expect(result).toBe(-1);
+ expect(bufferDecoder.cursor()).toBe(4);
+ });
+});
+
+describe('getUint32 does', () => {
+ it('read one', () => {
+ const bufferDecoder =
+ BufferDecoder.fromArrayBuffer(createArrayBuffer(0x01, 0x00, 0x00, 0x0));
+ const result = bufferDecoder.getUint32(0);
+ expect(result).toBe(1);
+ expect(bufferDecoder.cursor()).toBe(4);
+ });
+
+ it('read max uint32', () => {
+ const bufferDecoder = BufferDecoder.fromArrayBuffer(
+ createArrayBuffer(0xFF, 0xFF, 0xFF, 0xFF));
+ const result = bufferDecoder.getUint32(0);
+ expect(result).toBe(4294967295);
+ expect(bufferDecoder.cursor()).toBe(4);
});
});
diff --git a/js/experimental/runtime/kernel/indexer.js b/js/experimental/runtime/kernel/indexer.js
index c247c2f..e281994 100644
--- a/js/experimental/runtime/kernel/indexer.js
+++ b/js/experimental/runtime/kernel/indexer.js
@@ -8,7 +8,7 @@
const Storage = goog.require('protobuf.binary.Storage');
const WireType = goog.require('protobuf.binary.WireType');
const {Field} = goog.require('protobuf.binary.field');
-const {checkCriticalPositionIndex, checkCriticalState} = goog.require('protobuf.internal.checks');
+const {checkCriticalElementIndex, checkCriticalState} = goog.require('protobuf.internal.checks');
/**
* Appends a new entry in the index array for the given field number.
@@ -57,8 +57,6 @@
constructor(bufferDecoder) {
/** @private @const {!BufferDecoder} */
this.bufferDecoder_ = bufferDecoder;
- /** @private {number} */
- this.cursor_ = bufferDecoder.startIndex();
}
/**
@@ -66,15 +64,18 @@
* @return {!Storage<!Field>}
*/
index(pivot) {
+ this.bufferDecoder_.setCursor(this.bufferDecoder_.startIndex());
+
const storage = new Storage(pivot);
- while (this.hasNextByte_()) {
- const tag = this.readVarInt32_();
+ while (this.bufferDecoder_.hasNext()) {
+ const tag = this.bufferDecoder_.getUnsignedVarint32();
const wireType = tagToWireType(tag);
const fieldNumber = tagToFieldNumber(tag);
checkCriticalState(
fieldNumber > 0, `Invalid field number ${fieldNumber}`);
- addIndexEntry(storage, fieldNumber, wireType, this.cursor_);
+ addIndexEntry(
+ storage, fieldNumber, wireType, this.bufferDecoder_.cursor());
checkCriticalState(
!this.skipField_(wireType, fieldNumber),
@@ -93,14 +94,18 @@
skipField_(wireType, fieldNumber) {
switch (wireType) {
case WireType.VARINT:
- this.cursor_ = this.bufferDecoder_.skipVarint(this.cursor_);
+ checkCriticalElementIndex(
+ this.bufferDecoder_.cursor(), this.bufferDecoder_.endIndex());
+ this.bufferDecoder_.skipVarint(this.bufferDecoder_.cursor());
return false;
case WireType.FIXED64:
- this.skip_(8);
+ this.bufferDecoder_.skip(8);
return false;
case WireType.DELIMITED:
- const length = this.readVarInt32_();
- this.skip_(length);
+ checkCriticalElementIndex(
+ this.bufferDecoder_.cursor(), this.bufferDecoder_.endIndex());
+ const length = this.bufferDecoder_.getUnsignedVarint32();
+ this.bufferDecoder_.skip(length);
return false;
case WireType.START_GROUP:
checkCriticalState(this.skipGroup_(fieldNumber), 'No end group found.');
@@ -109,7 +114,7 @@
// Signal that we found a stop group to the caller
return true;
case WireType.FIXED32:
- this.skip_(4);
+ this.bufferDecoder_.skip(4);
return false;
default:
throw new Error(`Invalid wire type: ${wireType}`);
@@ -117,16 +122,6 @@
}
/**
- * Seeks forward by the given amount.
- * @param {number} skipAmount
- * @private
- */
- skip_(skipAmount) {
- this.cursor_ += skipAmount;
- checkCriticalPositionIndex(this.cursor_, this.bufferDecoder_.endIndex());
- }
-
- /**
* Skips over fields until it finds the end of a given group.
* @param {number} groupFieldNumber
* @return {boolean} Returns true if an end was found.
@@ -138,8 +133,8 @@
// Note: Since we are calling skipField from here nested groups will be
// handled by recursion of this method and thus we will not see a nested
// STOP GROUP here unless there is something wrong with the input data.
- while (this.hasNextByte_()) {
- const tag = this.readVarInt32_();
+ while (this.bufferDecoder_.hasNext()) {
+ const tag = this.bufferDecoder_.getUnsignedVarint32();
const wireType = tagToWireType(tag);
const fieldNumber = tagToFieldNumber(tag);
@@ -153,26 +148,6 @@
}
return false;
}
-
- /**
- * Returns a JS number for a 32 bit var int.
- * @return {number}
- * @private
- */
- readVarInt32_() {
- const {lowBits, dataStart} = this.bufferDecoder_.getVarint(this.cursor_);
- this.cursor_ = dataStart;
- return lowBits;
- }
-
- /**
- * Returns true if there are more bytes to read in the array.
- * @return {boolean}
- * @private
- */
- hasNextByte_() {
- return this.cursor_ < this.bufferDecoder_.endIndex();
- }
}
/**
@@ -186,7 +161,6 @@
return new Indexer(bufferDecoder).index(pivot);
}
-
exports = {
buildIndex,
};
diff --git a/js/experimental/runtime/kernel/reader.js b/js/experimental/runtime/kernel/reader.js
index fec79cf..2b80e15 100644
--- a/js/experimental/runtime/kernel/reader.js
+++ b/js/experimental/runtime/kernel/reader.js
@@ -6,6 +6,7 @@
const BufferDecoder = goog.require('protobuf.binary.BufferDecoder');
const ByteString = goog.require('protobuf.ByteString');
const Int64 = goog.require('protobuf.Int64');
+const {checkState} = goog.require('protobuf.internal.checks');
/******************************************************************************
@@ -13,18 +14,6 @@
******************************************************************************/
/**
- * Reads a boolean from the binary bytes.
- * Also returns the first position after the boolean.
- * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
- * @param {number} index Start of the data.
- * @return {{value: boolean, nextCursor: number}}
- */
-function readBoolValue(bufferDecoder, index) {
- const {lowBits, highBits, dataStart} = bufferDecoder.getVarint(index);
- return {value: lowBits !== 0 || highBits !== 0, nextCursor: dataStart};
-}
-
-/**
* Reads a boolean value from the binary bytes.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
@@ -32,11 +21,12 @@
* @package
*/
function readBool(bufferDecoder, start) {
- return readBoolValue(bufferDecoder, start).value;
+ const {lowBits, highBits} = bufferDecoder.getVarint(start);
+ return lowBits !== 0 || highBits !== 0;
}
/**
- * Reads a double value from the binary bytes.
+ * Reads a ByteString value from the binary bytes.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {!ByteString}
@@ -49,39 +39,15 @@
/**
* Reads a int32 value from the binary bytes encoded as varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
- * @param {number} index Start of the data.
- * @return {{value: number, nextCursor: number}}
- * @package
- */
-function readInt32Value(bufferDecoder, index) {
- const {lowBits, dataStart} = bufferDecoder.getVarint(index);
- // Negative 32 bit integers are encoded with 64 bit values.
- // Clients are expected to truncate back to 32 bits.
- // This is why we are dropping the upper bytes here.
- return {value: lowBits | 0, nextCursor: dataStart};
-}
-
-/**
- * Reads a int32 value from the binary bytes encoded as varint.
- * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {number}
* @package
*/
function readInt32(bufferDecoder, start) {
- return readInt32Value(bufferDecoder, start).value;
-}
-
-/**
- * Reads a int32 value from the binary bytes encoded as varint.
- * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
- * @param {number} index Start of the data.
- * @return {{ value: !Int64, nextCursor: number}}
- * @package
- */
-function readInt64Value(bufferDecoder, index) {
- const {lowBits, highBits, dataStart} = bufferDecoder.getVarint(index);
- return {value: Int64.fromBits(lowBits, highBits), nextCursor: dataStart};
+ // Negative 32 bit integers are encoded with 64 bit values.
+ // Clients are expected to truncate back to 32 bits.
+ // This is why we are dropping the upper bytes here.
+ return bufferDecoder.getUnsignedVarint32At(start) | 0;
}
/**
@@ -92,7 +58,8 @@
* @package
*/
function readInt64(bufferDecoder, start) {
- return readInt64Value(bufferDecoder, start).value;
+ const {lowBits, highBits} = bufferDecoder.getVarint(start);
+ return Int64.fromBits(lowBits, highBits);
}
/**
@@ -132,45 +99,15 @@
/**
* Reads a sint32 value from the binary bytes encoded as varint.
- * Also returns the first position after the boolean.
- * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
- * @param {number} index Start of the data.
- * @return {{value: number, nextCursor: number}}
- */
-function readSint32Value(bufferDecoder, index) {
- const {lowBits, dataStart} = bufferDecoder.getVarint(index);
- // Truncate upper bits and convert from zig zag to signd int
- return {value: (lowBits >>> 1) ^ -(lowBits & 0x01), nextCursor: dataStart};
-}
-
-/**
- * Reads a sint32 value from the binary bytes encoded as varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {number}
* @package
*/
function readSint32(bufferDecoder, start) {
- return readSint32Value(bufferDecoder, start).value;
-}
-
-/**
- * Reads a sint64 value from the binary bytes encoded as varint.
- * Also returns the first position after the value.
- * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
- * @param {number} index Start of the data.
- * @return {{value: !Int64, nextCursor: number}}
- * @package
- */
-function readSint64Value(bufferDecoder, index) {
- const {lowBits, highBits, dataStart} = bufferDecoder.getVarint(index);
- const sign = -(lowBits & 0x01);
- const decodedLowerBits = ((lowBits >>> 1) | (highBits & 0x01) << 31) ^ sign;
- const decodedUpperBits = (highBits >>> 1) ^ sign;
- return {
- value: Int64.fromBits(decodedLowerBits, decodedUpperBits),
- nextCursor: dataStart
- };
+ const bits = bufferDecoder.getUnsignedVarint32At(start);
+ // Truncate upper bits and convert from zig zag to signd int
+ return (bits >>> 1) ^ -(bits & 0x01);
}
/**
@@ -181,7 +118,11 @@
* @package
*/
function readSint64(bufferDecoder, start) {
- return readSint64Value(bufferDecoder, start).value;
+ const {lowBits, highBits} = bufferDecoder.getVarint(start);
+ const sign = -(lowBits & 0x01);
+ const decodedLowerBits = ((lowBits >>> 1) | (highBits & 0x01) << 31) ^ sign;
+ const decodedUpperBits = (highBits >>> 1) ^ sign;
+ return Int64.fromBits(decodedLowerBits, decodedUpperBits);
}
/**
@@ -192,9 +133,8 @@
* @package
*/
function readDelimited(bufferDecoder, start) {
- const {lowBits, dataStart} = bufferDecoder.getVarint(start);
- const unsignedLength = lowBits >>> 0;
- return bufferDecoder.subBufferDecoder(dataStart, unsignedLength);
+ const unsignedLength = bufferDecoder.getUnsignedVarint32At(start);
+ return bufferDecoder.subBufferDecoder(bufferDecoder.cursor(), unsignedLength);
}
/**
@@ -210,25 +150,13 @@
/**
* Reads a uint32 value from the binary bytes encoded as varint.
- * Also returns the first position after the value.
- * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
- * @param {number} index Start of the data.
- * @return {{value: number, nextCursor: number}}
- */
-function readUint32Value(bufferDecoder, index) {
- const {lowBits, dataStart} = bufferDecoder.getVarint(index);
- return {value: lowBits >>> 0, nextCursor: dataStart};
-}
-
-/**
- * Reads a uint32 value from the binary bytes encoded as varint.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
* @return {number}
* @package
*/
function readUint32(bufferDecoder, start) {
- return readUint32Value(bufferDecoder, start).value;
+ return bufferDecoder.getUnsignedVarint32At(start);
}
/**
@@ -266,7 +194,7 @@
* @package
*/
function readPackedBool(bufferDecoder, start) {
- return readPackedVariableLength(bufferDecoder, start, readBoolValue);
+ return readPacked(bufferDecoder, start, readBool);
}
/**
@@ -278,7 +206,7 @@
* @package
*/
function readPackedDouble(bufferDecoder, start) {
- return readPackedFixed(bufferDecoder, start, 8, readDouble);
+ return readPacked(bufferDecoder, start, readDouble);
}
/**
@@ -290,7 +218,7 @@
* @package
*/
function readPackedFixed32(bufferDecoder, start) {
- return readPackedFixed(bufferDecoder, start, 4, readFixed32);
+ return readPacked(bufferDecoder, start, readFixed32);
}
/**
@@ -302,7 +230,7 @@
* @package
*/
function readPackedFloat(bufferDecoder, start) {
- return readPackedFixed(bufferDecoder, start, 4, readFloat);
+ return readPacked(bufferDecoder, start, readFloat);
}
/**
@@ -314,7 +242,7 @@
* @package
*/
function readPackedInt32(bufferDecoder, start) {
- return readPackedVariableLength(bufferDecoder, start, readInt32Value);
+ return readPacked(bufferDecoder, start, readInt32);
}
/**
@@ -326,7 +254,7 @@
* @package
*/
function readPackedInt64(bufferDecoder, start) {
- return readPackedVariableLength(bufferDecoder, start, readInt64Value);
+ return readPacked(bufferDecoder, start, readInt64);
}
/**
@@ -338,7 +266,7 @@
* @package
*/
function readPackedSfixed32(bufferDecoder, start) {
- return readPackedFixed(bufferDecoder, start, 4, readSfixed32);
+ return readPacked(bufferDecoder, start, readSfixed32);
}
/**
@@ -350,7 +278,7 @@
* @package
*/
function readPackedSfixed64(bufferDecoder, start) {
- return readPackedFixed(bufferDecoder, start, 8, readSfixed64);
+ return readPacked(bufferDecoder, start, readSfixed64);
}
/**
@@ -362,7 +290,7 @@
* @package
*/
function readPackedSint32(bufferDecoder, start) {
- return readPackedVariableLength(bufferDecoder, start, readSint32Value);
+ return readPacked(bufferDecoder, start, readSint32);
}
/**
@@ -374,7 +302,7 @@
* @package
*/
function readPackedSint64(bufferDecoder, start) {
- return readPackedVariableLength(bufferDecoder, start, readSint64Value);
+ return readPacked(bufferDecoder, start, readSint64);
}
/**
@@ -386,51 +314,25 @@
* @package
*/
function readPackedUint32(bufferDecoder, start) {
- return readPackedVariableLength(bufferDecoder, start, readUint32Value);
+ return readPacked(bufferDecoder, start, readUint32);
}
/**
- * Read packed variable length values.
+ * Read packed values.
* @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
* @param {number} start Start of the data.
- * @param {function(!BufferDecoder, number):{value:T, nextCursor: number}}
- * valueFunction
- * @return {!Array<T>}
- * @package
- * @template T
- */
-function readPackedVariableLength(bufferDecoder, start, valueFunction) {
- const /** !Array<T> */ result = [];
- const {lowBits, dataStart} = bufferDecoder.getVarint(start);
- let cursor = dataStart;
- const unsignedLength = lowBits >>> 0;
- while (cursor < dataStart + unsignedLength) {
- const {value, nextCursor} = valueFunction(bufferDecoder, cursor);
- cursor = nextCursor;
- result.push(value);
- }
- return result;
-}
-
-/**
- * Read a packed fixed values.
- * @param {!BufferDecoder} bufferDecoder Binary format encoded bytes.
- * @param {number} start Start of the data.
- * @param {number} size End of the data.
* @param {function(!BufferDecoder, number):T} valueFunction
* @return {!Array<T>}
* @package
* @template T
*/
-function readPackedFixed(bufferDecoder, start, size, valueFunction) {
- const {lowBits, dataStart} = bufferDecoder.getVarint(start);
- const unsignedLength = lowBits >>> 0;
- const noOfEntries = unsignedLength / size;
- const /** !Array<T> */ result = new Array(noOfEntries);
- let cursor = dataStart;
- for (let i = 0; i < noOfEntries; i++) {
- result[i] = valueFunction(bufferDecoder, cursor);
- cursor += size;
+function readPacked(bufferDecoder, start, valueFunction) {
+ const /** !Array<T> */ result = [];
+ const unsignedLength = bufferDecoder.getUnsignedVarint32At(start);
+ const dataStart = bufferDecoder.cursor();
+ while (bufferDecoder.cursor() < dataStart + unsignedLength) {
+ checkState(bufferDecoder.cursor() > 0);
+ result.push(valueFunction(bufferDecoder, bufferDecoder.cursor()));
}
return result;
}
diff --git a/js/experimental/runtime/kernel/reader_test.js b/js/experimental/runtime/kernel/reader_test.js
index a0cbcae..dd02086 100644
--- a/js/experimental/runtime/kernel/reader_test.js
+++ b/js/experimental/runtime/kernel/reader_test.js
@@ -12,7 +12,7 @@
const BufferDecoder = goog.require('protobuf.binary.BufferDecoder');
const ByteString = goog.require('protobuf.ByteString');
const reader = goog.require('protobuf.binary.reader');
-const {CHECK_STATE} = goog.require('protobuf.internal.checks');
+const {CHECK_CRITICAL_STATE} = goog.require('protobuf.internal.checks');
const {createBufferDecoder} = goog.require('protobuf.binary.bufferDecoderHelper');
const {encode} = goog.require('protobuf.binary.textencoding');
const {getBoolPairs} = goog.require('protobuf.binary.boolTestPairs');
@@ -45,7 +45,7 @@
describe('Read bool does', () => {
for (const pair of getBoolPairs()) {
it(`decode ${pair.name}`, () => {
- if (pair.error && CHECK_STATE) {
+ if (pair.error && CHECK_CRITICAL_STATE) {
expect(() => reader.readBool(pair.bufferDecoder, 0)).toThrow();
} else {
const d = reader.readBool(
@@ -120,7 +120,7 @@
for (const pair of getInt32Pairs()) {
it(`decode ${pair.name}`, () => {
- if (pair.error && CHECK_STATE) {
+ if (pair.error && CHECK_CRITICAL_STATE) {
expect(() => reader.readInt32(pair.bufferDecoder, 0)).toThrow();
} else {
const d = reader.readInt32(pair.bufferDecoder, 0);
@@ -166,7 +166,7 @@
for (const pair of getSint32Pairs()) {
it(`decode ${pair.name}`, () => {
- if (pair.error && CHECK_STATE) {
+ if (pair.error && CHECK_CRITICAL_STATE) {
expect(() => reader.readSint32(pair.bufferDecoder, 0)).toThrow();
} else {
const d = reader.readSint32(pair.bufferDecoder, 0);
@@ -184,7 +184,7 @@
for (const pair of getInt64Pairs()) {
it(`decode ${pair.name}`, () => {
- if (pair.error && CHECK_STATE) {
+ if (pair.error && CHECK_CRITICAL_STATE) {
expect(() => reader.readInt64(pair.bufferDecoder, 0)).toThrow();
} else {
const d = reader.readInt64(pair.bufferDecoder, 0);
@@ -202,7 +202,7 @@
for (const pair of getSint64Pairs()) {
it(`decode ${pair.name}`, () => {
- if (pair.error && CHECK_STATE) {
+ if (pair.error && CHECK_CRITICAL_STATE) {
expect(() => reader.readSint64(pair.bufferDecoder, 0)).toThrow();
} else {
const d = reader.readSint64(pair.bufferDecoder, 0);
@@ -220,7 +220,7 @@
for (const pair of getUint32Pairs()) {
it(`decode ${pair.name}`, () => {
- if (pair.error && CHECK_STATE) {
+ if (pair.error && CHECK_CRITICAL_STATE) {
expect(() => reader.readUint32(pair.bufferDecoder, 0)).toThrow();
} else {
const d = reader.readUint32(pair.bufferDecoder, 0);
diff --git a/js/experimental/runtime/kernel/writer.js b/js/experimental/runtime/kernel/writer.js
index 1fc7418..a0178d2 100644
--- a/js/experimental/runtime/kernel/writer.js
+++ b/js/experimental/runtime/kernel/writer.js
@@ -450,12 +450,13 @@
getLength_(bufferDecoder, start, wireType) {
switch (wireType) {
case WireType.VARINT:
- return bufferDecoder.skipVarint(start) - start;
+ bufferDecoder.skipVarint(start);
+ return bufferDecoder.cursor() - start;
case WireType.FIXED64:
return 8;
case WireType.DELIMITED:
- const {lowBits: dataLength, dataStart} = bufferDecoder.getVarint(start);
- return dataLength + dataStart - start;
+ const dataLength = bufferDecoder.getUnsignedVarint32At(start);
+ return dataLength + bufferDecoder.cursor() - start;
case WireType.START_GROUP:
return this.getGroupLength_(bufferDecoder, start);
case WireType.FIXED32:
@@ -477,12 +478,13 @@
// corresponding stop group
let cursor = start;
while (cursor < bufferDecoder.endIndex()) {
- const {lowBits: tag, dataStart} = bufferDecoder.getVarint(cursor);
+ const tag = bufferDecoder.getUnsignedVarint32At(cursor);
const wireType = /** @type {!WireType} */ (tag & 0x07);
if (wireType === WireType.END_GROUP) {
- return dataStart - start;
+ return bufferDecoder.cursor() - start;
}
- cursor = dataStart + this.getLength_(bufferDecoder, dataStart, wireType);
+ cursor = bufferDecoder.cursor() +
+ this.getLength_(bufferDecoder, bufferDecoder.cursor(), wireType);
}
throw new Error('No end group found');
}