1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5define("mojo/public/js/codec", [ 6 "mojo/public/js/unicode", 7 "mojo/public/js/buffer", 8], function(unicode, buffer) { 9 10 var kErrorUnsigned = "Passing negative value to unsigned"; 11 var kErrorArray = "Passing non Array for array type"; 12 var kErrorString = "Passing non String for string type"; 13 var kErrorMap = "Passing non Map for map type"; 14 15 // Memory ------------------------------------------------------------------- 16 17 var kAlignment = 8; 18 19 function align(size) { 20 return size + (kAlignment - (size % kAlignment)) % kAlignment; 21 } 22 23 function isAligned(offset) { 24 return offset >= 0 && (offset % kAlignment) === 0; 25 } 26 27 // Constants ---------------------------------------------------------------- 28 29 var kArrayHeaderSize = 8; 30 var kStructHeaderSize = 8; 31 var kMessageHeaderSize = 24; 32 var kMessageWithRequestIDHeaderSize = 32; 33 var kMapStructPayloadSize = 16; 34 35 var kStructHeaderNumBytesOffset = 0; 36 var kStructHeaderVersionOffset = 4; 37 38 var kEncodedInvalidHandleValue = 0xFFFFFFFF; 39 40 // Decoder ------------------------------------------------------------------ 41 42 function Decoder(buffer, handles, base) { 43 this.buffer = buffer; 44 this.handles = handles; 45 this.base = base; 46 this.next = base; 47 } 48 49 Decoder.prototype.align = function() { 50 this.next = align(this.next); 51 }; 52 53 Decoder.prototype.skip = function(offset) { 54 this.next += offset; 55 }; 56 57 Decoder.prototype.readInt8 = function() { 58 var result = this.buffer.getInt8(this.next); 59 this.next += 1; 60 return result; 61 }; 62 63 Decoder.prototype.readUint8 = function() { 64 var result = this.buffer.getUint8(this.next); 65 this.next += 1; 66 return result; 67 }; 68 69 Decoder.prototype.readInt16 = function() { 70 var result = this.buffer.getInt16(this.next); 71 this.next += 2; 72 return result; 73 }; 74 75 Decoder.prototype.readUint16 = function() { 76 var result = this.buffer.getUint16(this.next); 77 this.next += 2; 78 return result; 79 }; 80 81 Decoder.prototype.readInt32 = function() { 82 var result = this.buffer.getInt32(this.next); 83 this.next += 4; 84 return result; 85 }; 86 87 Decoder.prototype.readUint32 = function() { 88 var result = this.buffer.getUint32(this.next); 89 this.next += 4; 90 return result; 91 }; 92 93 Decoder.prototype.readInt64 = function() { 94 var result = this.buffer.getInt64(this.next); 95 this.next += 8; 96 return result; 97 }; 98 99 Decoder.prototype.readUint64 = function() { 100 var result = this.buffer.getUint64(this.next); 101 this.next += 8; 102 return result; 103 }; 104 105 Decoder.prototype.readFloat = function() { 106 var result = this.buffer.getFloat32(this.next); 107 this.next += 4; 108 return result; 109 }; 110 111 Decoder.prototype.readDouble = function() { 112 var result = this.buffer.getFloat64(this.next); 113 this.next += 8; 114 return result; 115 }; 116 117 Decoder.prototype.decodePointer = function() { 118 // TODO(abarth): To correctly decode a pointer, we need to know the real 119 // base address of the array buffer. 120 var offsetPointer = this.next; 121 var offset = this.readUint64(); 122 if (!offset) 123 return 0; 124 return offsetPointer + offset; 125 }; 126 127 Decoder.prototype.decodeAndCreateDecoder = function(pointer) { 128 return new Decoder(this.buffer, this.handles, pointer); 129 }; 130 131 Decoder.prototype.decodeHandle = function() { 132 return this.handles[this.readUint32()] || null; 133 }; 134 135 Decoder.prototype.decodeString = function() { 136 var numberOfBytes = this.readUint32(); 137 var numberOfElements = this.readUint32(); 138 var base = this.next; 139 this.next += numberOfElements; 140 return unicode.decodeUtf8String( 141 new Uint8Array(this.buffer.arrayBuffer, base, numberOfElements)); 142 }; 143 144 Decoder.prototype.decodeArray = function(cls) { 145 var numberOfBytes = this.readUint32(); 146 var numberOfElements = this.readUint32(); 147 var val = new Array(numberOfElements); 148 if (cls === PackedBool) { 149 var byte; 150 for (var i = 0; i < numberOfElements; ++i) { 151 if (i % 8 === 0) 152 byte = this.readUint8(); 153 val[i] = (byte & (1 << i % 8)) ? true : false; 154 } 155 } else { 156 for (var i = 0; i < numberOfElements; ++i) { 157 val[i] = cls.decode(this); 158 } 159 } 160 return val; 161 }; 162 163 Decoder.prototype.decodeStruct = function(cls) { 164 return cls.decode(this); 165 }; 166 167 Decoder.prototype.decodeStructPointer = function(cls) { 168 var pointer = this.decodePointer(); 169 if (!pointer) { 170 return null; 171 } 172 return cls.decode(this.decodeAndCreateDecoder(pointer)); 173 }; 174 175 Decoder.prototype.decodeArrayPointer = function(cls) { 176 var pointer = this.decodePointer(); 177 if (!pointer) { 178 return null; 179 } 180 return this.decodeAndCreateDecoder(pointer).decodeArray(cls); 181 }; 182 183 Decoder.prototype.decodeStringPointer = function() { 184 var pointer = this.decodePointer(); 185 if (!pointer) { 186 return null; 187 } 188 return this.decodeAndCreateDecoder(pointer).decodeString(); 189 }; 190 191 Decoder.prototype.decodeMap = function(keyClass, valueClass) { 192 this.skip(4); // numberOfBytes 193 this.skip(4); // version 194 var keys = this.decodeArrayPointer(keyClass); 195 var values = this.decodeArrayPointer(valueClass); 196 var val = new Map(); 197 for (var i = 0; i < keys.length; i++) 198 val.set(keys[i], values[i]); 199 return val; 200 }; 201 202 Decoder.prototype.decodeMapPointer = function(keyClass, valueClass) { 203 var pointer = this.decodePointer(); 204 if (!pointer) { 205 return null; 206 } 207 var decoder = this.decodeAndCreateDecoder(pointer); 208 return decoder.decodeMap(keyClass, valueClass); 209 }; 210 211 // Encoder ------------------------------------------------------------------ 212 213 function Encoder(buffer, handles, base) { 214 this.buffer = buffer; 215 this.handles = handles; 216 this.base = base; 217 this.next = base; 218 } 219 220 Encoder.prototype.align = function() { 221 this.next = align(this.next); 222 }; 223 224 Encoder.prototype.skip = function(offset) { 225 this.next += offset; 226 }; 227 228 Encoder.prototype.writeInt8 = function(val) { 229 this.buffer.setInt8(this.next, val); 230 this.next += 1; 231 }; 232 233 Encoder.prototype.writeUint8 = function(val) { 234 if (val < 0) { 235 throw new Error(kErrorUnsigned); 236 } 237 this.buffer.setUint8(this.next, val); 238 this.next += 1; 239 }; 240 241 Encoder.prototype.writeInt16 = function(val) { 242 this.buffer.setInt16(this.next, val); 243 this.next += 2; 244 }; 245 246 Encoder.prototype.writeUint16 = function(val) { 247 if (val < 0) { 248 throw new Error(kErrorUnsigned); 249 } 250 this.buffer.setUint16(this.next, val); 251 this.next += 2; 252 }; 253 254 Encoder.prototype.writeInt32 = function(val) { 255 this.buffer.setInt32(this.next, val); 256 this.next += 4; 257 }; 258 259 Encoder.prototype.writeUint32 = function(val) { 260 if (val < 0) { 261 throw new Error(kErrorUnsigned); 262 } 263 this.buffer.setUint32(this.next, val); 264 this.next += 4; 265 }; 266 267 Encoder.prototype.writeInt64 = function(val) { 268 this.buffer.setInt64(this.next, val); 269 this.next += 8; 270 }; 271 272 Encoder.prototype.writeUint64 = function(val) { 273 if (val < 0) { 274 throw new Error(kErrorUnsigned); 275 } 276 this.buffer.setUint64(this.next, val); 277 this.next += 8; 278 }; 279 280 Encoder.prototype.writeFloat = function(val) { 281 this.buffer.setFloat32(this.next, val); 282 this.next += 4; 283 }; 284 285 Encoder.prototype.writeDouble = function(val) { 286 this.buffer.setFloat64(this.next, val); 287 this.next += 8; 288 }; 289 290 Encoder.prototype.encodePointer = function(pointer) { 291 if (!pointer) 292 return this.writeUint64(0); 293 // TODO(abarth): To correctly encode a pointer, we need to know the real 294 // base address of the array buffer. 295 var offset = pointer - this.next; 296 this.writeUint64(offset); 297 }; 298 299 Encoder.prototype.createAndEncodeEncoder = function(size) { 300 var pointer = this.buffer.alloc(align(size)); 301 this.encodePointer(pointer); 302 return new Encoder(this.buffer, this.handles, pointer); 303 }; 304 305 Encoder.prototype.encodeHandle = function(handle) { 306 this.handles.push(handle); 307 this.writeUint32(this.handles.length - 1); 308 }; 309 310 Encoder.prototype.encodeString = function(val) { 311 var base = this.next + kArrayHeaderSize; 312 var numberOfElements = unicode.encodeUtf8String( 313 val, new Uint8Array(this.buffer.arrayBuffer, base)); 314 var numberOfBytes = kArrayHeaderSize + numberOfElements; 315 this.writeUint32(numberOfBytes); 316 this.writeUint32(numberOfElements); 317 this.next += numberOfElements; 318 }; 319 320 Encoder.prototype.encodeArray = 321 function(cls, val, numberOfElements, encodedSize) { 322 if (numberOfElements === undefined) 323 numberOfElements = val.length; 324 if (encodedSize === undefined) 325 encodedSize = kArrayHeaderSize + cls.encodedSize * numberOfElements; 326 327 this.writeUint32(encodedSize); 328 this.writeUint32(numberOfElements); 329 330 if (cls === PackedBool) { 331 var byte = 0; 332 for (i = 0; i < numberOfElements; ++i) { 333 if (val[i]) 334 byte |= (1 << i % 8); 335 if (i % 8 === 7 || i == numberOfElements - 1) { 336 Uint8.encode(this, byte); 337 byte = 0; 338 } 339 } 340 } else { 341 for (var i = 0; i < numberOfElements; ++i) 342 cls.encode(this, val[i]); 343 } 344 }; 345 346 Encoder.prototype.encodeStruct = function(cls, val) { 347 return cls.encode(this, val); 348 }; 349 350 Encoder.prototype.encodeStructPointer = function(cls, val) { 351 if (val == null) { 352 // Also handles undefined, since undefined == null. 353 this.encodePointer(val); 354 return; 355 } 356 var encoder = this.createAndEncodeEncoder(cls.encodedSize); 357 cls.encode(encoder, val); 358 }; 359 360 Encoder.prototype.encodeArrayPointer = function(cls, val) { 361 if (val == null) { 362 // Also handles undefined, since undefined == null. 363 this.encodePointer(val); 364 return; 365 } 366 367 var numberOfElements = val.length; 368 if (!Number.isSafeInteger(numberOfElements) || numberOfElements < 0) 369 throw new Error(kErrorArray); 370 371 var encodedSize = kArrayHeaderSize + ((cls === PackedBool) ? 372 Math.ceil(numberOfElements / 8) : cls.encodedSize * numberOfElements); 373 var encoder = this.createAndEncodeEncoder(encodedSize); 374 encoder.encodeArray(cls, val, numberOfElements, encodedSize); 375 }; 376 377 Encoder.prototype.encodeStringPointer = function(val) { 378 if (val == null) { 379 // Also handles undefined, since undefined == null. 380 this.encodePointer(val); 381 return; 382 } 383 // Only accepts string primivites, not String Objects like new String("foo") 384 if (typeof(val) !== "string") { 385 throw new Error(kErrorString); 386 } 387 var encodedSize = kArrayHeaderSize + unicode.utf8Length(val); 388 var encoder = this.createAndEncodeEncoder(encodedSize); 389 encoder.encodeString(val); 390 }; 391 392 Encoder.prototype.encodeMap = function(keyClass, valueClass, val) { 393 var keys = new Array(val.size); 394 var values = new Array(val.size); 395 var i = 0; 396 val.forEach(function(value, key) { 397 values[i] = value; 398 keys[i++] = key; 399 }); 400 this.writeUint32(kStructHeaderSize + kMapStructPayloadSize); 401 this.writeUint32(0); // version 402 this.encodeArrayPointer(keyClass, keys); 403 this.encodeArrayPointer(valueClass, values); 404 } 405 406 Encoder.prototype.encodeMapPointer = function(keyClass, valueClass, val) { 407 if (val == null) { 408 // Also handles undefined, since undefined == null. 409 this.encodePointer(val); 410 return; 411 } 412 if (!(val instanceof Map)) { 413 throw new Error(kErrorMap); 414 } 415 var encodedSize = kStructHeaderSize + kMapStructPayloadSize; 416 var encoder = this.createAndEncodeEncoder(encodedSize); 417 encoder.encodeMap(keyClass, valueClass, val); 418 }; 419 420 // Message ------------------------------------------------------------------ 421 422 var kMessageInterfaceIdOffset = kStructHeaderSize; 423 var kMessageNameOffset = kMessageInterfaceIdOffset + 4; 424 var kMessageFlagsOffset = kMessageNameOffset + 4; 425 var kMessageRequestIDOffset = kMessageFlagsOffset + 8; 426 427 var kMessageExpectsResponse = 1 << 0; 428 var kMessageIsResponse = 1 << 1; 429 430 function Message(buffer, handles) { 431 this.buffer = buffer; 432 this.handles = handles; 433 } 434 435 Message.prototype.getHeaderNumBytes = function() { 436 return this.buffer.getUint32(kStructHeaderNumBytesOffset); 437 }; 438 439 Message.prototype.getHeaderVersion = function() { 440 return this.buffer.getUint32(kStructHeaderVersionOffset); 441 }; 442 443 Message.prototype.getName = function() { 444 return this.buffer.getUint32(kMessageNameOffset); 445 }; 446 447 Message.prototype.getFlags = function() { 448 return this.buffer.getUint32(kMessageFlagsOffset); 449 }; 450 451 Message.prototype.isResponse = function() { 452 return (this.getFlags() & kMessageIsResponse) != 0; 453 }; 454 455 Message.prototype.expectsResponse = function() { 456 return (this.getFlags() & kMessageExpectsResponse) != 0; 457 }; 458 459 Message.prototype.setRequestID = function(requestID) { 460 // TODO(darin): Verify that space was reserved for this field! 461 this.buffer.setUint64(kMessageRequestIDOffset, requestID); 462 }; 463 464 465 // MessageBuilder ----------------------------------------------------------- 466 467 function MessageBuilder(messageName, payloadSize) { 468 // Currently, we don't compute the payload size correctly ahead of time. 469 // Instead, we resize the buffer at the end. 470 var numberOfBytes = kMessageHeaderSize + payloadSize; 471 this.buffer = new buffer.Buffer(numberOfBytes); 472 this.handles = []; 473 var encoder = this.createEncoder(kMessageHeaderSize); 474 encoder.writeUint32(kMessageHeaderSize); 475 encoder.writeUint32(0); // version. 476 encoder.writeUint32(0); // interface ID. 477 encoder.writeUint32(messageName); 478 encoder.writeUint32(0); // flags. 479 encoder.writeUint32(0); // padding. 480 } 481 482 MessageBuilder.prototype.createEncoder = function(size) { 483 var pointer = this.buffer.alloc(size); 484 return new Encoder(this.buffer, this.handles, pointer); 485 }; 486 487 MessageBuilder.prototype.encodeStruct = function(cls, val) { 488 cls.encode(this.createEncoder(cls.encodedSize), val); 489 }; 490 491 MessageBuilder.prototype.finish = function() { 492 // TODO(abarth): Rather than resizing the buffer at the end, we could 493 // compute the size we need ahead of time, like we do in C++. 494 this.buffer.trim(); 495 var message = new Message(this.buffer, this.handles); 496 this.buffer = null; 497 this.handles = null; 498 this.encoder = null; 499 return message; 500 }; 501 502 // MessageWithRequestIDBuilder ----------------------------------------------- 503 504 function MessageWithRequestIDBuilder(messageName, payloadSize, flags, 505 requestID) { 506 // Currently, we don't compute the payload size correctly ahead of time. 507 // Instead, we resize the buffer at the end. 508 var numberOfBytes = kMessageWithRequestIDHeaderSize + payloadSize; 509 this.buffer = new buffer.Buffer(numberOfBytes); 510 this.handles = []; 511 var encoder = this.createEncoder(kMessageWithRequestIDHeaderSize); 512 encoder.writeUint32(kMessageWithRequestIDHeaderSize); 513 encoder.writeUint32(1); // version. 514 encoder.writeUint32(0); // interface ID. 515 encoder.writeUint32(messageName); 516 encoder.writeUint32(flags); 517 encoder.writeUint32(0); // padding. 518 encoder.writeUint64(requestID); 519 } 520 521 MessageWithRequestIDBuilder.prototype = 522 Object.create(MessageBuilder.prototype); 523 524 MessageWithRequestIDBuilder.prototype.constructor = 525 MessageWithRequestIDBuilder; 526 527 // MessageReader ------------------------------------------------------------ 528 529 function MessageReader(message) { 530 this.decoder = new Decoder(message.buffer, message.handles, 0); 531 var messageHeaderSize = this.decoder.readUint32(); 532 this.payloadSize = message.buffer.byteLength - messageHeaderSize; 533 var version = this.decoder.readUint32(); 534 var interface_id = this.decoder.readUint32(); 535 if (interface_id != 0) { 536 throw new Error("Receiving non-zero interface ID. Associated interfaces " + 537 "are not yet supported."); 538 } 539 this.messageName = this.decoder.readUint32(); 540 this.flags = this.decoder.readUint32(); 541 // Skip the padding. 542 this.decoder.skip(4); 543 if (version >= 1) 544 this.requestID = this.decoder.readUint64(); 545 this.decoder.skip(messageHeaderSize - this.decoder.next); 546 } 547 548 MessageReader.prototype.decodeStruct = function(cls) { 549 return cls.decode(this.decoder); 550 }; 551 552 // Built-in types ----------------------------------------------------------- 553 554 // This type is only used with ArrayOf(PackedBool). 555 function PackedBool() { 556 } 557 558 function Int8() { 559 } 560 561 Int8.encodedSize = 1; 562 563 Int8.decode = function(decoder) { 564 return decoder.readInt8(); 565 }; 566 567 Int8.encode = function(encoder, val) { 568 encoder.writeInt8(val); 569 }; 570 571 Uint8.encode = function(encoder, val) { 572 encoder.writeUint8(val); 573 }; 574 575 function Uint8() { 576 } 577 578 Uint8.encodedSize = 1; 579 580 Uint8.decode = function(decoder) { 581 return decoder.readUint8(); 582 }; 583 584 Uint8.encode = function(encoder, val) { 585 encoder.writeUint8(val); 586 }; 587 588 function Int16() { 589 } 590 591 Int16.encodedSize = 2; 592 593 Int16.decode = function(decoder) { 594 return decoder.readInt16(); 595 }; 596 597 Int16.encode = function(encoder, val) { 598 encoder.writeInt16(val); 599 }; 600 601 function Uint16() { 602 } 603 604 Uint16.encodedSize = 2; 605 606 Uint16.decode = function(decoder) { 607 return decoder.readUint16(); 608 }; 609 610 Uint16.encode = function(encoder, val) { 611 encoder.writeUint16(val); 612 }; 613 614 function Int32() { 615 } 616 617 Int32.encodedSize = 4; 618 619 Int32.decode = function(decoder) { 620 return decoder.readInt32(); 621 }; 622 623 Int32.encode = function(encoder, val) { 624 encoder.writeInt32(val); 625 }; 626 627 function Uint32() { 628 } 629 630 Uint32.encodedSize = 4; 631 632 Uint32.decode = function(decoder) { 633 return decoder.readUint32(); 634 }; 635 636 Uint32.encode = function(encoder, val) { 637 encoder.writeUint32(val); 638 }; 639 640 function Int64() { 641 } 642 643 Int64.encodedSize = 8; 644 645 Int64.decode = function(decoder) { 646 return decoder.readInt64(); 647 }; 648 649 Int64.encode = function(encoder, val) { 650 encoder.writeInt64(val); 651 }; 652 653 function Uint64() { 654 } 655 656 Uint64.encodedSize = 8; 657 658 Uint64.decode = function(decoder) { 659 return decoder.readUint64(); 660 }; 661 662 Uint64.encode = function(encoder, val) { 663 encoder.writeUint64(val); 664 }; 665 666 function String() { 667 }; 668 669 String.encodedSize = 8; 670 671 String.decode = function(decoder) { 672 return decoder.decodeStringPointer(); 673 }; 674 675 String.encode = function(encoder, val) { 676 encoder.encodeStringPointer(val); 677 }; 678 679 function NullableString() { 680 } 681 682 NullableString.encodedSize = String.encodedSize; 683 684 NullableString.decode = String.decode; 685 686 NullableString.encode = String.encode; 687 688 function Float() { 689 } 690 691 Float.encodedSize = 4; 692 693 Float.decode = function(decoder) { 694 return decoder.readFloat(); 695 }; 696 697 Float.encode = function(encoder, val) { 698 encoder.writeFloat(val); 699 }; 700 701 function Double() { 702 } 703 704 Double.encodedSize = 8; 705 706 Double.decode = function(decoder) { 707 return decoder.readDouble(); 708 }; 709 710 Double.encode = function(encoder, val) { 711 encoder.writeDouble(val); 712 }; 713 714 function PointerTo(cls) { 715 this.cls = cls; 716 } 717 718 PointerTo.prototype.encodedSize = 8; 719 720 PointerTo.prototype.decode = function(decoder) { 721 var pointer = decoder.decodePointer(); 722 if (!pointer) { 723 return null; 724 } 725 return this.cls.decode(decoder.decodeAndCreateDecoder(pointer)); 726 }; 727 728 PointerTo.prototype.encode = function(encoder, val) { 729 if (!val) { 730 encoder.encodePointer(val); 731 return; 732 } 733 var objectEncoder = encoder.createAndEncodeEncoder(this.cls.encodedSize); 734 this.cls.encode(objectEncoder, val); 735 }; 736 737 function NullablePointerTo(cls) { 738 PointerTo.call(this, cls); 739 } 740 741 NullablePointerTo.prototype = Object.create(PointerTo.prototype); 742 743 function ArrayOf(cls, length) { 744 this.cls = cls; 745 this.length = length || 0; 746 } 747 748 ArrayOf.prototype.encodedSize = 8; 749 750 ArrayOf.prototype.dimensions = function() { 751 return [this.length].concat( 752 (this.cls instanceof ArrayOf) ? this.cls.dimensions() : []); 753 } 754 755 ArrayOf.prototype.decode = function(decoder) { 756 return decoder.decodeArrayPointer(this.cls); 757 }; 758 759 ArrayOf.prototype.encode = function(encoder, val) { 760 encoder.encodeArrayPointer(this.cls, val); 761 }; 762 763 function NullableArrayOf(cls) { 764 ArrayOf.call(this, cls); 765 } 766 767 NullableArrayOf.prototype = Object.create(ArrayOf.prototype); 768 769 function Handle() { 770 } 771 772 Handle.encodedSize = 4; 773 774 Handle.decode = function(decoder) { 775 return decoder.decodeHandle(); 776 }; 777 778 Handle.encode = function(encoder, val) { 779 encoder.encodeHandle(val); 780 }; 781 782 function NullableHandle() { 783 } 784 785 NullableHandle.encodedSize = Handle.encodedSize; 786 787 NullableHandle.decode = Handle.decode; 788 789 NullableHandle.encode = Handle.encode; 790 791 function Interface() { 792 } 793 794 Interface.encodedSize = 8; 795 796 Interface.decode = function(decoder) { 797 var handle = decoder.decodeHandle(); 798 // Ignore the version field for now. 799 decoder.readUint32(); 800 801 return handle; 802 }; 803 804 Interface.encode = function(encoder, val) { 805 encoder.encodeHandle(val); 806 // Set the version field to 0 for now. 807 encoder.writeUint32(0); 808 }; 809 810 function NullableInterface() { 811 } 812 813 NullableInterface.encodedSize = Interface.encodedSize; 814 815 NullableInterface.decode = Interface.decode; 816 817 NullableInterface.encode = Interface.encode; 818 819 function MapOf(keyClass, valueClass) { 820 this.keyClass = keyClass; 821 this.valueClass = valueClass; 822 } 823 824 MapOf.prototype.encodedSize = 8; 825 826 MapOf.prototype.decode = function(decoder) { 827 return decoder.decodeMapPointer(this.keyClass, this.valueClass); 828 }; 829 830 MapOf.prototype.encode = function(encoder, val) { 831 encoder.encodeMapPointer(this.keyClass, this.valueClass, val); 832 }; 833 834 function NullableMapOf(keyClass, valueClass) { 835 MapOf.call(this, keyClass, valueClass); 836 } 837 838 NullableMapOf.prototype = Object.create(MapOf.prototype); 839 840 var exports = {}; 841 exports.align = align; 842 exports.isAligned = isAligned; 843 exports.Message = Message; 844 exports.MessageBuilder = MessageBuilder; 845 exports.MessageWithRequestIDBuilder = MessageWithRequestIDBuilder; 846 exports.MessageReader = MessageReader; 847 exports.kArrayHeaderSize = kArrayHeaderSize; 848 exports.kMapStructPayloadSize = kMapStructPayloadSize; 849 exports.kStructHeaderSize = kStructHeaderSize; 850 exports.kEncodedInvalidHandleValue = kEncodedInvalidHandleValue; 851 exports.kMessageHeaderSize = kMessageHeaderSize; 852 exports.kMessageWithRequestIDHeaderSize = kMessageWithRequestIDHeaderSize; 853 exports.kMessageExpectsResponse = kMessageExpectsResponse; 854 exports.kMessageIsResponse = kMessageIsResponse; 855 exports.Int8 = Int8; 856 exports.Uint8 = Uint8; 857 exports.Int16 = Int16; 858 exports.Uint16 = Uint16; 859 exports.Int32 = Int32; 860 exports.Uint32 = Uint32; 861 exports.Int64 = Int64; 862 exports.Uint64 = Uint64; 863 exports.Float = Float; 864 exports.Double = Double; 865 exports.String = String; 866 exports.NullableString = NullableString; 867 exports.PointerTo = PointerTo; 868 exports.NullablePointerTo = NullablePointerTo; 869 exports.ArrayOf = ArrayOf; 870 exports.NullableArrayOf = NullableArrayOf; 871 exports.PackedBool = PackedBool; 872 exports.Handle = Handle; 873 exports.NullableHandle = NullableHandle; 874 exports.Interface = Interface; 875 exports.NullableInterface = NullableInterface; 876 exports.MapOf = MapOf; 877 exports.NullableMapOf = NullableMapOf; 878 return exports; 879}); 880