diff --git a/README.md b/README.md index 260b244..7f78ffc 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ const buffer = pbf.finish(); Alternatively, you can compile a protobuf schema file directly in the code: ```js -import compile from 'pbf/compile'; +import {compile} from 'pbf/compile'; import schema from 'protocol-buffers-schema'; const proto = schema.parse(fs.readFileSync('example.proto')); diff --git a/bench/bench.js b/bench/bench.js index 09d4216..589ca6c 100644 --- a/bench/bench.js +++ b/bench/bench.js @@ -5,12 +5,12 @@ import {fileURLToPath} from 'node:url'; import protocolBuffers from 'protocol-buffers'; import protobufjs from 'protobufjs'; -import {readTile, writeTile} from './vector_tile.js'; +import {readTile, writeTile} from '../test/fixtures/vector_tile.js'; import Pbf from '../index.js'; var data = fs.readFileSync(new URL('../test/fixtures/12665.vector.pbf', import.meta.url)), suite = new Benchmark.Suite(), - vtProtoUrl = new URL('vector_tile.proto', import.meta.url), + vtProtoUrl = new URL('../test/fixtures/vector_tile.proto', import.meta.url), ProtocolBuffersTile = protocolBuffers(fs.readFileSync(vtProtoUrl)).Tile, ProtobufjsTile = protobufjs.loadSync(fileURLToPath(vtProtoUrl)).lookup('vector_tile.Tile'); diff --git a/compile.js b/compile.js index cd07ba6..90a6d47 100644 --- a/compile.js +++ b/compile.js @@ -9,7 +9,7 @@ export function compile(proto) { export function compileRaw(proto, options = {}) { const context = buildDefaults(buildContext(proto, null), proto.syntax); - return `// code generated by pbf v${version}\n${writeContext(context, options)}`; + return `${options.dev ? '' : `// code generated by pbf v${version}\n`}${writeContext(context, options)}`; } function writeContext(ctx, options) { @@ -32,9 +32,9 @@ function writeMessage(ctx, options) { const readName = `read${ctx._name}`; code += `${writeFunctionExport(options, readName)}function ${readName}(pbf, end) { - return pbf.readFields(${readName}Tag, ${compileDest(ctx)}, end); + return pbf.readFields(${readName}Field, ${compileDest(ctx)}, end); } -function ${readName}Tag(tag, obj, pbf) { +function ${readName}Field(tag, obj, pbf) { `; for (let i = 0; i < fields.length; i++) { const field = fields[i]; @@ -138,7 +138,7 @@ function fieldShouldUseStringAsNumber(field) { function compileFieldRead(ctx, field) { const type = getType(ctx, field); if (type) { - if (type._proto.fields) return `read${type._name}(pbf, pbf.readEnd())`; + if (type._proto.fields) return `read${type._name}(pbf, pbf.readVarint() + pbf.pos)`; if (!isEnum(type)) throw new Error(`Unexpected type: ${type._name}`); } diff --git a/eslint.config.js b/eslint.config.js index 2fa4d9b..5da1771 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -10,11 +10,12 @@ export default [ } }, { - files: ['bench/*.js'], + files: ['test/fixtures/*.js'], rules: { camelcase: 0, '@stylistic/js/quotes': 0, '@stylistic/js/semi': 0, + '@stylistic/js/brace-style': 0, 'no-unused-vars': 0 } } diff --git a/index.js b/index.js index 21f1768..f610634 100644 --- a/index.js +++ b/index.js @@ -43,7 +43,7 @@ export default class Pbf { } readMessage(readField, result) { - return this.readFields(readField, result, this.readEnd()); + return this.readFields(readField, result, this.readVarint() + this.pos); } readFixed32() { @@ -111,7 +111,7 @@ export default class Pbf { } readString() { - const end = this.readEnd(); + const end = this.readVarint() + this.pos; const pos = this.pos; this.pos = end; @@ -124,7 +124,7 @@ export default class Pbf { } readBytes() { - const end = this.readEnd(), + const end = this.readVarint() + this.pos, buffer = this.buf.subarray(this.pos, end); this.pos = end; return buffer; @@ -177,17 +177,14 @@ export default class Pbf { while (this.pos < end) arr.push(this.readSFixed64()); return arr; } - readEnd() { - return this.readVarint() + this.pos; - } readPackedEnd() { - return this.type === PBF_BYTES ? this.readEnd() : this.pos + 1; + return this.type === PBF_BYTES ? this.readVarint() + this.pos : this.pos + 1; } skip(val) { const type = val & 0x7; if (type === PBF_VARINT) while (this.buf[this.pos++] > 0x7f) {} - else if (type === PBF_BYTES) this.pos = this.readEnd(); + else if (type === PBF_BYTES) this.pos = this.readVarint() + this.pos; else if (type === PBF_FIXED32) this.pos += 4; else if (type === PBF_FIXED64) this.pos += 8; else throw new Error(`Unimplemented type: ${type}`); diff --git a/package.json b/package.json index 16c7074..e626e9d 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "scripts": { "bench": "node bench/bench.js", - "pretest": "eslint *.js compile.js test/*.js bench/vector_tile.js bin/pbf", + "pretest": "eslint *.js compile.js test/*.js test/fixtures/*.js bin/pbf", "test": "node --test", "cov": "node --test --experimental-test-covetage", "build": "rollup -c", diff --git a/test/compile.test.js b/test/compile.test.js index 1ba3afa..2f94f35 100644 --- a/test/compile.test.js +++ b/test/compile.test.js @@ -4,10 +4,26 @@ import assert from 'node:assert/strict'; import {sync as resolve} from 'resolve-protobuf-schema'; import Pbf from '../index.js'; -import {compile} from '../compile.js'; +import {compile, compileRaw} from '../compile.js'; + +test('compiles all proto files to proper js', () => { + const files = fs.readdirSync(new URL('fixtures', import.meta.url)); + + for (const path of files) { + if (!path.endsWith('.proto')) continue; + const proto = resolve(new URL(`fixtures/${path}`, import.meta.url)); + const js = compileRaw(proto, {dev: true}); + + // uncomment to update the fixtures + // fs.writeFileSync(new URL(`fixtures/${path}`.replace('.proto', '.js'), import.meta.url), js); + + const expectedJS = fs.readFileSync(new URL(`fixtures/${path}`.replace('.proto', '.js'), import.meta.url), 'utf8'); + assert.equal(js, expectedJS); + } +}); test('compiles vector tile proto', () => { - const proto = resolve(new URL('../bench/vector_tile.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/vector_tile.proto', import.meta.url)); const tileBuf = fs.readFileSync(new URL('fixtures/12665.vector.pbf', import.meta.url)); const {readTile, writeTile} = compile(proto); @@ -21,12 +37,12 @@ test('compiles vector tile proto', () => { }); test('compiles proto with embedded type reference', () => { - const proto = resolve(new URL('./fixtures/embedded_type.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/embedded_type.proto', import.meta.url)); compile(proto); }); test('compiles packed proto', () => { - const proto = resolve(new URL('./fixtures/packed.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/packed.proto', import.meta.url)); const {writeNotPacked, readFalsePacked} = compile(proto); const original = { @@ -43,7 +59,7 @@ test('compiles packed proto', () => { }); test('reads packed with unpacked field', () => { - const proto = resolve(new URL('./fixtures/packed.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/packed.proto', import.meta.url)); const {writePacked, readFalsePacked} = compile(proto); const original = { @@ -60,7 +76,7 @@ test('reads packed with unpacked field', () => { }); test('compiles packed proto3', () => { - const proto = resolve(new URL('./fixtures/packed_proto3.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/packed_proto3.proto', import.meta.url)); const {readNotPacked, writeNotPacked, writeFalsePacked} = compile(proto); const original = { @@ -82,7 +98,7 @@ test('compiles packed proto3', () => { }); test('compiles packed with multi-byte tags', () => { - const proto = resolve(new URL('./fixtures/packed_proto3.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/packed_proto3.proto', import.meta.url)); const {readPacked, writePacked} = compile(proto); const original = { @@ -98,7 +114,7 @@ test('compiles packed with multi-byte tags', () => { }); test('compiles defaults', () => { - const proto = resolve(new URL('./fixtures/defaults.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/defaults.proto', import.meta.url)); const {readEnvelope, writeEnvelope} = compile(proto); const pbf = new Pbf(); @@ -118,7 +134,7 @@ test('compiles defaults', () => { }); test('compiles proto3 ignoring defaults', () => { - const proto = resolve(new URL('./fixtures/defaults_proto3.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/defaults_proto3.proto', import.meta.url)); const {readEnvelope, writeEnvelope} = compile(proto); const pbf = new Pbf(); @@ -137,7 +153,7 @@ test('compiles proto3 ignoring defaults', () => { }); test('compiles maps', () => { - const proto = resolve(new URL('./fixtures/map.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/map.proto', import.meta.url)); const {readEnvelope, writeEnvelope} = compile(proto); const original = { @@ -161,7 +177,7 @@ test('compiles maps', () => { }); test('does not write undefined or null values', () => { - const proto = resolve(new URL('./fixtures/embedded_type.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/embedded_type.proto', import.meta.url)); const {writeEmbeddedType} = compile(proto); const pbf = new Pbf(); @@ -177,7 +193,7 @@ test('does not write undefined or null values', () => { }); test('handles all implicit default values', () => { - const proto = resolve(new URL('./fixtures/defaults_implicit.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/defaults_implicit.proto', import.meta.url)); const {readEnvelope, writeEnvelope} = compile(proto); const pbf = new Pbf(); @@ -200,7 +216,7 @@ test('handles all implicit default values', () => { }); test('sets oneof field name', () => { - const proto = resolve(new URL('./fixtures/oneof.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/oneof.proto', import.meta.url)); const {readEnvelope, writeEnvelope} = compile(proto); let pbf = new Pbf(); @@ -221,7 +237,7 @@ test('sets oneof field name', () => { }); test('handles jstype=JS_STRING', () => { - const proto = resolve(new URL('./fixtures/type_string.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/type_string.proto', import.meta.url)); const {readTypeString, writeTypeString, readTypeNotString} = compile(proto); const pbf = new Pbf(); @@ -250,7 +266,7 @@ test('handles jstype=JS_STRING', () => { }); test('handles negative varint', () => { - const proto = resolve(new URL('./fixtures/varint.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/varint.proto', import.meta.url)); const {readEnvelope, writeEnvelope} = compile(proto); const pbf = new Pbf(); @@ -267,7 +283,7 @@ test('handles negative varint', () => { }); test('handles unsigned varint', () => { - const proto = resolve(new URL('./fixtures/varint.proto', import.meta.url)); + const proto = resolve(new URL('fixtures/varint.proto', import.meta.url)); const {readEnvelope, writeEnvelope} = compile(proto); const pbf = new Pbf(); diff --git a/test/fixtures/defaults.js b/test/fixtures/defaults.js new file mode 100644 index 0000000..bf0ef32 --- /dev/null +++ b/test/fixtures/defaults.js @@ -0,0 +1,23 @@ + +export const MessageType = { + "UNKNOWN": 0, + "GREETING": 1 +}; + +export function readEnvelope(pbf, end) { + return pbf.readFields(readEnvelopeField, {type: 1, name: "test", flag: true, weight: 1.5, id: 1}, end); +} +function readEnvelopeField(tag, obj, pbf) { + if (tag === 1) obj.type = pbf.readVarint(); + else if (tag === 2) obj.name = pbf.readString(); + else if (tag === 3) obj.flag = pbf.readBoolean(); + else if (tag === 4) obj.weight = pbf.readFloat(); + else if (tag === 5) obj.id = pbf.readVarint(true); +} +export function writeEnvelope(obj, pbf) { + if (obj.type != null && obj.type !== 1) pbf.writeVarintField(1, obj.type); + if (obj.name != null && obj.name !== "test") pbf.writeStringField(2, obj.name); + if (obj.flag != null && obj.flag !== true) pbf.writeBooleanField(3, obj.flag); + if (obj.weight != null && obj.weight !== 1.5) pbf.writeFloatField(4, obj.weight); + if (obj.id != null && obj.id !== 1) pbf.writeVarintField(5, obj.id); +} diff --git a/test/fixtures/defaults_implicit.js b/test/fixtures/defaults_implicit.js new file mode 100644 index 0000000..5603350 --- /dev/null +++ b/test/fixtures/defaults_implicit.js @@ -0,0 +1,41 @@ + +export const MessageType = { + "UNKNOWN": 0, + "GREETING": 1 +}; + +export function readCustomType(pbf, end) { + return pbf.readFields(readCustomTypeField, {}, end); +} +function readCustomTypeField(tag, obj, pbf) { +} +export function writeCustomType(obj, pbf) { +} + +export function readEnvelope(pbf, end) { + return pbf.readFields(readEnvelopeField, {type: 0, name: "", flag: false, weight: 0, id: 0, tags: [], numbers: [], bytes: undefined, custom: undefined, types: []}, end); +} +function readEnvelopeField(tag, obj, pbf) { + if (tag === 1) obj.type = pbf.readVarint(); + else if (tag === 2) obj.name = pbf.readString(); + else if (tag === 3) obj.flag = pbf.readBoolean(); + else if (tag === 4) obj.weight = pbf.readFloat(); + else if (tag === 5) obj.id = pbf.readVarint(true); + else if (tag === 6) obj.tags.push(pbf.readString()); + else if (tag === 7) pbf.readPackedVarint(obj.numbers, true); + else if (tag === 8) obj.bytes = pbf.readBytes(); + else if (tag === 9) obj.custom = readCustomType(pbf, pbf.readVarint() + pbf.pos); + else if (tag === 10) pbf.readPackedVarint(obj.types); +} +export function writeEnvelope(obj, pbf) { + if (obj.type) pbf.writeVarintField(1, obj.type); + if (obj.name) pbf.writeStringField(2, obj.name); + if (obj.flag) pbf.writeBooleanField(3, obj.flag); + if (obj.weight) pbf.writeFloatField(4, obj.weight); + if (obj.id) pbf.writeVarintField(5, obj.id); + if (obj.tags) for (const item of obj.tags) pbf.writeStringField(6, item); + if (obj.numbers) for (const item of obj.numbers) pbf.writeVarintField(7, item); + if (obj.bytes != null) pbf.writeBytesField(8, obj.bytes); + if (obj.custom) pbf.writeMessage(9, writeCustomType, obj.custom); + if (obj.types) for (const item of obj.types) pbf.writeVarintField(10, item); +} diff --git a/test/fixtures/defaults_proto3.js b/test/fixtures/defaults_proto3.js new file mode 100644 index 0000000..57748fb --- /dev/null +++ b/test/fixtures/defaults_proto3.js @@ -0,0 +1,23 @@ + +export const MessageType = { + "UNKNOWN": 0, + "GREETING": 1 +}; + +export function readEnvelope(pbf, end) { + return pbf.readFields(readEnvelopeField, {type: 0, name: "", flag: false, weight: 0, id: 0}, end); +} +function readEnvelopeField(tag, obj, pbf) { + if (tag === 1) obj.type = pbf.readVarint(); + else if (tag === 2) obj.name = pbf.readString(); + else if (tag === 3) obj.flag = pbf.readBoolean(); + else if (tag === 4) obj.weight = pbf.readFloat(); + else if (tag === 5) obj.id = pbf.readVarint(true); +} +export function writeEnvelope(obj, pbf) { + if (obj.type) pbf.writeVarintField(1, obj.type); + if (obj.name) pbf.writeStringField(2, obj.name); + if (obj.flag) pbf.writeBooleanField(3, obj.flag); + if (obj.weight) pbf.writeFloatField(4, obj.weight); + if (obj.id) pbf.writeVarintField(5, obj.id); +} diff --git a/test/fixtures/embedded_type.js b/test/fixtures/embedded_type.js new file mode 100644 index 0000000..4c41ddf --- /dev/null +++ b/test/fixtures/embedded_type.js @@ -0,0 +1,34 @@ + +export function readEmbeddedType(pbf, end) { + return pbf.readFields(readEmbeddedTypeField, {value: "test", sub_field: undefined, sub_sub_field: undefined}, end); +} +function readEmbeddedTypeField(tag, obj, pbf) { + if (tag === 1) obj.value = pbf.readString(); + else if (tag === 4) obj.sub_field = readEmbeddedTypeContainer(pbf, pbf.readVarint() + pbf.pos); + else if (tag === 5) obj.sub_sub_field = readEmbeddedTypeContainerInner(pbf, pbf.readVarint() + pbf.pos); +} +export function writeEmbeddedType(obj, pbf) { + if (obj.value != null && obj.value !== "test") pbf.writeStringField(1, obj.value); + if (obj.sub_field) pbf.writeMessage(4, writeEmbeddedTypeContainer, obj.sub_field); + if (obj.sub_sub_field) pbf.writeMessage(5, writeEmbeddedTypeContainerInner, obj.sub_sub_field); +} + +export function readEmbeddedTypeContainer(pbf, end) { + return pbf.readFields(readEmbeddedTypeContainerField, {values: []}, end); +} +function readEmbeddedTypeContainerField(tag, obj, pbf) { + if (tag === 1) obj.values.push(readEmbeddedTypeContainerInner(pbf, pbf.readVarint() + pbf.pos)); +} +export function writeEmbeddedTypeContainer(obj, pbf) { + if (obj.values) for (const item of obj.values) pbf.writeMessage(1, writeEmbeddedTypeContainerInner, item); +} + +export function readEmbeddedTypeContainerInner(pbf, end) { + return pbf.readFields(readEmbeddedTypeContainerInnerField, {value: ""}, end); +} +function readEmbeddedTypeContainerInnerField(tag, obj, pbf) { + if (tag === 1) obj.value = pbf.readString(); +} +export function writeEmbeddedTypeContainerInner(obj, pbf) { + if (obj.value) pbf.writeStringField(1, obj.value); +} diff --git a/test/fixtures/map.js b/test/fixtures/map.js new file mode 100644 index 0000000..793d26c --- /dev/null +++ b/test/fixtures/map.js @@ -0,0 +1,36 @@ + +export function readEnvelope(pbf, end) { + return pbf.readFields(readEnvelopeField, {kv: {}, kn: {}}, end); +} +function readEnvelopeField(tag, obj, pbf) { + if (tag === 1) { const {key, value} = readEnvelope_FieldEntry1(pbf, pbf.readVarint() + pbf.pos); obj.kv[key] = value; } + else if (tag === 2) { const {key, value} = readEnvelope_FieldEntry2(pbf, pbf.readVarint() + pbf.pos); obj.kn[key] = value; } +} +export function writeEnvelope(obj, pbf) { + if (obj.kv) for (const key of Object.keys(obj.kv)) pbf.writeMessage(1, writeEnvelope_FieldEntry1, {key, value: obj.kv[key]}); + if (obj.kn) for (const key of Object.keys(obj.kn)) pbf.writeMessage(2, writeEnvelope_FieldEntry2, {key, value: obj.kn[key]}); +} + +export function readEnvelope_FieldEntry1(pbf, end) { + return pbf.readFields(readEnvelope_FieldEntry1Field, {key: "", value: ""}, end); +} +function readEnvelope_FieldEntry1Field(tag, obj, pbf) { + if (tag === 1) obj.key = pbf.readString(); + else if (tag === 2) obj.value = pbf.readString(); +} +export function writeEnvelope_FieldEntry1(obj, pbf) { + if (obj.key) pbf.writeStringField(1, obj.key); + if (obj.value) pbf.writeStringField(2, obj.value); +} + +export function readEnvelope_FieldEntry2(pbf, end) { + return pbf.readFields(readEnvelope_FieldEntry2Field, {key: "", value: 0}, end); +} +function readEnvelope_FieldEntry2Field(tag, obj, pbf) { + if (tag === 1) obj.key = pbf.readString(); + else if (tag === 2) obj.value = pbf.readVarint(true); +} +export function writeEnvelope_FieldEntry2(obj, pbf) { + if (obj.key) pbf.writeStringField(1, obj.key); + if (obj.value) pbf.writeVarintField(2, obj.value); +} diff --git a/test/fixtures/oneof.js b/test/fixtures/oneof.js new file mode 100644 index 0000000..ffc218e --- /dev/null +++ b/test/fixtures/oneof.js @@ -0,0 +1,16 @@ + +export function readEnvelope(pbf, end) { + return pbf.readFields(readEnvelopeField, {id: 0, int: 0, value: undefined, float: 0, string: ""}, end); +} +function readEnvelopeField(tag, obj, pbf) { + if (tag === 1) obj.id = pbf.readVarint(true); + else if (tag === 2) { obj.int = pbf.readVarint(true); obj.value = "int"; } + else if (tag === 3) { obj.float = pbf.readFloat(); obj.value = "float"; } + else if (tag === 4) { obj.string = pbf.readString(); obj.value = "string"; } +} +export function writeEnvelope(obj, pbf) { + if (obj.id) pbf.writeVarintField(1, obj.id); + if (obj.int) pbf.writeVarintField(2, obj.int); + if (obj.float) pbf.writeFloatField(3, obj.float); + if (obj.string) pbf.writeStringField(4, obj.string); +} diff --git a/test/fixtures/packed.js b/test/fixtures/packed.js new file mode 100644 index 0000000..6780737 --- /dev/null +++ b/test/fixtures/packed.js @@ -0,0 +1,36 @@ + +export function readNotPacked(pbf, end) { + return pbf.readFields(readNotPackedField, {value: [], types: []}, end); +} +function readNotPackedField(tag, obj, pbf) { + if (tag === 1) pbf.readPackedVarint(obj.value, true); + else if (tag === 2) pbf.readPackedVarint(obj.types, true); +} +export function writeNotPacked(obj, pbf) { + if (obj.value) for (const item of obj.value) pbf.writeVarintField(1, item); + if (obj.types) for (const item of obj.types) pbf.writeVarintField(2, item); +} + +export function readFalsePacked(pbf, end) { + return pbf.readFields(readFalsePackedField, {value: [], types: []}, end); +} +function readFalsePackedField(tag, obj, pbf) { + if (tag === 1) pbf.readPackedVarint(obj.value, true); + else if (tag === 2) pbf.readPackedVarint(obj.types, true); +} +export function writeFalsePacked(obj, pbf) { + if (obj.value) for (const item of obj.value) pbf.writeVarintField(1, item); + if (obj.types) for (const item of obj.types) pbf.writeVarintField(2, item); +} + +export function readPacked(pbf, end) { + return pbf.readFields(readPackedField, {value: [], types: []}, end); +} +function readPackedField(tag, obj, pbf) { + if (tag === 1) pbf.readPackedVarint(obj.value, true); + else if (tag === 2) pbf.readPackedVarint(obj.types, true); +} +export function writePacked(obj, pbf) { + if (obj.value) pbf.writePackedVarint(1, obj.value); + if (obj.types) pbf.writePackedVarint(2, obj.types); +} diff --git a/test/fixtures/packed_proto3.js b/test/fixtures/packed_proto3.js new file mode 100644 index 0000000..3584f4d --- /dev/null +++ b/test/fixtures/packed_proto3.js @@ -0,0 +1,39 @@ + +export const MessageType = { + "UNKNOWN": 0, + "GREETING": 1 +}; + +export function readNotPacked(pbf, end) { + return pbf.readFields(readNotPackedField, {value: [], types: []}, end); +} +function readNotPackedField(tag, obj, pbf) { + if (tag === 1) pbf.readPackedVarint(obj.value, true); + else if (tag === 2) pbf.readPackedVarint(obj.types); +} +export function writeNotPacked(obj, pbf) { + if (obj.value) pbf.writePackedVarint(1, obj.value); + if (obj.types) pbf.writePackedVarint(2, obj.types); +} + +export function readFalsePacked(pbf, end) { + return pbf.readFields(readFalsePackedField, {value: [], types: []}, end); +} +function readFalsePackedField(tag, obj, pbf) { + if (tag === 1) pbf.readPackedVarint(obj.value, true); + else if (tag === 2) pbf.readPackedVarint(obj.types); +} +export function writeFalsePacked(obj, pbf) { + if (obj.value) for (const item of obj.value) pbf.writeVarintField(1, item); + if (obj.types) for (const item of obj.types) pbf.writeVarintField(2, item); +} + +export function readPacked(pbf, end) { + return pbf.readFields(readPackedField, {value: []}, end); +} +function readPackedField(tag, obj, pbf) { + if (tag === 16) pbf.readPackedVarint(obj.value, true); +} +export function writePacked(obj, pbf) { + if (obj.value) pbf.writePackedVarint(16, obj.value); +} diff --git a/test/fixtures/type_string.js b/test/fixtures/type_string.js new file mode 100644 index 0000000..9c16b01 --- /dev/null +++ b/test/fixtures/type_string.js @@ -0,0 +1,36 @@ + +export function readTypeString(pbf, end) { + return pbf.readFields(readTypeStringField, {int: "0", long: "0", boolVal: false, float: "0", default_implicit: "0", default_explicit: "42"}, end); +} +function readTypeStringField(tag, obj, pbf) { + if (tag === 1) obj.int = pbf.readVarint(true).toString(); + else if (tag === 2) obj.long = pbf.readVarint(true).toString(); + else if (tag === 3) obj.boolVal = pbf.readBoolean(); + else if (tag === 4) obj.float = pbf.readFloat().toString(); + else if (tag === 5) obj.default_implicit = pbf.readVarint(true).toString(); + else if (tag === 6) obj.default_explicit = pbf.readVarint(true).toString(); +} +export function writeTypeString(obj, pbf) { + if (obj.int != null && obj.int !== "0") pbf.writeVarintField(1, parseInt(obj.int, 10)); + if (obj.long != null && obj.long !== "0") pbf.writeVarintField(2, parseInt(obj.long, 10)); + if (obj.boolVal) pbf.writeBooleanField(3, obj.boolVal); + if (obj.float != null && obj.float !== "0") pbf.writeFloatField(4, parseFloat(obj.float)); + if (obj.default_implicit != null && obj.default_implicit !== "0") pbf.writeVarintField(5, parseInt(obj.default_implicit, 10)); + if (obj.default_explicit != null && obj.default_explicit !== "42") pbf.writeVarintField(6, parseInt(obj.default_explicit, 10)); +} + +export function readTypeNotString(pbf, end) { + return pbf.readFields(readTypeNotStringField, {int: 0, long: 0, boolVal: false, float: 0}, end); +} +function readTypeNotStringField(tag, obj, pbf) { + if (tag === 1) obj.int = pbf.readVarint(true); + else if (tag === 2) obj.long = pbf.readVarint(true); + else if (tag === 3) obj.boolVal = pbf.readBoolean(); + else if (tag === 4) obj.float = pbf.readFloat(); +} +export function writeTypeNotString(obj, pbf) { + if (obj.int) pbf.writeVarintField(1, obj.int); + if (obj.long) pbf.writeVarintField(2, obj.long); + if (obj.boolVal) pbf.writeBooleanField(3, obj.boolVal); + if (obj.float) pbf.writeFloatField(4, obj.float); +} diff --git a/test/fixtures/varint.js b/test/fixtures/varint.js new file mode 100644 index 0000000..7cebe50 --- /dev/null +++ b/test/fixtures/varint.js @@ -0,0 +1,16 @@ + +export function readEnvelope(pbf, end) { + return pbf.readFields(readEnvelopeField, {int: 0, uint: 0, long: 0, ulong: 0}, end); +} +function readEnvelopeField(tag, obj, pbf) { + if (tag === 1) obj.int = pbf.readVarint(true); + else if (tag === 2) obj.uint = pbf.readVarint(); + else if (tag === 3) obj.long = pbf.readVarint(true); + else if (tag === 4) obj.ulong = pbf.readVarint(); +} +export function writeEnvelope(obj, pbf) { + if (obj.int) pbf.writeVarintField(1, obj.int); + if (obj.uint) pbf.writeVarintField(2, obj.uint); + if (obj.long) pbf.writeVarintField(3, obj.long); + if (obj.ulong) pbf.writeVarintField(4, obj.ulong); +} diff --git a/bench/vector_tile.js b/test/fixtures/vector_tile.js similarity index 78% rename from bench/vector_tile.js rename to test/fixtures/vector_tile.js index 63faeb1..5796828 100644 --- a/bench/vector_tile.js +++ b/test/fixtures/vector_tile.js @@ -1,10 +1,9 @@ -// code generated by pbf v3.3.0 export function readTile(pbf, end) { - return pbf.readFields(readTileTag, {layers: []}, end); + return pbf.readFields(readTileField, {layers: []}, end); } -function readTileTag(tag, obj, pbf) { - if (tag === 3) obj.layers.push(readTileLayer(pbf, pbf.readEnd())); +function readTileField(tag, obj, pbf) { + if (tag === 3) obj.layers.push(readTileLayer(pbf, pbf.readVarint() + pbf.pos)); } export function writeTile(obj, pbf) { if (obj.layers) for (const item of obj.layers) pbf.writeMessage(3, writeTileLayer, item); @@ -18,9 +17,9 @@ export const TileGeomType = { }; export function readTileValue(pbf, end) { - return pbf.readFields(readTileValueTag, {string_value: "", float_value: 0, double_value: 0, int_value: 0, uint_value: 0, sint_value: 0, bool_value: false}, end); + return pbf.readFields(readTileValueField, {string_value: "", float_value: 0, double_value: 0, int_value: 0, uint_value: 0, sint_value: 0, bool_value: false}, end); } -function readTileValueTag(tag, obj, pbf) { +function readTileValueField(tag, obj, pbf) { if (tag === 1) obj.string_value = pbf.readString(); else if (tag === 2) obj.float_value = pbf.readFloat(); else if (tag === 3) obj.double_value = pbf.readDouble(); @@ -40,9 +39,9 @@ export function writeTileValue(obj, pbf) { } export function readTileFeature(pbf, end) { - return pbf.readFields(readTileFeatureTag, {id: 0, tags: [], type: 0, geometry: []}, end); + return pbf.readFields(readTileFeatureField, {id: 0, tags: [], type: 0, geometry: []}, end); } -function readTileFeatureTag(tag, obj, pbf) { +function readTileFeatureField(tag, obj, pbf) { if (tag === 1) obj.id = pbf.readVarint(); else if (tag === 2) pbf.readPackedVarint(obj.tags); else if (tag === 3) obj.type = pbf.readVarint(); @@ -56,14 +55,14 @@ export function writeTileFeature(obj, pbf) { } export function readTileLayer(pbf, end) { - return pbf.readFields(readTileLayerTag, {version: 1, name: "", features: [], keys: [], values: [], extent: 4096}, end); + return pbf.readFields(readTileLayerField, {version: 1, name: "", features: [], keys: [], values: [], extent: 4096}, end); } -function readTileLayerTag(tag, obj, pbf) { +function readTileLayerField(tag, obj, pbf) { if (tag === 15) obj.version = pbf.readVarint(); else if (tag === 1) obj.name = pbf.readString(); - else if (tag === 2) obj.features.push(readTileFeature(pbf, pbf.readEnd())); + else if (tag === 2) obj.features.push(readTileFeature(pbf, pbf.readVarint() + pbf.pos)); else if (tag === 3) obj.keys.push(pbf.readString()); - else if (tag === 4) obj.values.push(readTileValue(pbf, pbf.readEnd())); + else if (tag === 4) obj.values.push(readTileValue(pbf, pbf.readVarint() + pbf.pos)); else if (tag === 5) obj.extent = pbf.readVarint(); } export function writeTileLayer(obj, pbf) { diff --git a/bench/vector_tile.proto b/test/fixtures/vector_tile.proto similarity index 100% rename from bench/vector_tile.proto rename to test/fixtures/vector_tile.proto