3 * Runtime message from/to plain object converters.
6 var converter = exports;
8 var Enum = require("./enum"),
9 util = require("./util");
12 * Generates a partial value fromObject conveter.
13 * @param {Codegen} gen Codegen instance
14 * @param {Field} field Reflected field
15 * @param {number} fieldIndex Field index
16 * @param {string} prop Property reference
17 * @returns {Codegen} Codegen instance
20 function genValuePartial_fromObject(gen, field, fieldIndex, prop) {
21 /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
22 if (field.resolvedType) {
23 if (field.resolvedType instanceof Enum) { gen
24 ("switch(d%s){", prop);
25 for (var values = field.resolvedType.values, keys = Object.keys(values), i = 0; i < keys.length; ++i) {
26 if (field.repeated && values[keys[i]] === field.typeDefault) gen
30 ("case %i:", values[keys[i]])
31 ("m%s=%j", prop, values[keys[i]])
36 ("if(typeof d%s!==\"object\")", prop)
37 ("throw TypeError(%j)", field.fullName + ": object expected")
38 ("m%s=types[%i].fromObject(d%s)", prop, fieldIndex, prop);
40 var isUnsigned = false;
44 ("m%s=Number(d%s)", prop, prop); // also catches "NaN", "Infinity"
48 ("m%s=d%s>>>0", prop, prop);
53 ("m%s=d%s|0", prop, prop);
57 // eslint-disable-line no-fallthrough
63 ("(m%s=util.Long.fromValue(d%s)).unsigned=%j", prop, prop, isUnsigned)
64 ("else if(typeof d%s===\"string\")", prop)
65 ("m%s=parseInt(d%s,10)", prop, prop)
66 ("else if(typeof d%s===\"number\")", prop)
67 ("m%s=d%s", prop, prop)
68 ("else if(typeof d%s===\"object\")", prop)
69 ("m%s=new util.LongBits(d%s.low>>>0,d%s.high>>>0).toNumber(%s)", prop, prop, prop, isUnsigned ? "true" : "");
72 ("if(typeof d%s===\"string\")", prop)
73 ("util.base64.decode(d%s,m%s=util.newBuffer(util.base64.length(d%s)),0)", prop, prop, prop)
74 ("else if(d%s.length)", prop)
75 ("m%s=d%s", prop, prop);
78 ("m%s=String(d%s)", prop, prop);
81 ("m%s=Boolean(d%s)", prop, prop);
84 ("m%s=d%s", prop, prop);
89 /* eslint-enable no-unexpected-multiline, block-scoped-var, no-redeclare */
93 * Generates a plain object to runtime message converter specific to the specified message type.
94 * @param {Type} mtype Message type
95 * @returns {Codegen} Codegen instance
97 converter.fromObject = function fromObject(mtype) {
98 /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
99 var fields = mtype.fieldsArray;
100 var gen = util.codegen(["d"], mtype.name + "$fromObject")
101 ("if(d instanceof this.ctor)")
103 if (!fields.length) return gen
104 ("return new this.ctor");
106 ("var m=new this.ctor");
107 for (var i = 0; i < fields.length; ++i) {
108 var field = fields[i].resolve(),
109 prop = util.safeProp(field.name);
114 ("if(typeof d%s!==\"object\")", prop)
115 ("throw TypeError(%j)", field.fullName + ": object expected")
117 ("for(var ks=Object.keys(d%s),i=0;i<ks.length;++i){", prop);
118 genValuePartial_fromObject(gen, field, /* not sorted */ i, prop + "[ks[i]]")
123 } else if (field.repeated) { gen
125 ("if(!Array.isArray(d%s))", prop)
126 ("throw TypeError(%j)", field.fullName + ": array expected")
128 ("for(var i=0;i<d%s.length;++i){", prop);
129 genValuePartial_fromObject(gen, field, /* not sorted */ i, prop + "[i]")
133 // Non-repeated fields
135 if (!(field.resolvedType instanceof Enum)) gen // no need to test for null/undefined if an enum (uses switch)
136 ("if(d%s!=null){", prop); // !== undefined && !== null
137 genValuePartial_fromObject(gen, field, /* not sorted */ i, prop);
138 if (!(field.resolvedType instanceof Enum)) gen
143 /* eslint-enable no-unexpected-multiline, block-scoped-var, no-redeclare */
147 * Generates a partial value toObject converter.
148 * @param {Codegen} gen Codegen instance
149 * @param {Field} field Reflected field
150 * @param {number} fieldIndex Field index
151 * @param {string} prop Property reference
152 * @returns {Codegen} Codegen instance
155 function genValuePartial_toObject(gen, field, fieldIndex, prop) {
156 /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
157 if (field.resolvedType) {
158 if (field.resolvedType instanceof Enum) gen
159 ("d%s=o.enums===String?types[%i].values[m%s]:m%s", prop, fieldIndex, prop, prop);
161 ("d%s=types[%i].toObject(m%s,o)", prop, fieldIndex, prop);
163 var isUnsigned = false;
164 switch (field.type) {
167 ("d%s=o.json&&!isFinite(m%s)?String(m%s):m%s", prop, prop, prop, prop);
171 // eslint-disable-line no-fallthrough
176 ("if(typeof m%s===\"number\")", prop)
177 ("d%s=o.longs===String?String(m%s):m%s", prop, prop, prop)
178 ("else") // Long-like
179 ("d%s=o.longs===String?util.Long.prototype.toString.call(m%s):o.longs===Number?new util.LongBits(m%s.low>>>0,m%s.high>>>0).toNumber(%s):m%s", prop, prop, prop, prop, isUnsigned ? "true": "", prop);
182 ("d%s=o.bytes===String?util.base64.encode(m%s,0,m%s.length):o.bytes===Array?Array.prototype.slice.call(m%s):m%s", prop, prop, prop, prop, prop);
185 ("d%s=m%s", prop, prop);
190 /* eslint-enable no-unexpected-multiline, block-scoped-var, no-redeclare */
194 * Generates a runtime message to plain object converter specific to the specified message type.
195 * @param {Type} mtype Message type
196 * @returns {Codegen} Codegen instance
198 converter.toObject = function toObject(mtype) {
199 /* eslint-disable no-unexpected-multiline, block-scoped-var, no-redeclare */
200 var fields = mtype.fieldsArray.slice().sort(util.compareFieldsById);
202 return util.codegen()("return {}");
203 var gen = util.codegen(["m", "o"], mtype.name + "$toObject")
208 var repeatedFields = [],
212 for (; i < fields.length; ++i)
213 if (!fields[i].partOf)
214 ( fields[i].resolve().repeated ? repeatedFields
215 : fields[i].map ? mapFields
216 : normalFields).push(fields[i]);
218 if (repeatedFields.length) { gen
219 ("if(o.arrays||o.defaults){");
220 for (i = 0; i < repeatedFields.length; ++i) gen
221 ("d%s=[]", util.safeProp(repeatedFields[i].name));
226 if (mapFields.length) { gen
227 ("if(o.objects||o.defaults){");
228 for (i = 0; i < mapFields.length; ++i) gen
229 ("d%s={}", util.safeProp(mapFields[i].name));
234 if (normalFields.length) { gen
236 for (i = 0; i < normalFields.length; ++i) {
237 var field = normalFields[i],
238 prop = util.safeProp(field.name);
239 if (field.resolvedType instanceof Enum) gen
240 ("d%s=o.enums===String?%j:%j", prop, field.resolvedType.valuesById[field.typeDefault], field.typeDefault);
241 else if (field.long) gen
243 ("var n=new util.Long(%i,%i,%j)", field.typeDefault.low, field.typeDefault.high, field.typeDefault.unsigned)
244 ("d%s=o.longs===String?n.toString():o.longs===Number?n.toNumber():n", prop)
246 ("d%s=o.longs===String?%j:%i", prop, field.typeDefault.toString(), field.typeDefault.toNumber());
247 else if (field.bytes) {
248 var arrayDefault = "[" + Array.prototype.slice.call(field.typeDefault).join(",") + "]";
250 ("if(o.bytes===String)d%s=%j", prop, String.fromCharCode.apply(String, field.typeDefault))
252 ("d%s=%s", prop, arrayDefault)
253 ("if(o.bytes!==Array)d%s=util.newBuffer(d%s)", prop, prop)
256 ("d%s=%j", prop, field.typeDefault); // also messages (=null)
261 for (i = 0; i < fields.length; ++i) {
262 var field = fields[i],
263 index = mtype._fieldsArray.indexOf(field),
264 prop = util.safeProp(field.name);
266 if (!hasKs2) { hasKs2 = true; gen
269 ("if(m%s&&(ks2=Object.keys(m%s)).length){", prop, prop)
271 ("for(var j=0;j<ks2.length;++j){");
272 genValuePartial_toObject(gen, field, /* sorted */ index, prop + "[ks2[j]]")
274 } else if (field.repeated) { gen
275 ("if(m%s&&m%s.length){", prop, prop)
277 ("for(var j=0;j<m%s.length;++j){", prop);
278 genValuePartial_toObject(gen, field, /* sorted */ index, prop + "[j]")
281 ("if(m%s!=null&&m.hasOwnProperty(%j)){", prop, field.name); // !== undefined && !== null
282 genValuePartial_toObject(gen, field, /* sorted */ index, prop);
283 if (field.partOf) gen
285 ("d%s=%j", util.safeProp(field.partOf.name), field.name);
292 /* eslint-enable no-unexpected-multiline, block-scoped-var, no-redeclare */