| Index: mojo/public/dart/src/codec.dart
|
| diff --git a/mojo/public/dart/src/codec.dart b/mojo/public/dart/src/codec.dart
|
| index 5d017367e4afb3e676ce027519afe946869c6658..8969ea101081f66281b370892f620a79bd5adf2c 100644
|
| --- a/mojo/public/dart/src/codec.dart
|
| +++ b/mojo/public/dart/src/codec.dart
|
| @@ -2,768 +2,557 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| -// TODO(zra): Rewrite MojoDecoder and MojoEncoder using Dart idioms, and make
|
| -// corresponding changes to the bindings generation script.
|
| -
|
| part of bindings;
|
|
|
| -const int kAlignment = 8;
|
| -const int kArrayHeaderSize = 8;
|
| -const int kStructHeaderSize = 8;
|
| -const int kMessageHeaderSize = 16;
|
| -const int kMessageWithRequestIDHeaderSize = 24;
|
| -const int kMapStructPayloadSize = 16;
|
| -const int kStructHeaderNumBytesOffset = 0;
|
| -const int kStructHeaderNumFieldsOffset = 4;
|
| -const int kEncodedInvalidHandleValue = 0xffffffff;
|
| -const String kErrorUnsigned = "Passing negative value to unsigned encoder";
|
| -
|
| -
|
| int align(int size) => size + (kAlignment - (size % kAlignment)) % kAlignment;
|
| -bool isAligned(offset) => (offset >= 0) && ((offset % kAlignment) == 0);
|
| -
|
| -
|
| -Uint8List utf8OfString(String s) =>
|
| - (new Uint8List.fromList((const Utf8Encoder()).convert(s)));
|
| -
|
|
|
| -String stringOfUtf8(Uint8List bytes) =>
|
| - (const Utf8Decoder()).convert(bytes.toList());
|
| -
|
| -
|
| -// Given an argument that is either a Type or an instance:
|
| -// Invoke the static method "decode" of the Type, or the instance method
|
| -// "decode" of the instance, on the MojoDecoder.
|
| -Object _callDecode(Object typeOrInstance, MojoDecoder decoder) {
|
| - if (typeOrInstance is Type) {
|
| - return reflectClass(typeOrInstance).invoke(#decode, [decoder]).reflectee;
|
| - } else {
|
| - return typeOrInstance.decode(decoder);
|
| - }
|
| -}
|
| -
|
| -
|
| -// Given an argument that is either a Type or an instance:
|
| -// Invoke the static method "encode" of the Type, or the instance method
|
| -// "encode" of the instance, on the MojoEncoder and value to be encoded.
|
| -void _callEncode(Object typeOrInstance, MojoEncoder encoder, Object val) {
|
| - if (typeOrInstance is Type) {
|
| - reflectClass(typeOrInstance).invoke(#encode, [encoder, val]);
|
| - } else {
|
| - typeOrInstance.encode(encoder, val);
|
| - }
|
| -}
|
| -
|
| -
|
| -// Given an argument that is either a Type or an instance:
|
| -// Invoke the static getter "encodedSize" of the Type, or the instance getter
|
| -// "encodedSize" of the instance, and return the result.
|
| -int getEncodedSize(Object typeOrInstance) {
|
| - if (typeOrInstance is Type) {
|
| - return reflectClass(typeOrInstance).getField(#encodedSize).reflectee;
|
| - } else {
|
| - return typeOrInstance.encodedSize;
|
| - }
|
| -}
|
| -
|
| -
|
| -class MojoDecoder {
|
| +const int kAlignment = 8;
|
| +const int kSerializedHandleSize = 4;
|
| +const int kPointerSize = 8;
|
| +const DataHeader kMapStructHeader = const DataHeader(24, 2);
|
| +const int kUnspecifiedArrayLength = -1;
|
| +const int kNothingNullable = 0;
|
| +const int kArrayNullable = (1 << 0);
|
| +const int kElementNullable = (1 << 1);
|
| +
|
| +bool isArrayNullable(int nullability) => (nullability & kArrayNullable) > 0;
|
| +bool isElementNullable(int nullability) => (nullability & kElementNullable) > 0;
|
| +
|
| +class _EncoderBuffer {
|
| ByteData buffer;
|
| - List<core.RawMojoHandle> handles;
|
| - int base;
|
| - int next;
|
| + List<core.MojoHandle> handles;
|
| + int extent;
|
|
|
| - MojoDecoder(this.buffer, this.handles, this.base) {
|
| - next = base;
|
| - }
|
| + static const int kInitialBufferSize = 1024;
|
|
|
| - void skip(int offset) {
|
| - next += offset;
|
| - }
|
| + _EncoderBuffer([int size = -1]) :
|
| + buffer = new ByteData(size > 0 ? size : kInitialBufferSize),
|
| + handles = [],
|
| + extent = 0;
|
|
|
| - int readInt8() {
|
| - int result = buffer.getInt8(next);
|
| - next += 1;
|
| - return result;
|
| + void _grow(int newSize) {
|
| + Uint8List newBuffer = new Uint8List(newSize);
|
| + newBuffer.setRange(0, buffer.lengthInBytes, buffer.buffer.asUint8List());
|
| + buffer = newBuffer.buffer.asByteData();
|
| }
|
|
|
| - int readUint8() {
|
| - int result = buffer.getUint8(next);
|
| - next += 1;
|
| - return result;
|
| + void claimMemory(int claimSize) {
|
| + extent += claimSize;
|
| + if (extent > buffer.lengthInBytes) {
|
| + int newSize = buffer.lengthInBytes + claimSize;
|
| + newSize += newSize ~/ 2;
|
| + _grow(newSize);
|
| + }
|
| }
|
|
|
| - int readInt16() {
|
| - int result = buffer.getInt16(next, Endianness.LITTLE_ENDIAN);
|
| - next += 2;
|
| - return result;
|
| - }
|
| + ByteData get trimmed => new ByteData.view(buffer.buffer, 0, extent);
|
| +}
|
|
|
| - int readUint16() {
|
| - int result = buffer.getUint16(next, Endianness.LITTLE_ENDIAN);
|
| - next += 2;
|
| - return result;
|
| - }
|
| +class Encoder {
|
| + _EncoderBuffer _buffer;
|
| + int _base;
|
|
|
| - int readInt32() {
|
| - int result = buffer.getInt32(next, Endianness.LITTLE_ENDIAN);
|
| - next += 4;
|
| - return result;
|
| - }
|
| + Encoder([int size = -1]) : _buffer = new _EncoderBuffer(size), _base = 0;
|
|
|
| - int readUint32() {
|
| - int result = buffer.getUint32(next, Endianness.LITTLE_ENDIAN);
|
| - next += 4;
|
| - return result;
|
| - }
|
| + Encoder._fromBuffer(_EncoderBuffer buffer) :
|
| + _buffer = buffer,
|
| + _base = buffer.extent;
|
|
|
| - int readInt64() {
|
| - int result = buffer.getInt64(next, Endianness.LITTLE_ENDIAN);
|
| - next += 8;
|
| + Encoder getEncoderAtOffset(DataHeader dataHeader) {
|
| + var result = new Encoder._fromBuffer(_buffer);
|
| + result.encodeDataHeader(dataHeader);
|
| return result;
|
| }
|
|
|
| - int readUint64() {
|
| - int result = buffer.getUint64(next, Endianness.LITTLE_ENDIAN);
|
| - next += 8;
|
| - return result;
|
| - }
|
| + Message get message => new Message(_buffer.trimmed, _buffer.handles);
|
|
|
| - double readFloat() {
|
| - double result = buffer.getFloat32(next,Endianness.LITTLE_ENDIAN);
|
| - next += 4;
|
| - return result;
|
| + void encodeDataHeader(DataHeader dataHeader) {
|
| + _buffer.claimMemory(align(dataHeader.size));
|
| + encodeUint32(dataHeader.size, DataHeader.kSizeOffset);
|
| + encodeUint32(dataHeader.numFields, DataHeader.kNumFieldsOffset);
|
| }
|
|
|
| - double readDouble() {
|
| - double result = buffer.getFloat64(next, Endianness.LITTLE_ENDIAN);
|
| - next += 8;
|
| - return result;
|
| - }
|
| + static const String kErrorUnsigned =
|
| + 'Passing negative value to unsigned encoder';
|
|
|
| - int decodePointer() {
|
| - int offsetPointer = next;
|
| - int offset = readUint64();
|
| - if (offset == 0) {
|
| - return 0;
|
| + void encodeBool(bool value, int offset, int bit) {
|
| + if (value) {
|
| + int encodedValue = _buffer.buffer.getUint8(_base + offset);
|
| + encodedValue |= (1 << bit);
|
| + _buffer.buffer.setUint8(_base + offset, encodedValue);
|
| }
|
| - return offsetPointer + offset;
|
| - }
|
| -
|
| - MojoDecoder decodeAndCreateDecoder(int offset) {
|
| - return new MojoDecoder(buffer, handles, offset);
|
| }
|
|
|
| - core.RawMojoHandle decodeHandle() {
|
| - int handleIndex = readUint32();
|
| - return (handleIndex == kEncodedInvalidHandleValue) ?
|
| - new core.RawMojoHandle(core.RawMojoHandle.INVALID) :
|
| - handles[handleIndex];
|
| - }
|
| -
|
| - String decodeString() {
|
| - int numBytes = readUint32();
|
| - int numElements = readUint32();
|
| - int base = next;
|
| - next += numElements;
|
| - return stringOfUtf8(buffer.buffer.asUint8List(base, numElements));
|
| - }
|
| + void encodeInt8(int value, int offset) =>
|
| + _buffer.buffer.setInt8(_base + offset, value);
|
|
|
| - List decodeArray(Object type) {
|
| - int numBytes = readUint32();
|
| - int numElements = readUint32();
|
| - if (type == PackedBool) {
|
| - int b;
|
| - List<bool> result = new List<bool>(numElements);
|
| - for (int i = 0; i < numElements; i++) {
|
| - if ((i % 8) == 0) {
|
| - b = readUint8();
|
| - }
|
| - result[i] = ((b & (1 << (i % 8)) != 0) ? true : false);
|
| - }
|
| - return result;
|
| - } else {
|
| - List result = new List(numElements);
|
| - for (int i = 0; i < numElements; i++) {
|
| - result[i] = _callDecode(type, this);
|
| - }
|
| - return result;
|
| + void encodeUint8(int value, int offset) {
|
| + if (value < 0) {
|
| + throw '$kErrorUnsigned: $val';
|
| }
|
| + _buffer.buffer.setUint8(_base + offset, value);
|
| }
|
|
|
| - Object decodeStruct(Object t) {
|
| - return _callDecode(t, this);
|
| - }
|
| + void encodeInt16(int value, int offset) =>
|
| + _buffer.buffer.setInt16(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
|
|
| - Object decodeStructPointer(Object t) {
|
| - int pointer = decodePointer();
|
| - if (pointer == 0) {
|
| - return null;
|
| + void encodeUint16(int value, int offset) {
|
| + if (value < 0) {
|
| + throw '$kErrorUnsigned: $val';
|
| }
|
| - return _callDecode(t, decodeAndCreateDecoder(pointer));
|
| + _buffer.buffer.setUint16(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
| }
|
|
|
| - List decodeArrayPointer(Object type) {
|
| - int pointer = decodePointer();
|
| - if (pointer == 0) {
|
| - return null;
|
| - }
|
| - return decodeAndCreateDecoder(pointer).decodeArray(type);
|
| - }
|
| + void encodeInt32(int value, int offset) =>
|
| + _buffer.buffer.setInt32(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
|
|
| - String decodeStringPointer() {
|
| - int pointer = decodePointer();
|
| - if (pointer == 0) {
|
| - return null;
|
| + void encodeUint32(int value, int offset) {
|
| + if (value < 0) {
|
| + throw '$kErrorUnsigned: $val';
|
| }
|
| - return decodeAndCreateDecoder(pointer).decodeString();
|
| + _buffer.buffer.setUint32(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
| }
|
|
|
| - Map decodeMap(Object keyType, Object valType) {
|
| - skip(4); // number of bytes.
|
| - skip(4); // number of fields.
|
| - List keys = decodeArrayPointer(keyType);
|
| - List values = decodeArrayPointer(valType);
|
| - return new Map.fromIterables(keys, values);
|
| - }
|
| + void encodeInt64(int value, int offset) =>
|
| + _buffer.buffer.setInt64(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
|
|
| - Map decodeMapPointer(Object keyType, Object valType) {
|
| - int pointer = this.decodePointer();
|
| - if (pointer == 0) {
|
| - return null;
|
| + void encodeUint64(int value, int offset) {
|
| + if (value < 0) {
|
| + throw '$kErrorUnsigned: $val';
|
| }
|
| - MojoDecoder decoder = decodeAndCreateDecoder(pointer);
|
| - return decoder.decodeMap(keyType, valType);
|
| + _buffer.buffer.setUint64(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
| }
|
| -}
|
|
|
| + void encodeFloat(double value, int offset) =>
|
| + _buffer.buffer.setFloat32(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
|
|
| -class MojoEncoder {
|
| - ByteData buffer;
|
| - List<core.RawMojoHandle> handles;
|
| - int base;
|
| - int next;
|
| - int extent;
|
| -
|
| - MojoEncoder(this.buffer, this.handles, this.base, this.extent) {
|
| - next = base;
|
| - }
|
| + void encodeDouble(double value, int offset) =>
|
| + _buffer.buffer.setFloat64(_base + offset, value, Endianness.LITTLE_ENDIAN);
|
|
|
| - void skip(int offset) {
|
| - next += offset;
|
| - }
|
| -
|
| - void writeInt8(int val) {
|
| - buffer.setInt8(next, val);
|
| - next += 1;
|
| - }
|
| -
|
| - void writeUint8(int val) {
|
| - if (val < 0) {
|
| - throw new ArgumentError("$kErrorUnsigned: $val");
|
| + void encodeHandle(core.MojoHandle value, int offset, bool nullable) {
|
| + if ((value == null) || !value.isValid) {
|
| + encodeInvalideHandle(offset, nullable);
|
| + } else {
|
| + encodeUint32(_buffer.handles.length, offset);
|
| + _buffer.handles.add(value);
|
| }
|
| - buffer.setUint8(next, val);
|
| - next += 1;
|
| - }
|
| -
|
| - void writeInt16(int val) {
|
| - buffer.setInt16(next, val, Endianness.LITTLE_ENDIAN);
|
| - next += 2;
|
| }
|
|
|
| - void writeUint16(int val) {
|
| - if (val < 0) {
|
| - throw new ArgumentError("$kErrorUnsigned: $val");
|
| + void encodeNullPointer(int offset, bool nullable) {
|
| + if (!nullable) {
|
| + throw 'Trying to encode a null pointer for a non-nullable type';
|
| }
|
| - buffer.setUint16(next, val, Endianness.LITTLE_ENDIAN);
|
| - next += 2;
|
| + _buffer.buffer.setUint64(_base + offset, 0, Endianness.LITTLE_ENDIAN);
|
| }
|
|
|
| - void writeInt32(int val) {
|
| - buffer.setInt32(next, val, Endianness.LITTLE_ENDIAN);
|
| - next += 4;
|
| - }
|
| -
|
| - void writeUint32(int val) {
|
| - if (val < 0) {
|
| - throw new ArgumentError("$kErrorUnsigned: $val");
|
| + void encodeInvalideHandle(int offset, bool nullable) {
|
| + if (!nullable) {
|
| + throw 'Trying to encode a null pointer for a non-nullable type';
|
| }
|
| - buffer.setUint32(next, val, Endianness.LITTLE_ENDIAN);
|
| - next += 4;
|
| - }
|
| -
|
| - void writeInt64(int val) {
|
| - buffer.setInt64(next, val, Endianness.LITTLE_ENDIAN);
|
| - next += 8;
|
| - }
|
| -
|
| - void writeUint64(int val) {
|
| - if (val < 0) {
|
| - throw new ArgumentError("$kErrorUnsigned: $val");
|
| - }
|
| - buffer.setUint64(next, val, Endianness.LITTLE_ENDIAN);
|
| - next += 8;
|
| - }
|
| -
|
| - void writeFloat(double val) {
|
| - buffer.setFloat32(next, val, Endianness.LITTLE_ENDIAN);
|
| - next += 4;
|
| + _buffer.buffer.setInt32(_base + offset, -1, Endianness.LITTLE_ENDIAN);
|
| }
|
|
|
| - void writeDouble(double val) {
|
| - buffer.setFloat64(next, val, Endianness.LITTLE_ENDIAN);
|
| - next += 8;
|
| - }
|
| + void encodePointerToNextUnclaimed(int offset) =>
|
| + encodeUint64(_buffer.extent - (_base + offset), offset);
|
|
|
| - void encodePointer(int pointer) {
|
| - if (pointer == null) {
|
| - writeUint64(0);
|
| + void encodeStruct(Struct value, int offset, bool nullable) {
|
| + if (value == null) {
|
| + encodeNullPointer(offset, nullable);
|
| return;
|
| }
|
| - int offset = pointer - next;
|
| - writeUint64(offset);
|
| - }
|
| -
|
| - void grow(int new_size) {
|
| - Uint8List new_buffer = new Uint8List(new_size);
|
| - new_buffer.setRange(0, buffer.lengthInBytes, buffer.buffer.asUint8List());
|
| - buffer = new_buffer.buffer.asByteData();
|
| - }
|
| -
|
| - int alloc(int size_request) {
|
| - int pointer = extent;
|
| - extent += size_request;
|
| - if (extent > buffer.lengthInBytes) {
|
| - int new_size = buffer.lengthInBytes + size_request;
|
| - new_size += new_size ~/ 2;
|
| - grow(new_size);
|
| - }
|
| - return pointer;
|
| + encodePointerToNextUnclaimed(offset);
|
| + value.encode(this);
|
| }
|
|
|
| - MojoEncoder createAndEncodeEncoder(int size) {
|
| - int pointer = alloc(align(size));
|
| - encodePointer(pointer);
|
| - return new MojoEncoder(buffer, handles, pointer, extent);
|
| - }
|
| + Encoder encodePointerArray(int length, int offset, int expectedLength) =>
|
| + encoderForArray(kPointerSize, length, offset, expectedLength);
|
|
|
| - void encodeHandle(core.RawMojoHandle handle) {
|
| - if (handle.isValid) {
|
| - handles.add(handle);
|
| - writeUint32(handles.length - 1);
|
| - } else {
|
| - writeUint32(kEncodedInvalidHandleValue);
|
| + Encoder encoderForArray(
|
| + int elementSize, int length, int offset, int expectedLength) {
|
| + if ((expectedLength != kUnspecifiedArrayLength) &&
|
| + (expectedLength != length)) {
|
| + throw 'Trying to encode a fixed array of incorrect length';
|
| }
|
| + return encoderForArrayByTotalSize(length * elementSize, length, offset);
|
| }
|
|
|
| - void encodeString(String val) {
|
| - Uint8List utf8string = utf8OfString(val);
|
| - int numElements = utf8string.lengthInBytes;
|
| - int numBytes = kArrayHeaderSize + numElements;
|
| - writeUint32(numBytes);
|
| - writeUint32(numElements);
|
| - buffer.buffer.asUint8List().setRange(next, next + numElements, utf8string);
|
| - next += numElements;
|
| + Encoder encoderForArrayByTotalSize(int size, int length, int offset) {
|
| + encodePointerToNextUnclaimed(offset);
|
| + return getEncoderAtOffset(
|
| + new DataHeader(DataHeader.kHeaderSize + size, length));
|
| }
|
|
|
| - void encodeArray(Object t, List val, [int numElements, int encodedSize]) {
|
| - if (numElements == null) {
|
| - numElements = val.length;
|
| + void encodeBoolArray(
|
| + List<bool> value, int offset, int nullability, int expectedLength) {
|
| + if (value == null) {
|
| + encodeNullPointer(offset, isArrayNullable(nullability));
|
| + return;
|
| }
|
| - if (encodedSize == null) {
|
| - encodedSize = kArrayHeaderSize + (getEncodedSize(t) * numElements);
|
| + if ((expectedLength != kUnspecifiedArrayLength) &&
|
| + (expectedLength != value.length)) {
|
| + throw 'Trying to encode a fixed array of incorrect size.';
|
| }
|
| -
|
| - writeUint32(encodedSize);
|
| - writeUint32(numElements);
|
| -
|
| - if (t == PackedBool) {
|
| - int b = 0;
|
| - for (int i = 0; i < numElements; i++) {
|
| - if (val[i]) {
|
| - b |= (1 << (i % 8));
|
| - }
|
| - if (((i % 8) == 7) || (i == (numElements - 1))) {
|
| - Uint8.encode(this, b);
|
| + var bytes = new Uint8List((value.length + 7) ~/ kAlignment);
|
| + for (int i = 0; i < bytes.length; ++i) {
|
| + for (int j = 0; j < kAlignment; ++j) {
|
| + int boolIndex = kAlignment * i + j;
|
| + if ((boolIndex < value.length) && value[boolIndex]) {
|
| + bytes[i] |= (1 << j);
|
| }
|
| }
|
| - } else {
|
| - for (int i = 0; i < numElements; i++) {
|
| - _callEncode(t, this, val[i]);
|
| - }
|
| }
|
| - }
|
| -
|
| - void encodeStruct(Object t, Object val) {
|
| - _callEncode(t, this, val);
|
| - }
|
| -
|
| - void encodeStructPointer(Object t, Object val) {
|
| - if (val == null) {
|
| - encodePointer(val);
|
| + var encoder = encoderForArrayByTotalSize(
|
| + bytes.length, value.length, offset);
|
| + encoder.appendUint8Array(bytes);
|
| + }
|
| +
|
| + void encodeArray(Function arrayAppend,
|
| + int elementBytes,
|
| + List<int> value,
|
| + int offset,
|
| + int nullability,
|
| + int expectedLength) {
|
| + if (value == null) {
|
| + encodeNullPointer(offset, isArrayNullable(nullability));
|
| return;
|
| }
|
| - MojoEncoder encoder = createAndEncodeEncoder(getEncodedSize(t));
|
| - _callEncode(t, encoder, val);
|
| - extent = encoder.extent;
|
| - buffer = encoder.buffer;
|
| - }
|
| -
|
| - void encodeArrayPointer(Object t, List val) {
|
| - if (val == null) {
|
| - encodePointer(val);
|
| + var encoder = encoderForArray(
|
| + elementBytes, value.length, offset, expectedLength);
|
| + arrayAppend(encoder, value);
|
| + }
|
| +
|
| + void encodeInt8Array(
|
| + List<int> value, int offset, int nullability, int expectedLength) =>
|
| + encodeArray((e, v) => e.appendInt8Array(v),
|
| + 1, value, offset, nullability, expectedLength);
|
| +
|
| + void encodeUint8Array(
|
| + List<int> value, int offset, int nullability, int expectedLength) =>
|
| + encodeArray((e, v) => e.appendUint8Array(v),
|
| + 1, value, offset, nullability, expectedLength);
|
| +
|
| + void encodeInt16Array(
|
| + List<int> value, int offset, int nullability, int expectedLength) =>
|
| + encodeArray((e, v) => e.appendInt16Array(v),
|
| + 2, value, offset, nullability, expectedLength);
|
| +
|
| + void encodeUint16Array(
|
| + List<int> value, int offset, int nullability, int expectedLength) =>
|
| + encodeArray((e, v) => e.appendUint16Array(v),
|
| + 2, value, offset, nullability, expectedLength);
|
| +
|
| + void encodeInt32Array(
|
| + List<int> value, int offset, int nullability, int expectedLength) =>
|
| + encodeArray((e, v) => e.appendInt32Array(v),
|
| + 4, value, offset, nullability, expectedLength);
|
| +
|
| + void encodeUint32Array(
|
| + List<int> value, int offset, int nullability, int expectedLength) =>
|
| + encodeArray((e, v) => e.appendUint32Array(v),
|
| + 4, value, offset, nullability, expectedLength);
|
| +
|
| + void encodeInt64Array(
|
| + List<int> value, int offset, int nullability, int expectedLength) =>
|
| + encodeArray((e, v) => e.appendInt64Array(v),
|
| + 8, value, offset, nullability, expectedLength);
|
| +
|
| + void encodeUint64Array(
|
| + List<int> value, int offset, int nullability, int expectedLength) =>
|
| + encodeArray((e, v) => e.appendUint64Array(v),
|
| + 8, value, offset, nullability, expectedLength);
|
| +
|
| + void encodeFloatArray(
|
| + List<int> value, int offset, int nullability, int expectedLength) =>
|
| + encodeArray((e, v) => e.appendFloatArray(v),
|
| + 4, value, offset, nullability, expectedLength);
|
| +
|
| + void encodeDoubleArray(
|
| + List<int> value, int offset, int nullability, int expectedLength) =>
|
| + encodeArray((e, v) => e.appendDoubleArray(v),
|
| + 8, value, offset, nullability, expectedLength);
|
| +
|
| + void encodeHandleArray(List<core.MojoHandle> value,
|
| + int offset,
|
| + int nullability,
|
| + int expectedLength) {
|
| + if (value == null) {
|
| + encodeNullPointer(offset, isArrayNullable(nullability));
|
| return;
|
| }
|
| - int numElements = val.length;
|
| - int encodedSize = kArrayHeaderSize + ((t == PackedBool) ?
|
| - (numElements / 8).ceil() : (getEncodedSize(t) * numElements));
|
| - MojoEncoder encoder = createAndEncodeEncoder(encodedSize);
|
| - encoder.encodeArray(t, val, numElements, encodedSize);
|
| - extent = encoder.extent;
|
| - buffer = encoder.buffer;
|
| - }
|
| -
|
| - void encodeStringPointer(String val) {
|
| - if (val == null) {
|
| - encodePointer(val);
|
| - return;
|
| + var encoder = encoderForArray(
|
| + kSerializedHandleSize, value.length, offset, expectedLength);
|
| + for (int i = 0; i < value.length; ++i) {
|
| + int handleOffset = DataHeader.kHeaderSize + kSerializedHandleSize * i;
|
| + encoder.encodeHandle(
|
| + value[i], handleOffset, isElementNullable(nullability));
|
| }
|
| - int encodedSize = kArrayHeaderSize + utf8OfString(val).lengthInBytes;
|
| - MojoEncoder encoder = createAndEncodeEncoder(encodedSize);
|
| - encoder.encodeString(val);
|
| - extent = encoder.extent;
|
| - buffer = encoder.buffer;
|
| }
|
|
|
| - void encodeMap(Object keyType, Object valType, Map val) {
|
| - List keys = val.keys;
|
| - List vals = val.values;
|
| - writeUint32(kStructHeaderSize + kMapStructPayloadSize);
|
| - writeUint32(2);
|
| - encodeArrayPointer(keyType, keys);
|
| - encodeArrayPointer(valType, vals);
|
| - }
|
| + static Uint8List _utf8OfString(String s) =>
|
| + (new Uint8List.fromList((const Utf8Encoder()).convert(s)));
|
|
|
| - void encodeMapPointer(Object keyTYpe, Object valType, Map val) {
|
| - if (val == null) {
|
| - encodePointer(val);
|
| + void encodeString(String value, int offset, bool nullable) {
|
| + if (value == null) {
|
| + encodeNullPointer(offset, nullable);
|
| return;
|
| }
|
| - int encodedSize = kStructHeaderSize + kMapStructPayloadSize;
|
| - MojoEncoder encoder = createAndEncodeEncoder(encodedSize);
|
| - encoder.encodeMap(keyType, valType, val);
|
| - extent = encoder.extent;
|
| - buffer = encoder.buffer;
|
| + int nullability = nullable ? kArrayNullable : kNothingNullable;
|
| + encodeUint8Array(_utf8OfString(value),
|
| + offset,
|
| + nullability,
|
| + kUnspecifiedArrayLength);
|
| }
|
| -}
|
| -
|
|
|
| -const int kMessageNameOffset = kStructHeaderSize;
|
| -const int kMessageFlagsOffset = kMessageNameOffset + 4;
|
| -const int kMessageRequestIDOffset = kMessageFlagsOffset + 4;
|
| -const int kMessageExpectsResponse = 1 << 0;
|
| -const int kMessageIsResponse = 1 << 1;
|
| -
|
| -class Message {
|
| - ByteData buffer;
|
| - List<core.RawMojoHandle> handles;
|
| -
|
| - Message(this.buffer, this.handles);
|
| -
|
| - int getHeaderNumBytes() => buffer.getUint32(kStructHeaderNumBytesOffset);
|
| - int getHeaderNumFields() => buffer.getUint32(kStructHeaderNumFieldsOffset);
|
| - int getName() => buffer.getUint32(kMessageNameOffset);
|
| - int getFlags() => buffer.getUint32(kMessageFlagsOffset);
|
| - bool isResponse() => (getFlags() & kMessageIsResponse) != 0;
|
| - bool expectsResponse() => (getFlags() & kMessageExpectsResponse) != 0;
|
| -
|
| - void setRequestID(int id) {
|
| - buffer.setUint64(kMessageRequestIDOffset, id);
|
| + void appendBytes(Uint8List value) {
|
| + _buffer.buffer.buffer.asUint8List().setRange(
|
| + _base + DataHeader.kHeaderSize,
|
| + _base + DataHeader.kHeaderSize + value.lengthInBytes,
|
| + value);
|
| }
|
| -}
|
|
|
| + void appendInt8Array(List<int> value) =>
|
| + appendBytes(new Uint8List.view(new Int8List.fromList(value)));
|
|
|
| -class MessageBuilder {
|
| - MojoEncoder encoder;
|
| - List<core.RawMojoHandle> handles;
|
| + void appendUint8Array(List<int> value) =>
|
| + appendBytes(new Uint8List.fromList(value));
|
|
|
| - MessageBuilder._();
|
| + void appendInt16Array(List<int> value) =>
|
| + appendBytes(new Uint8List.view(new Int16List.fromList(value)));
|
|
|
| - MessageBuilder(int name, int payloadSize) {
|
| - int numBytes = kMessageHeaderSize + payloadSize;
|
| - var buffer = new ByteData(numBytes);
|
| - handles = <core.RawMojoHandle>[];
|
| + void appendUint16Array(List<int> value) =>
|
| + appendBytes(new Uint8List.view(new Uint16List.fromList(value)));
|
|
|
| - encoder = new MojoEncoder(buffer, handles, 0, kMessageHeaderSize);
|
| - encoder.writeUint32(kMessageHeaderSize);
|
| - encoder.writeUint32(2); // num_fields;
|
| - encoder.writeUint32(name);
|
| - encoder.writeUint32(0); // flags.
|
| - }
|
| + void appendInt32Array(List<int> value) =>
|
| + appendBytes(new Uint8List.view(new Int32List.fromList(value)));
|
|
|
| - MojoEncoder createEncoder(int size) {
|
| - encoder = new MojoEncoder(encoder.buffer,
|
| - handles,
|
| - encoder.next,
|
| - encoder.next + size);
|
| - return encoder;
|
| - }
|
| + void appendUint32Array(List<int> value) =>
|
| + appendBytes(new Uint8List.view(new Uint32List.fromList(value)));
|
|
|
| - void encodeStruct(Object t, Object val) {
|
| - encoder = createEncoder(getEncodedSize(t));
|
| - _callEncode(t, encoder, val);
|
| - }
|
| + void appendInt64Array(List<int> value) =>
|
| + appendBytes(new Uint8List.view(new Int64List.fromList(value)));
|
|
|
| - ByteData _trimBuffer() {
|
| - return new ByteData.view(encoder.buffer.buffer, 0, encoder.extent);
|
| - }
|
| + void appendUint64Array(List<int> value) =>
|
| + appendBytes(new Uint8List.view(new Uint64List.fromList(value)));
|
|
|
| - Message finish() {
|
| - Message message = new Message(_trimBuffer(), handles);
|
| - encoder = null;
|
| - handles = null;
|
| - return message;
|
| - }
|
| -}
|
| + void appendFloatArray(List<int> value) =>
|
| + appendBytes(new Uint8List.view(new Float32List.fromList(value)));
|
|
|
| + void appendDoubleArray(List<int> value) =>
|
| + appendBytes(new Uint8List.view(new Float64List.fromList(value)));
|
|
|
| -class MessageWithRequestIDBuilder extends MessageBuilder {
|
| - MessageWithRequestIDBuilder(
|
| - int name, int payloadSize, int requestID, [int flags = 0])
|
| - : super._() {
|
| - int numBytes = kMessageWithRequestIDHeaderSize + payloadSize;
|
| - var buffer = new ByteData(numBytes);
|
| - handles = <core.RawMojoHandle>[];
|
| -
|
| - encoder = new MojoEncoder(
|
| - buffer, handles, 0, kMessageWithRequestIDHeaderSize);
|
| - encoder.writeUint32(kMessageWithRequestIDHeaderSize);
|
| - encoder.writeUint32(3); // num_fields.
|
| - encoder.writeUint32(name);
|
| - encoder.writeUint32(flags);
|
| - encoder.writeUint64(requestID);
|
| + Encoder encoderForMap(int offset) {
|
| + encodePointerToNextUnclaimed(offset);
|
| + return getEncoderAtOffset(kMapStructHeader);
|
| }
|
| }
|
|
|
| -
|
| -class MessageReader {
|
| - MojoDecoder decoder;
|
| - int payloadSize;
|
| - int name;
|
| - int flags;
|
| - int requestID;
|
| -
|
| - MessageReader(Message message) {
|
| - decoder = new MojoDecoder(message.buffer, message.handles, 0);
|
| -
|
| - int messageHeaderSize = decoder.readUint32();
|
| - payloadSize = message.buffer.lengthInBytes - messageHeaderSize;
|
| -
|
| - int num_fields = decoder.readUint32();
|
| - name = decoder.readUint32();
|
| - flags = decoder.readUint32();
|
| -
|
| - if (num_fields >= 3) {
|
| - requestID = decoder.readUint64();
|
| +class Decoder {
|
| + Message _message;
|
| + int _base = 0;
|
| +
|
| + Decoder(this._message, [this._base = 0]);
|
| +
|
| + Decoder getDecoderAtPosition(int offset) => new Decoder(_message, offset);
|
| +
|
| + factory Decoder.atOffset(Decoder d, int offset) =>
|
| + new Decoder(d._message, offset);
|
| +
|
| + ByteData get _buffer => _message.buffer;
|
| + List<core.MojoHandle> get _handles => _message.handles;
|
| +
|
| + int decodeInt8(int offset) => _buffer.getInt8(_base + offset);
|
| + int decodeUint8(int offset) => _buffer.getUint8(_base + offset);
|
| + int decodeInt16(int offset) =>
|
| + _buffer.getInt16(_base + offset, Endianness.LITTLE_ENDIAN);
|
| + int decodeUint16(int offset) =>
|
| + _buffer.getUint16(_base + offset, Endianness.LITTLE_ENDIAN);
|
| + int decodeInt32(int offset) =>
|
| + _buffer.getInt32(_base + offset, Endianness.LITTLE_ENDIAN);
|
| + int decodeUint32(int offset) =>
|
| + _buffer.getUint32(_base + offset, Endianness.LITTLE_ENDIAN);
|
| + int decodeInt64(int offset) =>
|
| + _buffer.getInt64(_base + offset, Endianness.LITTLE_ENDIAN);
|
| + int decodeUint64(int offset) =>
|
| + _buffer.getUint64(_base + offset,Endianness.LITTLE_ENDIAN);
|
| + double decodeFloat(int offset) =>
|
| + _buffer.getFloat32(_base + offset, Endianness.LITTLE_ENDIAN);
|
| + double decodeDouble(int offset) =>
|
| + _buffer.getFloat64(_base + offset, Endianness.LITTLE_ENDIAN);
|
| +
|
| + bool decodeBool(int offset, int bit) =>
|
| + (decodeUint8(offset) & (1 << bit)) != 0;
|
| +
|
| + core.MojoHandle decodeHandle(int offset, bool nullable) {
|
| + int index = decodeInt32(offset);
|
| + if (index == -1) {
|
| + if (!nullable) {
|
| + throw 'Trying to decode an invalid handle from a non-nullable type.';
|
| + }
|
| + return new core.MojoHandle(core.MojoHandle.INVALID);
|
| }
|
| - decoder.skip(messageHeaderSize - decoder.next);
|
| - }
|
| -
|
| - Object decodeStruct(Object t) => _callDecode(t, decoder);
|
| -}
|
| -
|
| -
|
| -class PackedBool {}
|
| -
|
| -
|
| -class Int8 {
|
| - static const int encodedSize = 1;
|
| - static int decode(MojoDecoder decoder) => decoder.readInt8();
|
| - static void encode(MojoEncoder encoder, int val) {
|
| - encoder.writeInt8(val);
|
| - }
|
| -}
|
| -
|
| -
|
| -class Uint8 {
|
| - static const int encodedSize = 1;
|
| - static int decode(MojoDecoder decoder) => decoder.readUint8();
|
| - static void encode(MojoEncoder encoder, int val) {
|
| - encoder.writeUint8(val);
|
| - }
|
| -}
|
| -
|
| -
|
| -class Int16 {
|
| - static const int encodedSize = 2;
|
| - static int decode(MojoDecoder decoder) => decoder.readInt16();
|
| - static void encode(MojoEncoder encoder, int val) {
|
| - encoder.writeInt16(val);
|
| - }
|
| -}
|
| -
|
| -
|
| -class Uint16 {
|
| - static const int encodedSize = 2;
|
| - static int decode(MojoDecoder decoder) => decoder.readUint16();
|
| - static void encode(MojoEncoder encoder, int val) {
|
| - encoder.writeUint16(val);
|
| - }
|
| -}
|
| -
|
| -
|
| -class Int32 {
|
| - static const int encodedSize = 4;
|
| - static int decode(MojoDecoder decoder) => decoder.readInt32();
|
| - static void encode(MojoEncoder encoder, int val) {
|
| - encoder.writeInt32(val);
|
| + return _handles[index];
|
| }
|
| -}
|
| -
|
| -
|
| -class Uint32 {
|
| - static const int encodedSize = 4;
|
| - static int decode(MojoDecoder decoder) => decoder.readUint32();
|
| - static void encode(MojoEncoder encoder, int val) {
|
| - encoder.writeUint32(val);
|
| - }
|
| -}
|
| -
|
| -
|
| -class Int64 {
|
| - static const int encodedSize = 8;
|
| - static int decode(MojoDecoder decoder) => decoder.readInt64();
|
| - static void encode(MojoEncoder encoder, int val) {
|
| - encoder.writeInt64(val);
|
| - }
|
| -}
|
| -
|
| -
|
| -class Uint64 {
|
| - static const int encodedSize = 8;
|
| - static int decode(MojoDecoder decoder) => decoder.readUint64();
|
| - static void encode(MojoEncoder encoder, int val) {
|
| - encoder.writeUint64(val);
|
| - }
|
| -}
|
|
|
| -
|
| -class MojoString {
|
| - static const int encodedSize = 8;
|
| - static String decode(MojoDecoder decoder) => decoder.decodeStringPointer();
|
| - static void encode(MojoEncoder encoder, String val) {
|
| - encoder.encodeStringPointer(val);
|
| + Decoder decodePointer(int offset, bool nullable) {
|
| + int basePosition = _base + offset;
|
| + int pointerOffset = decodeUint64(offset);
|
| + if (pointerOffset == 0) {
|
| + if (!nullable) {
|
| + throw 'Trying to decode a null pointer for a non-nullable type';
|
| + }
|
| + return null;
|
| + }
|
| + int newPosition = (basePosition + pointerOffset);
|
| + return new Decoder.atOffset(this, newPosition);
|
| }
|
| -}
|
| -
|
| -
|
| -class NullableMojoString {
|
| - static const int encodedSize = MojoString.encodedSize;
|
| - static var decode = MojoString.decode;
|
| - static var encode = MojoString.encode;
|
| -}
|
| -
|
|
|
| -class Float {
|
| - static const int encodedSize = 4;
|
| - static double decode(MojoDecoder decoder) => decoder.readFloat();
|
| - static void encode(MojoEncoder encoder, double val) {
|
| - encoder.writeFloat(val);
|
| + DataHeader decodeDataHeader() {
|
| + int size = decodeUint32(DataHeader.kSizeOffset);
|
| + int numFields = decodeUint32(DataHeader.kNumFieldsOffset);
|
| + return new DataHeader(size, numFields);
|
| }
|
| -}
|
| -
|
|
|
| -class Double {
|
| - static const int encodedSize = 8;
|
| - static double decode(MojoDecoder decoder) => decoder.readDouble();
|
| - static void encode(MojoEncoder encoder, double val) {
|
| - encoder.writeDouble(val);
|
| + // Decode arrays.
|
| + DataHeader decodeDataHeaderForBoolArray(int expectedLength) {
|
| + var header = decodeDataHeader();
|
| + if (header.size < DataHeader.kHeaderSize + (header.numFields + 7) ~/ 8) {
|
| + throw 'Array header is incorrect';
|
| + }
|
| + if ((expectedLength != kUnspecifiedArrayLength) &&
|
| + (header.numFields != expectedLength)) {
|
| + throw 'Incorrect array length';
|
| + }
|
| + return header;
|
| }
|
| -}
|
|
|
| -
|
| -class PointerTo {
|
| - Object val;
|
| -
|
| - PointerTo(this.val);
|
| -
|
| - int encodedSize = 8;
|
| - Object decode(MojoDecoder decoder) {
|
| - int pointer = decoder.decodePointer();
|
| - if (pointer == 0) {
|
| + List<bool> decodeBoolArray(int offset, int nullability, int expectedLength) {
|
| + Decoder d = decodePointer(offset, isArrayNullable(nullability));
|
| + if (d == null) {
|
| return null;
|
| }
|
| - return _callDecode(val, decoder.decodeAndCreateDecoder(pointer));
|
| - }
|
| - void encode(MojoEncoder encoder, Object val) {
|
| - if (val == null) {
|
| - encoder.encodePointer(val);
|
| - return;
|
| + var header = d.decodeDataHeaderForBoolArray(expectedLength);
|
| + var bytes = new Uint8List.view(
|
| + d._buffer.buffer,
|
| + d._buffer.offsetInBytes + d._base + DataHeader.kHeaderSize,
|
| + (header.numFields + 7) ~/ kAlignment);
|
| + var result = new List<bool>(header.numFields);
|
| + for (int i = 0; i < bytes.lengthInBytes; ++i) {
|
| + for (int j = 0; j < kAlignment; ++j) {
|
| + int boolIndex = i * kAlignment + j;
|
| + if (boolIndex < result.length) {
|
| + result[boolIndex] = (bytes[i] & (1 << j)) != 0;
|
| + }
|
| + }
|
| }
|
| - MojoEncoder obj_encoder =
|
| - encoder.createAndEncodeEncoder(getEncodedSize(this.val));
|
| - _callEncode(this.val, obj_encoder, val);
|
| + return result;
|
| }
|
| -}
|
| -
|
| -
|
| -class NullablePointerTo extends PointerTo {
|
| - NullablePointerTo(Object val) : super(val);
|
| -}
|
| -
|
|
|
| -class ArrayOf {
|
| - Object val;
|
| - int length;
|
| -
|
| - ArrayOf(this.val, [this.length = 0]);
|
| -
|
| - int dimensions() => [length].addAll((val is ArrayOf) ? val.dimensions() : []);
|
| -
|
| - int encodedSize = 8;
|
| - List decode(MojoDecoder decoder) => decoder.decodeArrayPointer(val);
|
| - void encode(MojoEncoder encoder, List val) {
|
| - encoder.encodeArrayPointer(this.val, val);
|
| + DataHeader decodeDataHeaderForArray(int elementSize, int expectedLength) {
|
| + var header = decodeDataHeader();
|
| + if (header.size < DataHeader.kHeaderSize + header.numFields * elementSize) {
|
| + throw 'Array header is incorrect: $header, elementSize = $elementSize';
|
| + }
|
| + if ((expectedLength != kUnspecifiedArrayLength) &&
|
| + (header.numFields != expectedLength)) {
|
| + throw 'Incorrect array length.';
|
| + }
|
| + return header;
|
| }
|
| -}
|
|
|
| + DataHeader decodeDataHeaderForPointerArray(int expectedLength) =>
|
| + decodeDataHeaderForArray(kPointerSize, expectedLength);
|
|
|
| -class NullableArrayOf extends ArrayOf {
|
| - NullableArrayOf(Object val, [int length = 0]) : super(val, length);
|
| -}
|
| -
|
| -
|
| -class Handle {
|
| - static const int encodedSize = 4;
|
| - static core.RawMojoHandle decode(MojoDecoder decoder) =>
|
| - decoder.decodeHandle();
|
| - static void encode(MojoEncoder encoder, core.RawMojoHandle val) {
|
| - encoder.encodeHandle(val);
|
| + List<int> decodeArray(Function arrayViewer,
|
| + int elementSize,
|
| + int offset,
|
| + int nullability,
|
| + int expectedLength) {
|
| + Decoder d = decodePointer(offset, isArrayNullable(nullability));
|
| + if (d == null) {
|
| + return null;
|
| + }
|
| + var header = d.decodeDataHeaderForArray(elementSize, expectedLength);
|
| + return arrayViewer(
|
| + d._buffer.buffer,
|
| + d._buffer.offsetInBytes + d._base + DataHeader.kHeaderSize,
|
| + header.numFields);
|
| + }
|
| +
|
| + List<int> decodeInt8Array(
|
| + int offset, int nullability, int expectedLength) =>
|
| + decodeArray((b, s, l) => new Int8List.view(b, s, l),
|
| + 1, offset, nullability, expectedLength);
|
| +
|
| + List<int> decodeUint8Array(
|
| + int offset, int nullability, int expectedLength) =>
|
| + decodeArray((b, s, l) => new Uint8List.view(b, s, l),
|
| + 1, offset, nullability, expectedLength);
|
| +
|
| + List<int> decodeInt16Array(
|
| + int offset, int nullability, int expectedLength) =>
|
| + decodeArray((b, s, l) => new Int16List.view(b, s, l),
|
| + 2, offset, nullability, expectedLength);
|
| +
|
| + List<int> decodeUint16Array(
|
| + int offset, int nullability, int expectedLength) =>
|
| + decodeArray((b, s, l) => new Uint16List.view(b, s, l),
|
| + 2, offset, nullability, expectedLength);
|
| +
|
| + List<int> decodeInt32Array(
|
| + int offset, int nullability, int expectedLength) =>
|
| + decodeArray((b, s, l) => new Int32List.view(b, s, l),
|
| + 4, offset, nullability, expectedLength);
|
| +
|
| + List<int> decodeUint32Array(
|
| + int offset, int nullability, int expectedLength) =>
|
| + decodeArray((b, s, l) => new Uint32List.view(b, s, l),
|
| + 4, offset, nullability, expectedLength);
|
| +
|
| + List<int> decodeInt64Array(
|
| + int offset, int nullability, int expectedLength) =>
|
| + decodeArray((b, s, l) => new Int64List.view(b, s, l),
|
| + 8, offset, nullability, expectedLength);
|
| +
|
| + List<int> decodeUint64Array(
|
| + int offset, int nullability, int expectedLength) =>
|
| + decodeArray((b, s, l) => new Uint64List.view(b, s, l),
|
| + 8, offset, nullability, expectedLength);
|
| +
|
| + List<double> decodeFloatArray(
|
| + int offset, int nullability, int expectedLength) =>
|
| + decodeArray((b, s, l) => new Float32List.view(b, s, l),
|
| + 4, offset, nullability, expectedLength);
|
| +
|
| + List<double> decodeDoubleArray(
|
| + int offset, int nullability, int expectedLength) =>
|
| + decodeArray((b, s, l) => new Float64List.view(b, s, l),
|
| + 8, offset, nullability, expectedLength);
|
| +
|
| + List<core.MojoHandle> decodeHandleArray(
|
| + int offset, int nullability, int expectedLength) {
|
| + Decoder d = decodePointer(offset, isArrayNullable(nullability));
|
| + if (d == null) {
|
| + return null;
|
| + }
|
| + var header = d.decodeDataHeaderForArray(4, expectedLength);
|
| + var result = new core.MojoHandle(header.numFields);
|
| + for (int i = 0; i < result.length; ++i) {
|
| + result[i] = d.decodeHandle(
|
| + DataHeader.kHeaderSize + kSerializedHandleSize * i,
|
| + isElementNullable(nullability));
|
| + }
|
| + return result;
|
| }
|
| -}
|
| -
|
| -
|
| -class NullableHandle {
|
| - static const int encodedSize = Handle.encodedSize;
|
| - static const decode = Handle.decode;
|
| - static const encode = Handle.encode;
|
| -}
|
| -
|
|
|
| -class MapOf {
|
| - Object key;
|
| - Object val;
|
| + static String _stringOfUtf8(Uint8List bytes) =>
|
| + (const Utf8Decoder()).convert(bytes.toList());
|
|
|
| - MapOf(this.key, this.val);
|
| -
|
| - int encodedSize = 8;
|
| - Map decode(MojoDecoder decoder) => decoder.decodeMapPointer(key, val);
|
| - void encode(MojoEncoder encoder, Map map) {
|
| - encoder.encodeMapPointer(key, val, map);
|
| + String decodeString(int offset, bool nullable) {
|
| + int nullability = nullable ? kArrayNullable : 0;
|
| + var bytes = decodeUint8Array(offset, nullability, kUnspecifiedArrayLength);
|
| + if (bytes == null) {
|
| + return null;
|
| + }
|
| + return _stringOfUtf8(bytes);
|
| }
|
| }
|
| -
|
| -
|
| -class NullableMapOf extends MapOf {
|
| - NullableMapOf(Object key, Object val) : super(key, val);
|
| -}
|
|
|