Skip to content

Commit baea920

Browse files
committed
Properly encode/decode map kv pairs as repeated messages (codegen and fallback), see #547
1 parent 52cd8b5 commit baea920

10 files changed

+174
-145
lines changed

dist/protobuf.js

+44-68
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.min.js

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/protobuf.min.js.gz

-50 Bytes
Binary file not shown.

dist/protobuf.min.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/decode.js

+25-40
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,18 @@ function decode(readerOrBuffer, length) {
3030

3131
// Map fields
3232
if (field.map) {
33-
var keyType = field.resolvedKeyType /* only valid is enum */ ? "uint32" : field.keyType,
34-
length = reader.uint32();
35-
var map = message[field.name] = {};
36-
if (length) {
37-
length += reader.pos;
38-
var ks = [], vs = [];
39-
while (reader.pos < length) {
40-
if (reader.tag().id === 1)
41-
ks[ks.length] = reader[keyType]();
42-
else if (types.basic[type] !== undefined)
43-
vs[vs.length] = reader[type]();
44-
else
45-
vs[vs.length] = field.resolvedType.decode(reader, reader.uint32());
46-
}
47-
for (var i = 0; i < ks.length; ++i)
48-
map[typeof ks[i] === "object" ? util.longToHash(ks[i]) : ks[i]] = vs[i];
49-
}
33+
var keyType = field.resolvedKeyType /* only valid is enum */ ? "uint32" : field.keyType;
34+
reader.skip();
35+
reader.pos++; // assumes id 1
36+
if (message[field.name] === util.emptyObject)
37+
message[field.name] = {};
38+
var key = reader[keyType]();
39+
if (typeof key === "object")
40+
key = util.longToHash(key);
41+
reader.pos++; // assumes id 2
42+
message[field.name][key] = types.basic[type] === undefined
43+
? field.resolvedType.decode(reader, reader.uint32())
44+
: reader[type]();
5045

5146
// Repeated fields
5247
} else if (field.repeated) {
@@ -105,31 +100,21 @@ decode.generate = function generate(mtype) {
105100
("case %d:", field.id);
106101

107102
if (field.map) {
103+
108104
var keyType = field.resolvedKeyType /* only valid is enum */ ? "uint32" : field.keyType;
109105
gen
110-
("var n=r.uint32(),o={}")
111-
("if(n){")
112-
("n+=r.pos")
113-
("var k=[],v=[]")
114-
("while(r.pos<n){")
115-
("if(r.tag().id===1)")
116-
("k[k.length]=r.%s()", keyType);
117-
118-
if (types.basic[type] !== undefined) gen
119-
120-
("else")
121-
("v[v.length]=r.%s()", type);
122-
123-
else gen
124-
125-
("else")
126-
("v[v.length]=types[%d].decode(r,r.uint32())", i, i);
127-
gen
128-
("}")
129-
("for(var i=0;i<k.length;++i)")
130-
("o[typeof(k[i])===\"object\"?util.longToHash(k[i]):k[i]]=v[i]")
131-
("}")
132-
("m%s=o", prop);
106+
("r.skip()")
107+
("r.pos++")
108+
("if(m%s===util.emptyObject)", prop)
109+
("m%s={}", prop)
110+
("var k=r.%s()", keyType)
111+
("if(typeof k===\"object\")")
112+
("k=util.longToHash(k)")
113+
("r.pos++");
114+
if (types.basic[type] === undefined) gen
115+
("m%s[k]=types[%d].decode(r,r.uint32())", prop, i);
116+
else gen
117+
("m%s[k]=r.%s()", prop, type);
133118

134119
} else if (field.repeated) { gen
135120

src/encode.js

+17-26
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,16 @@ function encode(message, writer) {
2828
// Map fields
2929
if (field.map) {
3030
var keyType = field.resolvedKeyType /* only valid is enum */ ? "uint32" : field.keyType;
31-
var value, keys;
32-
if ((value = message[field.name]) && (keys = Object.keys(value)).length) {
33-
writer.fork();
34-
for (var i = 0; i < keys.length; ++i) {
35-
writer.tag(1, types.mapKey[keyType])[keyType](keys[i]);
36-
if (wireType !== undefined)
37-
writer.tag(2, wireType)[type](value[keys[i]]);
31+
if (message[field.name] && message[field.name] !== util.emptyObject) {
32+
for (var keys = Object.keys(message[field.name]), i = 0; i < keys.length; ++i) {
33+
writer.tag(field.id,2).fork()
34+
.tag(1,types.mapKey[keyType])[keyType](keys[i]);
35+
if (wireType === undefined)
36+
field.resolvedType.encode(message[field.name][keys[i]], writer.tag(2,2).fork()).ldelim();
3837
else
39-
field.resolvedType.encode(value[keys[i]], writer.tag(2,2).fork()).ldelim();
38+
writer.tag(2,wireType)[type](message[field.name][keys[i]]);
39+
writer.ldelim();
4040
}
41-
writer.ldelim(field.id);
4241
}
4342

4443
// Repeated fields
@@ -112,29 +111,21 @@ encode.generate = function generate(mtype) {
112111
type = field.resolvedType instanceof Enum ? "uint32" : field.type,
113112
wireType = types.basic[type],
114113
prop = safeProp(field.name);
115-
114+
116115
// Map fields
117116
if (field.map) {
118-
var keyType = field.resolvedKeyType /* only valid is enum */ ? "uint32" : field.keyType,
119-
keyWireType = types.mapKey[keyType];
117+
var keyType = field.resolvedKeyType /* only valid is enum */ ? "uint32" : field.keyType;
120118
gen
121-
122-
("if(m%s){", prop)
123-
("w.fork()")
124-
("for(var i=0,ks=Object.keys(m%s);i<ks.length;++i){", prop)
125-
("w.tag(1,%d).%s(ks[i])", keyWireType, keyType);
126-
127-
if (wireType !== undefined) gen
128-
129-
("w.tag(2,%d).%s(m%s[ks[i]])", wireType, type, prop);
130-
131-
else gen
132-
119+
("if(m%s&&m%s!==util.emptyObject){", prop, prop)
120+
("for(var ks=Object.keys(m%s),i=0;i<ks.length;++i){", prop)
121+
("w.tag(%d,2).fork().tag(1,%d).%s(ks[i])", field.id, types.mapKey[keyType], keyType);
122+
if (wireType === undefined) gen
133123
("types[%d].encode(m%s[ks[i]],w.tag(2,2).fork()).ldelim()", i, prop);
134-
124+
else gen
125+
("w.tag(2,%d).%s(m%s[ks[i]])", wireType, type, prop);
135126
gen
127+
("w.ldelim()")
136128
("}")
137-
("w.len&&w.ldelim(%d)||w.reset()", field.id)
138129
("}");
139130

140131
// Repeated fields

src/field.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ FieldPrototype.jsonConvert = function(value, options) {
266266
? typeof value === "number"
267267
? value
268268
: util.Long.fromValue(value).toNumber()
269-
: util.Long.fromValue(value, this.type.charAt(0) === "u").toString()
269+
: util.Long.fromValue(value, this.type.charAt(0) === "u").toString();
270270
else if (options.bytes && this.type === "bytes")
271271
return options.bytes === Array
272272
? Array.prototype.slice.call(value)

0 commit comments

Comments
 (0)