Skip to content

Commit e789367

Browse files
committed
Take special care of oneofs when encoding (i.e. when explicitly set to defaults), see #542
1 parent aff21a7 commit e789367

File tree

8 files changed

+138
-23
lines changed

8 files changed

+138
-23
lines changed

dist/protobuf.js

Lines changed: 58 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.min.js

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.min.js.gz

135 Bytes
Binary file not shown.

dist/protobuf.min.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/encode.js

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ function encode(message, writer) {
6969
// Non-repeated
7070
} else {
7171
var value = message[field.name];
72-
if (field.required || value !== undefined && field.long ? util.longNeq(value, field.defaultValue) : value !== field.defaultValue) {
72+
if (
73+
field.partOf && message[field.partOf.name] === field.name
74+
||
75+
(field.required || value !== undefined) && (field.long ? util.longNeq(value, field.defaultValue) : value !== field.defaultValue)
76+
) {
7377
if (wireType !== undefined)
7478
writer.tag(field.id, wireType)[type](value);
7579
else {
@@ -97,6 +101,7 @@ function encode(message, writer) {
97101
encode.generate = function generate(mtype) {
98102
/* eslint-disable no-unexpected-multiline */
99103
var fields = mtype.getFieldsArray();
104+
var oneofs = mtype.getOneofsArray();
100105
var gen = util.codegen("m", "w")
101106
("w||(w=Writer.create())");
102107

@@ -156,7 +161,7 @@ encode.generate = function generate(mtype) {
156161
}
157162

158163
// Non-repeated
159-
} else {
164+
} else if (!field.partOf) {
160165
if (!field.required) {
161166

162167
if (field.long) gen
@@ -180,6 +185,38 @@ encode.generate = function generate(mtype) {
180185

181186
}
182187
}
188+
for (var i = 0; i < oneofs.length; ++i) { gen
189+
var oneof = oneofs[i],
190+
prop = util.safeProp(oneof.name);
191+
gen
192+
("switch(m%s){", prop);
193+
var oneofFields = oneof.getFieldsArray();
194+
for (var j = 0; j < oneofFields.length; ++j) {
195+
var field = oneofFields[j],
196+
type = field.resolvedType instanceof Enum ? "uint32" : field.type,
197+
wireType = types.basic[type],
198+
prop = util.safeProp(field.name);
199+
gen
200+
("case%j:", field.name);
201+
202+
if (wireType !== undefined) gen
203+
204+
("w.tag(%d,%d).%s(m%s)", field.id, wireType, type, prop);
205+
206+
else if (field.required) gen
207+
208+
("types[%d].encode(m%s,w.tag(%d,2).fork()).ldelim()", fields.indexOf(field), prop, field.id);
209+
210+
else gen
211+
212+
("types[%d].encode(m%s,w.fork()).len&&w.ldelim(%d)||w.reset()", fields.indexOf(field), prop, field.id);
213+
gen
214+
("break;");
215+
216+
} gen
217+
("}");
218+
}
219+
183220
return gen
184221
("return w");
185222
/* eslint-enable no-unexpected-multiline */

src/oneof.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,21 @@ function OneOf(name, fieldNames, options) {
4545
* @type {Field[]}
4646
* @private
4747
*/
48-
this._fields = [];
48+
this._fieldsArray = [];
4949
}
5050

51+
/**
52+
* Fields that belong to this oneof as an array for iteration.
53+
* @name OneOf#fieldsArray
54+
* @type {Field[]}
55+
* @readonly
56+
*/
57+
util.prop(OneOfPrototype, "fieldsArray", {
58+
get: function getFieldsArray() {
59+
return this._fieldsArray;
60+
}
61+
});
62+
5163
/**
5264
* Tests if the specified JSON object describes a oneof.
5365
* @param {*} json JSON object
@@ -87,7 +99,7 @@ OneOfPrototype.toJSON = function toJSON() {
8799
*/
88100
function addFieldsToParent(oneof) {
89101
if (oneof.parent)
90-
oneof._fields.forEach(function(field) {
102+
oneof._fieldsArray.forEach(function(field) {
91103
if (!field.parent)
92104
oneof.parent.add(field);
93105
});
@@ -104,7 +116,7 @@ OneOfPrototype.add = function add(field) {
104116
if (field.parent)
105117
field.parent.remove(field);
106118
this.oneof.push(field.name);
107-
this._fields.push(field);
119+
this._fieldsArray.push(field);
108120
field.partOf = this; // field.parent remains null
109121
addFieldsToParent(this);
110122
return this;
@@ -118,10 +130,10 @@ OneOfPrototype.add = function add(field) {
118130
OneOfPrototype.remove = function remove(field) {
119131
if (!(field instanceof Field))
120132
throw _TypeError("field", "a Field");
121-
var index = this._fields.indexOf(field);
133+
var index = this._fieldsArray.indexOf(field);
122134
if (index < 0)
123135
throw Error(field + " is not a member of " + this);
124-
this._fields.splice(index, 1);
136+
this._fieldsArray.splice(index, 1);
125137
index = this.oneof.indexOf(field.name);
126138
if (index > -1)
127139
this.oneof.splice(index, 1);
@@ -143,7 +155,7 @@ OneOfPrototype.onAdd = function onAdd(parent) {
143155
* @override
144156
*/
145157
OneOfPrototype.onRemove = function onRemove(parent) {
146-
this._fields.forEach(function(field) {
158+
this._fieldsArray.forEach(function(field) {
147159
if (field.parent)
148160
field.parent.remove(field);
149161
});

tests/oneof.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,24 @@ tape.test("oneofs", function(test) {
2727
test.notOk(message.hasOwnProperty('num'), "should delete the previous value");
2828
test.equal(message.str, "a", "should set the new value");
2929
test.equal(message.kind, "str", "should reference the new value");
30-
30+
31+
message.num = 0; // default
32+
message.setKind('num');
33+
test.notOk(message.hasOwnProperty('str'), "should delete the previous value");
34+
test.equal(message.num, 0, "should set the new value");
35+
test.equal(message.kind, "num", "should reference the new value");
36+
test.equal(message.hasOwnProperty("num"), true, "should have the new value on the instance, not just the prototype");
37+
38+
var buf = Message.encode(message).finish();
39+
test.equal(buf.length, 2, "should write a total of 2 bytes");
40+
test.equal(buf[0], 16, "should write id 1, wireType 0");
41+
test.equal(buf[1], 0, "should write a value of 0");
42+
43+
buf = protobuf.encode.call(Message, message).finish();
44+
test.equal(buf.length, 2, "should write a total of 2 bytes (fallback)");
45+
test.equal(buf[0], 16, "should write id 1, wireType 0 (fallback)");
46+
test.equal(buf[1], 0, "should write a value of 0 (fallback)");
47+
3148
test.end();
3249
});
3350

0 commit comments

Comments
 (0)