Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / node_modules / protobufjs / src / ProtoBuf / Reflect / Element.js
1 /**\r
2  * Constructs a new Element implementation that checks and converts values for a\r
3  * particular field type, as appropriate.\r
4  *\r
5  * An Element represents a single value: either the value of a singular field,\r
6  * or a value contained in one entry of a repeated field or map field. This\r
7  * class does not implement these higher-level concepts; it only encapsulates\r
8  * the low-level typechecking and conversion.\r
9  *\r
10  * @exports ProtoBuf.Reflect.Element\r
11  * @param {{name: string, wireType: number}} type Resolved data type\r
12  * @param {ProtoBuf.Reflect.T|null} resolvedType Resolved type, if relevant\r
13  * (e.g. submessage field).\r
14  * @param {boolean} isMapKey Is this element a Map key? The value will be\r
15  * converted to string form if so.\r
16  * @param {string} syntax Syntax level of defining message type, e.g.,\r
17  * proto2 or proto3.\r
18  * @param {string} name Name of the field containing this element (for error\r
19  * messages)\r
20  * @constructor\r
21  */\r
22 var Element = function(type, resolvedType, isMapKey, syntax, name) {\r
23 \r
24     /**\r
25      * Element type, as a string (e.g., int32).\r
26      * @type {{name: string, wireType: number}}\r
27      */\r
28     this.type = type;\r
29 \r
30     /**\r
31      * Element type reference to submessage or enum definition, if needed.\r
32      * @type {ProtoBuf.Reflect.T|null}\r
33      */\r
34     this.resolvedType = resolvedType;\r
35 \r
36     /**\r
37      * Element is a map key.\r
38      * @type {boolean}\r
39      */\r
40     this.isMapKey = isMapKey;\r
41 \r
42     /**\r
43      * Syntax level of defining message type, e.g., proto2 or proto3.\r
44      * @type {string}\r
45      */\r
46     this.syntax = syntax;\r
47 \r
48     /**\r
49      * Name of the field containing this element (for error messages)\r
50      * @type {string}\r
51      */\r
52     this.name = name;\r
53 \r
54     if (isMapKey && ProtoBuf.MAP_KEY_TYPES.indexOf(type) < 0)\r
55         throw Error("Invalid map key type: " + type.name);\r
56 };\r
57 \r
58 var ElementPrototype = Element.prototype;\r
59 \r
60 /**\r
61  * Obtains a (new) default value for the specified type.\r
62  * @param type {string|{name: string, wireType: number}} Field type\r
63  * @returns {*} Default value\r
64  * @inner\r
65  */\r
66 function mkDefault(type) {\r
67     if (typeof type === 'string')\r
68         type = ProtoBuf.TYPES[type];\r
69     if (typeof type.defaultValue === 'undefined')\r
70         throw Error("default value for type "+type.name+" is not supported");\r
71     if (type == ProtoBuf.TYPES["bytes"])\r
72         return new ByteBuffer(0);\r
73     return type.defaultValue;\r
74 }\r
75 \r
76 /**\r
77  * Returns the default value for this field in proto3.\r
78  * @function\r
79  * @param type {string|{name: string, wireType: number}} the field type\r
80  * @returns {*} Default value\r
81  */\r
82 Element.defaultFieldValue = mkDefault;\r
83 \r
84 /**\r
85  * Makes a Long from a value.\r
86  * @param {{low: number, high: number, unsigned: boolean}|string|number} value Value\r
87  * @param {boolean=} unsigned Whether unsigned or not, defaults to reuse it from Long-like objects or to signed for\r
88  *  strings and numbers\r
89  * @returns {!Long}\r
90  * @throws {Error} If the value cannot be converted to a Long\r
91  * @inner\r
92  */\r
93 function mkLong(value, unsigned) {\r
94     if (value && typeof value.low === 'number' && typeof value.high === 'number' && typeof value.unsigned === 'boolean'\r
95         && value.low === value.low && value.high === value.high)\r
96         return new ProtoBuf.Long(value.low, value.high, typeof unsigned === 'undefined' ? value.unsigned : unsigned);\r
97     if (typeof value === 'string')\r
98         return ProtoBuf.Long.fromString(value, unsigned || false, 10);\r
99     if (typeof value === 'number')\r
100         return ProtoBuf.Long.fromNumber(value, unsigned || false);\r
101     throw Error("not convertible to Long");\r
102 }\r
103 \r
104 ElementPrototype.toString = function() {\r
105     return (this.name || '') + (this.isMapKey ? 'map' : 'value') + ' element';\r
106 }\r
107 \r
108 /**\r
109  * Checks if the given value can be set for an element of this type (singular\r
110  * field or one element of a repeated field or map).\r
111  * @param {*} value Value to check\r
112  * @return {*} Verified, maybe adjusted, value\r
113  * @throws {Error} If the value cannot be verified for this element slot\r
114  * @expose\r
115  */\r
116 ElementPrototype.verifyValue = function(value) {\r
117     var self = this;\r
118     function fail(val, msg) {\r
119         throw Error("Illegal value for "+self.toString(true)+" of type "+self.type.name+": "+val+" ("+msg+")");\r
120     }\r
121     switch (this.type) {\r
122         // Signed 32bit\r
123         case ProtoBuf.TYPES["int32"]:\r
124         case ProtoBuf.TYPES["sint32"]:\r
125         case ProtoBuf.TYPES["sfixed32"]:\r
126             // Account for !NaN: value === value\r
127             if (typeof value !== 'number' || (value === value && value % 1 !== 0))\r
128                 fail(typeof value, "not an integer");\r
129             return value > 4294967295 ? value | 0 : value;\r
130 \r
131         // Unsigned 32bit\r
132         case ProtoBuf.TYPES["uint32"]:\r
133         case ProtoBuf.TYPES["fixed32"]:\r
134             if (typeof value !== 'number' || (value === value && value % 1 !== 0))\r
135                 fail(typeof value, "not an integer");\r
136             return value < 0 ? value >>> 0 : value;\r
137 \r
138         // Signed 64bit\r
139         case ProtoBuf.TYPES["int64"]:\r
140         case ProtoBuf.TYPES["sint64"]:\r
141         case ProtoBuf.TYPES["sfixed64"]: {\r
142             if (ProtoBuf.Long)\r
143                 try {\r
144                     return mkLong(value, false);\r
145                 } catch (e) {\r
146                     fail(typeof value, e.message);\r
147                 }\r
148             else\r
149                 fail(typeof value, "requires Long.js");\r
150         }\r
151 \r
152         // Unsigned 64bit\r
153         case ProtoBuf.TYPES["uint64"]:\r
154         case ProtoBuf.TYPES["fixed64"]: {\r
155             if (ProtoBuf.Long)\r
156                 try {\r
157                     return mkLong(value, true);\r
158                 } catch (e) {\r
159                     fail(typeof value, e.message);\r
160                 }\r
161             else\r
162                 fail(typeof value, "requires Long.js");\r
163         }\r
164 \r
165         // Bool\r
166         case ProtoBuf.TYPES["bool"]:\r
167             if (typeof value !== 'boolean')\r
168                 fail(typeof value, "not a boolean");\r
169             return value;\r
170 \r
171         // Float\r
172         case ProtoBuf.TYPES["float"]:\r
173         case ProtoBuf.TYPES["double"]:\r
174             if (typeof value !== 'number')\r
175                 fail(typeof value, "not a number");\r
176             return value;\r
177 \r
178         // Length-delimited string\r
179         case ProtoBuf.TYPES["string"]:\r
180             if (typeof value !== 'string' && !(value && value instanceof String))\r
181                 fail(typeof value, "not a string");\r
182             return ""+value; // Convert String object to string\r
183 \r
184         // Length-delimited bytes\r
185         case ProtoBuf.TYPES["bytes"]:\r
186             if (ByteBuffer.isByteBuffer(value))\r
187                 return value;\r
188             return ByteBuffer.wrap(value, "base64");\r
189 \r
190         // Constant enum value\r
191         case ProtoBuf.TYPES["enum"]: {\r
192             var values = this.resolvedType.getChildren(ProtoBuf.Reflect.Enum.Value);\r
193             for (i=0; i<values.length; i++)\r
194                 if (values[i].name == value)\r
195                     return values[i].id;\r
196                 else if (values[i].id == value)\r
197                     return values[i].id;\r
198 \r
199             if (this.syntax === 'proto3') {\r
200                 // proto3: just make sure it's an integer.\r
201                 if (typeof value !== 'number' || (value === value && value % 1 !== 0))\r
202                     fail(typeof value, "not an integer");\r
203                 if (value > 4294967295 || value < 0)\r
204                     fail(typeof value, "not in range for uint32")\r
205                 return value;\r
206             } else {\r
207                 // proto2 requires enum values to be valid.\r
208                 fail(value, "not a valid enum value");\r
209             }\r
210         }\r
211         // Embedded message\r
212         case ProtoBuf.TYPES["group"]:\r
213         case ProtoBuf.TYPES["message"]: {\r
214             if (!value || typeof value !== 'object')\r
215                 fail(typeof value, "object expected");\r
216             if (value instanceof this.resolvedType.clazz)\r
217                 return value;\r
218             if (value instanceof ProtoBuf.Builder.Message) {\r
219                 // Mismatched type: Convert to object (see: https://github.com/dcodeIO/ProtoBuf.js/issues/180)\r
220                 var obj = {};\r
221                 for (var i in value)\r
222                     if (value.hasOwnProperty(i))\r
223                         obj[i] = value[i];\r
224                 value = obj;\r
225             }\r
226             // Else let's try to construct one from a key-value object\r
227             return new (this.resolvedType.clazz)(value); // May throw for a hundred of reasons\r
228         }\r
229     }\r
230 \r
231     // We should never end here\r
232     throw Error("[INTERNAL] Illegal value for "+this.toString(true)+": "+value+" (undefined type "+this.type+")");\r
233 };\r
234 \r
235 /**\r
236  * Calculates the byte length of an element on the wire.\r
237  * @param {number} id Field number\r
238  * @param {*} value Field value\r
239  * @returns {number} Byte length\r
240  * @throws {Error} If the value cannot be calculated\r
241  * @expose\r
242  */\r
243 ElementPrototype.calculateLength = function(id, value) {\r
244     if (value === null) return 0; // Nothing to encode\r
245     // Tag has already been written\r
246     var n;\r
247     switch (this.type) {\r
248         case ProtoBuf.TYPES["int32"]:\r
249             return value < 0 ? ByteBuffer.calculateVarint64(value) : ByteBuffer.calculateVarint32(value);\r
250         case ProtoBuf.TYPES["uint32"]:\r
251             return ByteBuffer.calculateVarint32(value);\r
252         case ProtoBuf.TYPES["sint32"]:\r
253             return ByteBuffer.calculateVarint32(ByteBuffer.zigZagEncode32(value));\r
254         case ProtoBuf.TYPES["fixed32"]:\r
255         case ProtoBuf.TYPES["sfixed32"]:\r
256         case ProtoBuf.TYPES["float"]:\r
257             return 4;\r
258         case ProtoBuf.TYPES["int64"]:\r
259         case ProtoBuf.TYPES["uint64"]:\r
260             return ByteBuffer.calculateVarint64(value);\r
261         case ProtoBuf.TYPES["sint64"]:\r
262             return ByteBuffer.calculateVarint64(ByteBuffer.zigZagEncode64(value));\r
263         case ProtoBuf.TYPES["fixed64"]:\r
264         case ProtoBuf.TYPES["sfixed64"]:\r
265             return 8;\r
266         case ProtoBuf.TYPES["bool"]:\r
267             return 1;\r
268         case ProtoBuf.TYPES["enum"]:\r
269             return ByteBuffer.calculateVarint32(value);\r
270         case ProtoBuf.TYPES["double"]:\r
271             return 8;\r
272         case ProtoBuf.TYPES["string"]:\r
273             n = ByteBuffer.calculateUTF8Bytes(value);\r
274             return ByteBuffer.calculateVarint32(n) + n;\r
275         case ProtoBuf.TYPES["bytes"]:\r
276             if (value.remaining() < 0)\r
277                 throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining");\r
278             return ByteBuffer.calculateVarint32(value.remaining()) + value.remaining();\r
279         case ProtoBuf.TYPES["message"]:\r
280             n = this.resolvedType.calculate(value);\r
281             return ByteBuffer.calculateVarint32(n) + n;\r
282         case ProtoBuf.TYPES["group"]:\r
283             n = this.resolvedType.calculate(value);\r
284             return n + ByteBuffer.calculateVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP);\r
285     }\r
286     // We should never end here\r
287     throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)");\r
288 };\r
289 \r
290 /**\r
291  * Encodes a value to the specified buffer. Does not encode the key.\r
292  * @param {number} id Field number\r
293  * @param {*} value Field value\r
294  * @param {ByteBuffer} buffer ByteBuffer to encode to\r
295  * @return {ByteBuffer} The ByteBuffer for chaining\r
296  * @throws {Error} If the value cannot be encoded\r
297  * @expose\r
298  */\r
299 ElementPrototype.encodeValue = function(id, value, buffer) {\r
300     if (value === null) return buffer; // Nothing to encode\r
301     // Tag has already been written\r
302 \r
303     switch (this.type) {\r
304         // 32bit signed varint\r
305         case ProtoBuf.TYPES["int32"]:\r
306             // "If you use int32 or int64 as the type for a negative number, the resulting varint is always ten bytes\r
307             // long â€“ it is, effectively, treated like a very large unsigned integer." (see #122)\r
308             if (value < 0)\r
309                 buffer.writeVarint64(value);\r
310             else\r
311                 buffer.writeVarint32(value);\r
312             break;\r
313 \r
314         // 32bit unsigned varint\r
315         case ProtoBuf.TYPES["uint32"]:\r
316             buffer.writeVarint32(value);\r
317             break;\r
318 \r
319         // 32bit varint zig-zag\r
320         case ProtoBuf.TYPES["sint32"]:\r
321             buffer.writeVarint32ZigZag(value);\r
322             break;\r
323 \r
324         // Fixed unsigned 32bit\r
325         case ProtoBuf.TYPES["fixed32"]:\r
326             buffer.writeUint32(value);\r
327             break;\r
328 \r
329         // Fixed signed 32bit\r
330         case ProtoBuf.TYPES["sfixed32"]:\r
331             buffer.writeInt32(value);\r
332             break;\r
333 \r
334         // 64bit varint as-is\r
335         case ProtoBuf.TYPES["int64"]:\r
336         case ProtoBuf.TYPES["uint64"]:\r
337             buffer.writeVarint64(value); // throws\r
338             break;\r
339 \r
340         // 64bit varint zig-zag\r
341         case ProtoBuf.TYPES["sint64"]:\r
342             buffer.writeVarint64ZigZag(value); // throws\r
343             break;\r
344 \r
345         // Fixed unsigned 64bit\r
346         case ProtoBuf.TYPES["fixed64"]:\r
347             buffer.writeUint64(value); // throws\r
348             break;\r
349 \r
350         // Fixed signed 64bit\r
351         case ProtoBuf.TYPES["sfixed64"]:\r
352             buffer.writeInt64(value); // throws\r
353             break;\r
354 \r
355         // Bool\r
356         case ProtoBuf.TYPES["bool"]:\r
357             if (typeof value === 'string')\r
358                 buffer.writeVarint32(value.toLowerCase() === 'false' ? 0 : !!value);\r
359             else\r
360                 buffer.writeVarint32(value ? 1 : 0);\r
361             break;\r
362 \r
363         // Constant enum value\r
364         case ProtoBuf.TYPES["enum"]:\r
365             buffer.writeVarint32(value);\r
366             break;\r
367 \r
368         // 32bit float\r
369         case ProtoBuf.TYPES["float"]:\r
370             buffer.writeFloat32(value);\r
371             break;\r
372 \r
373         // 64bit float\r
374         case ProtoBuf.TYPES["double"]:\r
375             buffer.writeFloat64(value);\r
376             break;\r
377 \r
378         // Length-delimited string\r
379         case ProtoBuf.TYPES["string"]:\r
380             buffer.writeVString(value);\r
381             break;\r
382 \r
383         // Length-delimited bytes\r
384         case ProtoBuf.TYPES["bytes"]:\r
385             if (value.remaining() < 0)\r
386                 throw Error("Illegal value for "+this.toString(true)+": "+value.remaining()+" bytes remaining");\r
387             var prevOffset = value.offset;\r
388             buffer.writeVarint32(value.remaining());\r
389             buffer.append(value);\r
390             value.offset = prevOffset;\r
391             break;\r
392 \r
393         // Embedded message\r
394         case ProtoBuf.TYPES["message"]:\r
395             var bb = new ByteBuffer().LE();\r
396             this.resolvedType.encode(value, bb);\r
397             buffer.writeVarint32(bb.offset);\r
398             buffer.append(bb.flip());\r
399             break;\r
400 \r
401         // Legacy group\r
402         case ProtoBuf.TYPES["group"]:\r
403             this.resolvedType.encode(value, buffer);\r
404             buffer.writeVarint32((id << 3) | ProtoBuf.WIRE_TYPES.ENDGROUP);\r
405             break;\r
406 \r
407         default:\r
408             // We should never end here\r
409             throw Error("[INTERNAL] Illegal value to encode in "+this.toString(true)+": "+value+" (unknown type)");\r
410     }\r
411     return buffer;\r
412 };\r
413 \r
414 /**\r
415  * Decode one element value from the specified buffer.\r
416  * @param {ByteBuffer} buffer ByteBuffer to decode from\r
417  * @param {number} wireType The field wire type\r
418  * @param {number} id The field number\r
419  * @return {*} Decoded value\r
420  * @throws {Error} If the field cannot be decoded\r
421  * @expose\r
422  */\r
423 ElementPrototype.decode = function(buffer, wireType, id) {\r
424     if (wireType != this.type.wireType)\r
425         throw Error("Unexpected wire type for element");\r
426 \r
427     var value, nBytes;\r
428     switch (this.type) {\r
429         // 32bit signed varint\r
430         case ProtoBuf.TYPES["int32"]:\r
431             return buffer.readVarint32() | 0;\r
432 \r
433         // 32bit unsigned varint\r
434         case ProtoBuf.TYPES["uint32"]:\r
435             return buffer.readVarint32() >>> 0;\r
436 \r
437         // 32bit signed varint zig-zag\r
438         case ProtoBuf.TYPES["sint32"]:\r
439             return buffer.readVarint32ZigZag() | 0;\r
440 \r
441         // Fixed 32bit unsigned\r
442         case ProtoBuf.TYPES["fixed32"]:\r
443             return buffer.readUint32() >>> 0;\r
444 \r
445         case ProtoBuf.TYPES["sfixed32"]:\r
446             return buffer.readInt32() | 0;\r
447 \r
448         // 64bit signed varint\r
449         case ProtoBuf.TYPES["int64"]:\r
450             return buffer.readVarint64();\r
451 \r
452         // 64bit unsigned varint\r
453         case ProtoBuf.TYPES["uint64"]:\r
454             return buffer.readVarint64().toUnsigned();\r
455 \r
456         // 64bit signed varint zig-zag\r
457         case ProtoBuf.TYPES["sint64"]:\r
458             return buffer.readVarint64ZigZag();\r
459 \r
460         // Fixed 64bit unsigned\r
461         case ProtoBuf.TYPES["fixed64"]:\r
462             return buffer.readUint64();\r
463 \r
464         // Fixed 64bit signed\r
465         case ProtoBuf.TYPES["sfixed64"]:\r
466             return buffer.readInt64();\r
467 \r
468         // Bool varint\r
469         case ProtoBuf.TYPES["bool"]:\r
470             return !!buffer.readVarint32();\r
471 \r
472         // Constant enum value (varint)\r
473         case ProtoBuf.TYPES["enum"]:\r
474             // The following Builder.Message#set will already throw\r
475             return buffer.readVarint32();\r
476 \r
477         // 32bit float\r
478         case ProtoBuf.TYPES["float"]:\r
479             return buffer.readFloat();\r
480 \r
481         // 64bit float\r
482         case ProtoBuf.TYPES["double"]:\r
483             return buffer.readDouble();\r
484 \r
485         // Length-delimited string\r
486         case ProtoBuf.TYPES["string"]:\r
487             return buffer.readVString();\r
488 \r
489         // Length-delimited bytes\r
490         case ProtoBuf.TYPES["bytes"]: {\r
491             nBytes = buffer.readVarint32();\r
492             if (buffer.remaining() < nBytes)\r
493                 throw Error("Illegal number of bytes for "+this.toString(true)+": "+nBytes+" required but got only "+buffer.remaining());\r
494             value = buffer.clone(); // Offset already set\r
495             value.limit = value.offset+nBytes;\r
496             buffer.offset += nBytes;\r
497             return value;\r
498         }\r
499 \r
500         // Length-delimited embedded message\r
501         case ProtoBuf.TYPES["message"]: {\r
502             nBytes = buffer.readVarint32();\r
503             return this.resolvedType.decode(buffer, nBytes);\r
504         }\r
505 \r
506         // Legacy group\r
507         case ProtoBuf.TYPES["group"]:\r
508             return this.resolvedType.decode(buffer, -1, id);\r
509     }\r
510 \r
511     // We should never end here\r
512     throw Error("[INTERNAL] Illegal decode type");\r
513 };\r
514 \r
515 /**\r
516  * Converts a value from a string to the canonical element type.\r
517  *\r
518  * Legal only when isMapKey is true.\r
519  *\r
520  * @param {string} str The string value\r
521  * @returns {*} The value\r
522  */\r
523 ElementPrototype.valueFromString = function(str) {\r
524     if (!this.isMapKey) {\r
525         throw Error("valueFromString() called on non-map-key element");\r
526     }\r
527 \r
528     switch (this.type) {\r
529         case ProtoBuf.TYPES["int32"]:\r
530         case ProtoBuf.TYPES["sint32"]:\r
531         case ProtoBuf.TYPES["sfixed32"]:\r
532         case ProtoBuf.TYPES["uint32"]:\r
533         case ProtoBuf.TYPES["fixed32"]:\r
534             return this.verifyValue(parseInt(str));\r
535 \r
536         case ProtoBuf.TYPES["int64"]:\r
537         case ProtoBuf.TYPES["sint64"]:\r
538         case ProtoBuf.TYPES["sfixed64"]:\r
539         case ProtoBuf.TYPES["uint64"]:\r
540         case ProtoBuf.TYPES["fixed64"]:\r
541               // Long-based fields support conversions from string already.\r
542               return this.verifyValue(str);\r
543 \r
544         case ProtoBuf.TYPES["bool"]:\r
545               return str === "true";\r
546 \r
547         case ProtoBuf.TYPES["string"]:\r
548               return this.verifyValue(str);\r
549 \r
550         case ProtoBuf.TYPES["bytes"]:\r
551               return ByteBuffer.fromBinary(str);\r
552     }\r
553 };\r
554 \r
555 /**\r
556  * Converts a value from the canonical element type to a string.\r
557  *\r
558  * It should be the case that `valueFromString(valueToString(val))` returns\r
559  * a value equivalent to `verifyValue(val)` for every legal value of `val`\r
560  * according to this element type.\r
561  *\r
562  * This may be used when the element must be stored or used as a string,\r
563  * e.g., as a map key on an Object.\r
564  *\r
565  * Legal only when isMapKey is true.\r
566  *\r
567  * @param {*} val The value\r
568  * @returns {string} The string form of the value.\r
569  */\r
570 ElementPrototype.valueToString = function(value) {\r
571     if (!this.isMapKey) {\r
572         throw Error("valueToString() called on non-map-key element");\r
573     }\r
574 \r
575     if (this.type === ProtoBuf.TYPES["bytes"]) {\r
576         return value.toString("binary");\r
577     } else {\r
578         return value.toString();\r
579     }\r
580 };\r