Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / node_modules / protobufjs / src / ProtoBuf / Reflect / Message / Field.js
1 /**\r
2  * Constructs a new Message Field.\r
3  * @exports ProtoBuf.Reflect.Message.Field\r
4  * @param {!ProtoBuf.Builder} builder Builder reference\r
5  * @param {!ProtoBuf.Reflect.Message} message Message reference\r
6  * @param {string} rule Rule, one of requried, optional, repeated\r
7  * @param {string?} keytype Key data type, if any.\r
8  * @param {string} type Data type, e.g. int32\r
9  * @param {string} name Field name\r
10  * @param {number} id Unique field id\r
11  * @param {Object.<string,*>=} options Options\r
12  * @param {!ProtoBuf.Reflect.Message.OneOf=} oneof Enclosing OneOf\r
13  * @param {string?} syntax The syntax level of this definition (e.g., proto3)\r
14  * @constructor\r
15  * @extends ProtoBuf.Reflect.T\r
16  */\r
17 var Field = function(builder, message, rule, keytype, type, name, id, options, oneof, syntax) {\r
18     T.call(this, builder, message, name);\r
19 \r
20     /**\r
21      * @override\r
22      */\r
23     this.className = "Message.Field";\r
24 \r
25     /**\r
26      * Message field required flag.\r
27      * @type {boolean}\r
28      * @expose\r
29      */\r
30     this.required = rule === "required";\r
31 \r
32     /**\r
33      * Message field repeated flag.\r
34      * @type {boolean}\r
35      * @expose\r
36      */\r
37     this.repeated = rule === "repeated";\r
38 \r
39     /**\r
40      * Message field map flag.\r
41      * @type {boolean}\r
42      * @expose\r
43      */\r
44     this.map = rule === "map";\r
45 \r
46     /**\r
47      * Message field key type. Type reference string if unresolved, protobuf\r
48      * type if resolved. Valid only if this.map === true, null otherwise.\r
49      * @type {string|{name: string, wireType: number}|null}\r
50      * @expose\r
51      */\r
52     this.keyType = keytype || null;\r
53 \r
54     /**\r
55      * Message field type. Type reference string if unresolved, protobuf type if\r
56      * resolved. In a map field, this is the value type.\r
57      * @type {string|{name: string, wireType: number}}\r
58      * @expose\r
59      */\r
60     this.type = type;\r
61 \r
62     /**\r
63      * Resolved type reference inside the global namespace.\r
64      * @type {ProtoBuf.Reflect.T|null}\r
65      * @expose\r
66      */\r
67     this.resolvedType = null;\r
68 \r
69     /**\r
70      * Unique message field id.\r
71      * @type {number}\r
72      * @expose\r
73      */\r
74     this.id = id;\r
75 \r
76     /**\r
77      * Message field options.\r
78      * @type {!Object.<string,*>}\r
79      * @dict\r
80      * @expose\r
81      */\r
82     this.options = options || {};\r
83 \r
84     /**\r
85      * Default value.\r
86      * @type {*}\r
87      * @expose\r
88      */\r
89     this.defaultValue = null;\r
90 \r
91     /**\r
92      * Enclosing OneOf.\r
93      * @type {?ProtoBuf.Reflect.Message.OneOf}\r
94      * @expose\r
95      */\r
96     this.oneof = oneof || null;\r
97 \r
98     /**\r
99      * Syntax level of this definition (e.g., proto3).\r
100      * @type {string}\r
101      * @expose\r
102      */\r
103     this.syntax = syntax || 'proto2';\r
104 \r
105     /**\r
106      * Original field name.\r
107      * @type {string}\r
108      * @expose\r
109      */\r
110     this.originalName = this.name; // Used to revert camelcase transformation on naming collisions\r
111 \r
112     /**\r
113      * Element implementation. Created in build() after types are resolved.\r
114      * @type {ProtoBuf.Element}\r
115      * @expose\r
116      */\r
117     this.element = null;\r
118 \r
119     /**\r
120      * Key element implementation, for map fields. Created in build() after\r
121      * types are resolved.\r
122      * @type {ProtoBuf.Element}\r
123      * @expose\r
124      */\r
125     this.keyElement = null;\r
126 \r
127     // Convert field names to camel case notation if the override is set\r
128     if (this.builder.options['convertFieldsToCamelCase'] && !(this instanceof Message.ExtensionField))\r
129         this.name = ProtoBuf.Util.toCamelCase(this.name);\r
130 };\r
131 \r
132 /**\r
133  * @alias ProtoBuf.Reflect.Message.Field.prototype\r
134  * @inner\r
135  */\r
136 var FieldPrototype = Field.prototype = Object.create(T.prototype);\r
137 \r
138 /**\r
139  * Builds the field.\r
140  * @override\r
141  * @expose\r
142  */\r
143 FieldPrototype.build = function() {\r
144     this.element = new Element(this.type, this.resolvedType, false, this.syntax, this.name);\r
145     if (this.map)\r
146         this.keyElement = new Element(this.keyType, undefined, true, this.syntax, this.name);\r
147 \r
148     // In proto3, fields do not have field presence, and every field is set to\r
149     // its type's default value ("", 0, 0.0, or false).\r
150     if (this.syntax === 'proto3' && !this.repeated && !this.map)\r
151         this.defaultValue = Element.defaultFieldValue(this.type);\r
152 \r
153     // Otherwise, default values are present when explicitly specified\r
154     else if (typeof this.options['default'] !== 'undefined')\r
155         this.defaultValue = this.verifyValue(this.options['default']);\r
156 };\r
157 \r
158 /**\r
159  * Checks if the given value can be set for this field.\r
160  * @param {*} value Value to check\r
161  * @param {boolean=} skipRepeated Whether to skip the repeated value check or not. Defaults to false.\r
162  * @return {*} Verified, maybe adjusted, value\r
163  * @throws {Error} If the value cannot be set for this field\r
164  * @expose\r
165  */\r
166 FieldPrototype.verifyValue = function(value, skipRepeated) {\r
167     skipRepeated = skipRepeated || false;\r
168     var self = this;\r
169     function fail(val, msg) {\r
170         throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")");\r
171     }\r
172     if (value === null) { // NULL values for optional fields\r
173         if (this.required)\r
174             fail(typeof value, "required");\r
175         if (this.syntax === 'proto3' && this.type !== ProtoBuf.TYPES["message"])\r
176             fail(typeof value, "proto3 field without field presence cannot be null");\r
177         return null;\r
178     }\r
179     var i;\r
180     if (this.repeated && !skipRepeated) { // Repeated values as arrays\r
181         if (!Array.isArray(value))\r
182             value = [value];\r
183         var res = [];\r
184         for (i=0; i<value.length; i++)\r
185             res.push(this.element.verifyValue(value[i]));\r
186         return res;\r
187     }\r
188     if (this.map && !skipRepeated) { // Map values as objects\r
189         if (!(value instanceof ProtoBuf.Map)) {\r
190             // If not already a Map, attempt to convert.\r
191             if (!(value instanceof Object)) {\r
192                 fail(typeof value,\r
193                      "expected ProtoBuf.Map or raw object for map field");\r
194             }\r
195             return new ProtoBuf.Map(this, value);\r
196         } else {\r
197             return value;\r
198         }\r
199     }\r
200     // All non-repeated fields expect no array\r
201     if (!this.repeated && Array.isArray(value))\r
202         fail(typeof value, "no array expected");\r
203 \r
204     return this.element.verifyValue(value);\r
205 };\r
206 \r
207 /**\r
208  * Determines whether the field will have a presence on the wire given its\r
209  * value.\r
210  * @param {*} value Verified field value\r
211  * @param {!ProtoBuf.Builder.Message} message Runtime message\r
212  * @return {boolean} Whether the field will be present on the wire\r
213  */\r
214 FieldPrototype.hasWirePresence = function(value, message) {\r
215     if (this.syntax !== 'proto3')\r
216         return (value !== null);\r
217     if (this.oneof && message[this.oneof.name] === this.name)\r
218         return true;\r
219     switch (this.type) {\r
220         case ProtoBuf.TYPES["int32"]:\r
221         case ProtoBuf.TYPES["sint32"]:\r
222         case ProtoBuf.TYPES["sfixed32"]:\r
223         case ProtoBuf.TYPES["uint32"]:\r
224         case ProtoBuf.TYPES["fixed32"]:\r
225             return value !== 0;\r
226 \r
227         case ProtoBuf.TYPES["int64"]:\r
228         case ProtoBuf.TYPES["sint64"]:\r
229         case ProtoBuf.TYPES["sfixed64"]:\r
230         case ProtoBuf.TYPES["uint64"]:\r
231         case ProtoBuf.TYPES["fixed64"]:\r
232             return value.low !== 0 || value.high !== 0;\r
233 \r
234         case ProtoBuf.TYPES["bool"]:\r
235             return value;\r
236 \r
237         case ProtoBuf.TYPES["float"]:\r
238         case ProtoBuf.TYPES["double"]:\r
239             return value !== 0.0;\r
240 \r
241         case ProtoBuf.TYPES["string"]:\r
242             return value.length > 0;\r
243 \r
244         case ProtoBuf.TYPES["bytes"]:\r
245             return value.remaining() > 0;\r
246 \r
247         case ProtoBuf.TYPES["enum"]:\r
248             return value !== 0;\r
249 \r
250         case ProtoBuf.TYPES["message"]:\r
251             return value !== null;\r
252         default:\r
253             return true;\r
254     }\r
255 };\r
256 \r
257 /**\r
258  * Encodes the specified field value to the specified buffer.\r
259  * @param {*} value Verified field value\r
260  * @param {ByteBuffer} buffer ByteBuffer to encode to\r
261  * @param {!ProtoBuf.Builder.Message} message Runtime message\r
262  * @return {ByteBuffer} The ByteBuffer for chaining\r
263  * @throws {Error} If the field cannot be encoded\r
264  * @expose\r
265  */\r
266 FieldPrototype.encode = function(value, buffer, message) {\r
267     if (this.type === null || typeof this.type !== 'object')\r
268         throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type);\r
269     if (value === null || (this.repeated && value.length == 0))\r
270         return buffer; // Optional omitted\r
271     try {\r
272         if (this.repeated) {\r
273             var i;\r
274             // "Only repeated fields of primitive numeric types (types which use the varint, 32-bit, or 64-bit wire\r
275             // types) can be declared 'packed'."\r
276             if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {\r
277                 // "All of the elements of the field are packed into a single key-value pair with wire type 2\r
278                 // (length-delimited). Each element is encoded the same way it would be normally, except without a\r
279                 // tag preceding it."\r
280                 buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);\r
281                 buffer.ensureCapacity(buffer.offset += 1); // We do not know the length yet, so let's assume a varint of length 1\r
282                 var start = buffer.offset; // Remember where the contents begin\r
283                 for (i=0; i<value.length; i++)\r
284                     this.element.encodeValue(this.id, value[i], buffer);\r
285                 var len = buffer.offset-start,\r
286                     varintLen = ByteBuffer.calculateVarint32(len);\r
287                 if (varintLen > 1) { // We need to move the contents\r
288                     var contents = buffer.slice(start, buffer.offset);\r
289                     start += varintLen-1;\r
290                     buffer.offset = start;\r
291                     buffer.append(contents);\r
292                 }\r
293                 buffer.writeVarint32(len, start-varintLen);\r
294             } else {\r
295                 // "If your message definition has repeated elements (without the [packed=true] option), the encoded\r
296                 // message has zero or more key-value pairs with the same tag number"\r
297                 for (i=0; i<value.length; i++)\r
298                     buffer.writeVarint32((this.id << 3) | this.type.wireType),\r
299                     this.element.encodeValue(this.id, value[i], buffer);\r
300             }\r
301         } else if (this.map) {\r
302             // Write out each map entry as a submessage.\r
303             value.forEach(function(val, key, m) {\r
304                 // Compute the length of the submessage (key, val) pair.\r
305                 var length =\r
306                     ByteBuffer.calculateVarint32((1 << 3) | this.keyType.wireType) +\r
307                     this.keyElement.calculateLength(1, key) +\r
308                     ByteBuffer.calculateVarint32((2 << 3) | this.type.wireType) +\r
309                     this.element.calculateLength(2, val);\r
310 \r
311                 // Submessage with wire type of length-delimited.\r
312                 buffer.writeVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);\r
313                 buffer.writeVarint32(length);\r
314 \r
315                 // Write out the key and val.\r
316                 buffer.writeVarint32((1 << 3) | this.keyType.wireType);\r
317                 this.keyElement.encodeValue(1, key, buffer);\r
318                 buffer.writeVarint32((2 << 3) | this.type.wireType);\r
319                 this.element.encodeValue(2, val, buffer);\r
320             }, this);\r
321         } else {\r
322             if (this.hasWirePresence(value, message)) {\r
323                 buffer.writeVarint32((this.id << 3) | this.type.wireType);\r
324                 this.element.encodeValue(this.id, value, buffer);\r
325             }\r
326         }\r
327     } catch (e) {\r
328         throw Error("Illegal value for "+this.toString(true)+": "+value+" ("+e+")");\r
329     }\r
330     return buffer;\r
331 };\r
332 \r
333 /**\r
334  * Calculates the length of this field's value on the network level.\r
335  * @param {*} value Field value\r
336  * @param {!ProtoBuf.Builder.Message} message Runtime message\r
337  * @returns {number} Byte length\r
338  * @expose\r
339  */\r
340 FieldPrototype.calculate = function(value, message) {\r
341     value = this.verifyValue(value); // May throw\r
342     if (this.type === null || typeof this.type !== 'object')\r
343         throw Error("[INTERNAL] Unresolved type in "+this.toString(true)+": "+this.type);\r
344     if (value === null || (this.repeated && value.length == 0))\r
345         return 0; // Optional omitted\r
346     var n = 0;\r
347     try {\r
348         if (this.repeated) {\r
349             var i, ni;\r
350             if (this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {\r
351                 n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);\r
352                 ni = 0;\r
353                 for (i=0; i<value.length; i++)\r
354                     ni += this.element.calculateLength(this.id, value[i]);\r
355                 n += ByteBuffer.calculateVarint32(ni);\r
356                 n += ni;\r
357             } else {\r
358                 for (i=0; i<value.length; i++)\r
359                     n += ByteBuffer.calculateVarint32((this.id << 3) | this.type.wireType),\r
360                     n += this.element.calculateLength(this.id, value[i]);\r
361             }\r
362         } else if (this.map) {\r
363             // Each map entry becomes a submessage.\r
364             value.forEach(function(val, key, m) {\r
365                 // Compute the length of the submessage (key, val) pair.\r
366                 var length =\r
367                     ByteBuffer.calculateVarint32((1 << 3) | this.keyType.wireType) +\r
368                     this.keyElement.calculateLength(1, key) +\r
369                     ByteBuffer.calculateVarint32((2 << 3) | this.type.wireType) +\r
370                     this.element.calculateLength(2, val);\r
371 \r
372                 n += ByteBuffer.calculateVarint32((this.id << 3) | ProtoBuf.WIRE_TYPES.LDELIM);\r
373                 n += ByteBuffer.calculateVarint32(length);\r
374                 n += length;\r
375             }, this);\r
376         } else {\r
377             if (this.hasWirePresence(value, message)) {\r
378                 n += ByteBuffer.calculateVarint32((this.id << 3) | this.type.wireType);\r
379                 n += this.element.calculateLength(this.id, value);\r
380             }\r
381         }\r
382     } catch (e) {\r
383         throw Error("Illegal value for "+this.toString(true)+": "+value+" ("+e+")");\r
384     }\r
385     return n;\r
386 };\r
387 \r
388 /**\r
389  * Decode the field value from the specified buffer.\r
390  * @param {number} wireType Leading wire type\r
391  * @param {ByteBuffer} buffer ByteBuffer to decode from\r
392  * @param {boolean=} skipRepeated Whether to skip the repeated check or not. Defaults to false.\r
393  * @return {*} Decoded value: array for packed repeated fields, [key, value] for\r
394  *             map fields, or an individual value otherwise.\r
395  * @throws {Error} If the field cannot be decoded\r
396  * @expose\r
397  */\r
398 FieldPrototype.decode = function(wireType, buffer, skipRepeated) {\r
399     var value, nBytes;\r
400 \r
401     // We expect wireType to match the underlying type's wireType unless we see\r
402     // a packed repeated field, or unless this is a map field.\r
403     var wireTypeOK =\r
404         (!this.map && wireType == this.type.wireType) ||\r
405         (!skipRepeated && this.repeated && this.options["packed"] &&\r
406          wireType == ProtoBuf.WIRE_TYPES.LDELIM) ||\r
407         (this.map && wireType == ProtoBuf.WIRE_TYPES.LDELIM);\r
408     if (!wireTypeOK)\r
409         throw Error("Illegal wire type for field "+this.toString(true)+": "+wireType+" ("+this.type.wireType+" expected)");\r
410 \r
411     // Handle packed repeated fields.\r
412     if (wireType == ProtoBuf.WIRE_TYPES.LDELIM && this.repeated && this.options["packed"] && ProtoBuf.PACKABLE_WIRE_TYPES.indexOf(this.type.wireType) >= 0) {\r
413         if (!skipRepeated) {\r
414             nBytes = buffer.readVarint32();\r
415             nBytes = buffer.offset + nBytes; // Limit\r
416             var values = [];\r
417             while (buffer.offset < nBytes)\r
418                 values.push(this.decode(this.type.wireType, buffer, true));\r
419             return values;\r
420         }\r
421         // Read the next value otherwise...\r
422     }\r
423 \r
424     // Handle maps.\r
425     if (this.map) {\r
426         // Read one (key, value) submessage, and return [key, value]\r
427         var key = Element.defaultFieldValue(this.keyType);\r
428         value = Element.defaultFieldValue(this.type);\r
429 \r
430         // Read the length\r
431         nBytes = buffer.readVarint32();\r
432         if (buffer.remaining() < nBytes)\r
433             throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining());\r
434 \r
435         // Get a sub-buffer of this key/value submessage\r
436         var msgbuf = buffer.clone();\r
437         msgbuf.limit = msgbuf.offset + nBytes;\r
438         buffer.offset += nBytes;\r
439 \r
440         while (msgbuf.remaining() > 0) {\r
441             var tag = msgbuf.readVarint32();\r
442             wireType = tag & 0x07;\r
443             var id = tag >>> 3;\r
444             if (id === 1) {\r
445                 key = this.keyElement.decode(msgbuf, wireType, id);\r
446             } else if (id === 2) {\r
447                 value = this.element.decode(msgbuf, wireType, id);\r
448             } else {\r
449                 throw Error("Unexpected tag in map field key/value submessage");\r
450             }\r
451         }\r
452 \r
453         return [key, value];\r
454     }\r
455 \r
456     // Handle singular and non-packed repeated field values.\r
457     return this.element.decode(buffer, wireType, this.id);\r
458 };\r