Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1456)

Unified Diff: mojo/public/dart/bindings/lib/src/codec.dart

Issue 674383002: Initial work on Dart bindings for Mojo. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Merge. Work on templates. Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « mojo/public/dart/bindings/lib/src/client.dart ('k') | mojo/public/dart/bindings/lib/src/interface.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: mojo/public/dart/bindings/lib/src/codec.dart
diff --git a/mojo/public/dart/bindings/lib/src/codec.dart b/mojo/public/dart/bindings/lib/src/codec.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c7051ec3df8ac6095919625ffb1464c369b67922
--- /dev/null
+++ b/mojo/public/dart/bindings/lib/src/codec.dart
@@ -0,0 +1,720 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+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;
+
+
+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());
+
+
+Object _callDecode(Object typ_or_inst, MojoDecoder decoder) {
+ if (typ_or_inst is Type) {
+ return reflectClass(typ_or_inst).invoke(#decode, [decoder]).reflectee;
+ } else {
+ return typ_or_inst.decode(decoder);
+ }
+}
+
+
+void _callEncode(Object typ_or_inst, MojoEncoder encoder, Object val) {
+ if (typ_or_inst is Type) {
+ reflectClass(typ_or_inst).invoke(#encode, [encoder, val]);
+ } else {
+ typ_or_inst.encode(encoder, val);
+ }
+}
+
+
+int getEncodedSize(Object typ_or_inst) {
+ if (typ_or_inst is Type) {
+ return reflectClass(typ_or_inst).getField(#encodedSize).reflectee;
+ } else {
+ return typ_or_inst.encodedSize;
+ }
+}
+
+
+class MojoDecoder {
+ ByteData buffer;
+ List<int> handles;
+ int base;
+ int next;
+
+ MojoDecoder(this.buffer, this.handles, this.base) {
+ next = base;
+ }
+
+ void skip(int offset) {
+ next += offset;
+ }
+
+ int readInt8() {
+ int result = buffer.getInt8(next);
+ next += 1;
+ return result;
+ }
+
+ int readUint8() {
+ int result = buffer.getUint8(next);
+ next += 1;
+ return result;
+ }
+
+ int readInt16() {
+ int result = buffer.getInt16(next, Endianness.HOST_ENDIAN);
+ next += 2;
+ return result;
+ }
+
+ int readUint16() {
+ int result = buffer.getUint16(next, Endianness.HOST_ENDIAN);
+ next += 2;
+ return result;
+ }
+
+ int readInt32() {
+ int result = buffer.getInt32(next, Endianness.HOST_ENDIAN);
+ next += 4;
+ return result;
+ }
+
+ int readUint32() {
+ int result = buffer.getUint32(next, Endianness.HOST_ENDIAN);
+ next += 4;
+ return result;
+ }
+
+ int readInt64() {
+ int result = buffer.getInt64(next, Endianness.HOST_ENDIAN);
+ next += 8;
+ return result;
+ }
+
+ int readUint64() {
+ int result = buffer.getUint64(next, Endianness.HOST_ENDIAN);
+ next += 8;
+ return result;
+ }
+
+ double readFloat() {
+ double result = buffer.getFloat32(next,Endianness.HOST_ENDIAN);
+ next += 4;
+ return result;
+ }
+
+ double readDouble() {
+ double result = buffer.getFloat64(next, Endianness.HOST_ENDIAN);
+ next += 8;
+ return result;
+ }
+
+ int decodePointer() {
+ int offsetPointer = next;
+ int offset = readUint64();
+ if (offset == 0) {
+ return 0;
+ }
+ return offsetPointer + offset;
+ }
+
+ MojoDecoder decodeAndCreateDecoder(int offset) {
+ return new MojoDecoder(buffer, handles, offset);
+ }
+
+ int decodeHandle() {
+ return handles[readUint32()];
+ }
+
+ String decodeString() {
+ int num_bytes = readUint32();
+ int num_elements = readUint32();
+ int base = next;
+ next += num_elements;
+ return stringOfUtf8(buffer.buffer.asUint8List(base, num_elements));
+ }
+
+ List decodeArray(Object t) {
+ int num_bytes = readUint32();
+ int num_elements = readUint32();
+ if (t == PackedBool) {
+ int b;
+ List<bool> result = new List<bool>(num_elements);
+ for (int i = 0; i < num_elements; i++) {
+ if ((i % 8) == 0) {
+ b = readUint8();
+ }
+ result[i] = ((b & (1 << (i % 8)) != 0) ? true : false);
+ }
+ return result;
+ } else {
+ List result = new List(num_elements);
+ for (int i = 0; i < num_elements; i++) {
+ result[i] = _callDecode(t, this);
+ }
+ return result;
+ }
+ }
+
+ Object decodeStruct(Object t) {
+ return _callDecode(t, this);
+ }
+
+ Object decodeStructPointer(Object t) {
+ int pointer = decodePointer();
+ if (pointer == 0) {
+ return null;
+ }
+ return _callDecode(t, decodeAndCreateDecoder(pointer));
+ }
+
+ List decodeArrayPointer(Object t) {
+ int pointer = decodePointer();
+ if (pointer == 0) {
+ return null;
+ }
+ return decodeAndCreateDecoder(pointer).decodeArray(t);
+ }
+
+ String decodeStringPointer() {
+ int pointer = decodePointer();
+ if (pointer == 0) {
+ return null;
+ }
+ return decodeAndCreateDecoder(pointer).decodeString();
+ }
+
+ 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(keyes, values);
+ }
+
+ Map decodeMapPointer(Object keyType, Object valType) {
+ int pointer = this.decodePointer();
+ if (pointer == 0) {
+ return null;
+ }
+ MojoDecoder decoder = decodeAndCreateDecoder(pointer);
+ return decoder.decodeMap(keyType, valType);
+ }
+}
+
+
+class MojoEncoder {
+ ByteData buffer;
+ List handles;
+ int base;
+ int next;
+ int extent;
+
+ MojoEncoder(this.buffer, this.handles, this.base, this.extent) {
+ next = base;
+ }
+
+ void skip(int offset) {
+ next += offset;
+ }
+
+ void writeInt8(int val) {
+ buffer.setInt8(next, val);
+ next += 1;
+ }
+
+ void writeUint8(int val) {
+ buffer.setUint8(next, val);
+ next += 1;
+ }
+
+ void writeInt16(int val) {
+ buffer.setInt16(next, val, Endianness.HOST_ENDIAN);
+ next += 2;
+ }
+
+ void writeUint16(int val) {
+ buffer.setUint16(next, val, Endianness.HOST_ENDIAN);
+ next += 2;
+ }
+
+ void writeInt32(int val) {
+ buffer.setInt32(next, val, Endianness.HOST_ENDIAN);
+ next += 4;
+ }
+
+ void writeUint32(int val) {
+ buffer.setUint32(next, val, Endianness.HOST_ENDIAN);
+ next += 4;
+ }
+
+ void writeInt64(int val) {
+ buffer.setInt64(next, val, Endianness.HOST_ENDIAN);
+ next += 8;
+ }
+
+ void writeUint64(int val) {
+ buffer.setUint64(next, val, Endianness.HOST_ENDIAN);
+ next += 8;
+ }
+
+ void writeFloat(double val) {
+ buffer.setFloat32(next, val, Endianness.HOST_ENDIAN);
+ next += 4;
+ }
+
+ void writeDouble(double val) {
+ buffer.setFloat64(next, val, Endianness.HOST_ENDIAN);
+ next += 8;
+ }
+
+ void encodePointer(int pointer) {
+ if (pointer == null) {
+ writeUint64(0);
+ return;
+ }
+ int offset = pointer - next;
+ writeUint64(offset);
+ }
+
+ void grow(int new_size) {
+ Uint8List new_buffer = new Uint8List(new_size);
+ new_buffer.setRange(0, next, 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;
+ }
+
+ MojoEncoder createAndEncodeEncoder(int size) {
+ int pointer = alloc(align(size));
+ encodePointer(pointer);
+ return new MojoEncoder(buffer, handles, pointer, extent);
+ }
+
+ void encodeHandle(int handle) {
+ handles.add(handle);
+ writeUint32(handles.length - 1);
+ }
+
+ void encodeString(String val) {
+ Uint8List utf8string = utf8OfString(val);
+ int num_elements = utf8string.lengthInBytes;
+ int num_bytes = kArrayHeaderSize + num_elements;
+ writeUint32(num_bytes);
+ writeUint32(num_elements);
+ buffer.buffer.asUint8List().setRange(next, next + num_elements, utf8string);
+ next += num_elements;
+ }
+
+ void encodeArray(Object t, List val, [int num_elements, int encoded_size]) {
+ if (num_elements == null) {
+ num_elements = val.length;
+ }
+ if (encoded_size == null) {
+ encoded_size = kArrayHeaderSize + (getEncodedSize(t) * num_elements);
+ }
+
+ writeUint32(encoded_size);
+ writeUint32(num_elements);
+
+ if (t == PackedBool) {
+ int b = 0;
+ for (int i = 0; i < num_elements; i++) {
+ if (val[i]) {
+ b |= (1 << (i % 8));
+ }
+ if (((i % 8) == 7) || (i == (num_elements - 1))) {
+ Uint8.encode(this, b);
+ }
+ }
+ } else {
+ for (int i = 0; i < num_elements; 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);
+ 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);
+ return;
+ }
+ int num_elements = val.length;
+ int encoded_size = kArrayHeaderSize + ((t == PackedBool) ?
+ (num_elements / 8).ceil() : (getEncodedSize(t) * num_elements));
+ MojoEncoder encoder = createAndEncodeEncoder(encoded_size);
+ encoder.encodeArray(t, val, num_elements, encoded_size);
+ extent = encoder.extent;
+ buffer = encoder.buffer;
+ }
+
+ void encodeStringPointer(String val) {
+ if (val == null) {
+ encodePointer(val);
+ return;
+ }
+ int encoded_size = kArrayHeaderSize + utf8OfString(val).lengthInBytes;
+ MojoEncoder encoder = createAndEncodeEncoder(encoded_size);
+ 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);
+ }
+
+ void encodeMapPointer(Object keyTYpe, Object valType, Map val) {
+ if (val == null) {
+ encodePointer(val);
+ return;
+ }
+ int encoded_size = kStructHeaderSize + kMapStructPayloadSize;
+ MojoEncoder encoder = createAndEncodeEncoder(encoded_size);
+ encoder.encodeMap(keyType, valType, val);
+ extent = encoder.extent;
+ buffer = encoder.buffer;
+ }
+}
+
+
+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<int> 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);
+ }
+}
+
+
+class MessageBuilder {
+ ByteData buffer;
+ List<int> handles;
+ int base;
+
+ MessageBuilder(int name, int payload_size) {
+ int num_bytes = kMessageHeaderSize + payload_size;
+ buffer = new ByteData(num_bytes);
+ handles = [];
+ base = 0;
+ MojoEncoder encoder = createEncoder(kMessageHeaderSize);
+ encoder.writeUint32(kMessageHeaderSize);
+ encoder.writeUint32(2); // num_fields;
+ encoder.writeUint32(name);
+ encoder.writeUint32(0); // flags.
+ base = encoder.next;
+ buffer = encoder.buffer;
+ }
+
+ MojoEncoder createEncoder(int size) {
+ return new MojoEncoder(buffer, handles, base, base + size);
+ }
+
+ void encodeStruct(Object t, Object val) {
+ MojoEncoder encoder = createEncoder(getEncodedSize(t));
+ _callEncode(t, encoder, val);
+ base = encoder.next;
+ buffer = encoder.buffer;
+ }
+
+ Message finish() {
+ // trip buffer down to base.
+ Message message = new Message(buffer, handles);
+ buffer = null;
+ handles = null;
+ return message;
+ }
+}
+
+
+class MessageWithRequestIDBuilder extends MessageBuilder {
+ MessageWithRequestIDBuilder(
+ int name, int payload_size, int flags, int requestID) {
+ int num_bytes = kMessageWithRequestIDHeaderSize + payload_size;
+ buffer = new ByteData(num_bytes);
+ handles = [];
+ base = 0;
+
+ MojoEncoder encoder = createEncoder(0, kMessageWithRequestIDHeaderSize);
+ encoder.writeUint32(kMessageWithRequestIDHeaderSize);
+ encoder.writeUint32(3); // num_fields.
+ encoder.writeUint32(name);
+ encoder.writeUint32(flags);
+ encoder.writeUint64(requestID);
+ base = encoder.next;
+ buffer = encoder.buffer;
+ }
+}
+
+
+class MessageReader {
+ MojoDecoder decoder;
+ int payload_size;
+ int name;
+ int flags;
+ int requestID;
+
+ MessageReader(Message message) {
+ decoder = new MojoDecoder(message.buffer, message.handles, 0);
+
+ int message_header_size = decoder.readUint32();
+ payload_size = message.buffer.lengthInBytes - message_header_size;
+
+ int num_fields = decoder.readUint32();
+ name = decoder.readUint32();
+ flags = decoder.readUint32();
+
+ if (num_fields >= 3) {
+ requestID = decoder.readUint64();
+ }
+ decoder.skip(message_header_size - decoder.next);
+ }
+
+ Object decodeStruct(Object t) => _callDecode(t, decoder);
+}
+
+
+abstract class MojoType<T> {
+ static const int encodedSize = 0;
+ static T decode(MojoDecoder decoder) { return null }
+ static void encode(MojoEncoder encoder, T val) {}
+}
+
+
+// I guess we'll do this like JavaScript...
+class PackedBool {}
+
+class Int8 implements MojoType<int> {
+ static const int encodedSize = 1;
+ static int decode(MojoDecoder decoder) => decoder.readInt8();
+ static void encode(MojoEncoder encoder, int val) {
+ encoder.writeInt8(val);
+ }
+}
+
+
+class Uint8 implements MojoType<int> {
+ static const int encodedSize = 1;
+ static int decode(MojoDecoder decoder) => decoder.readUint8();
+ static void encode(MojoEncoder encoder, int val) {
+ encoder.writeUint8(val);
+ }
+}
+
+
+class Int16 implements MojoType<int> {
+ static const int encodedSize = 2;
+ static int decode(MojoDecoder decoder) => decoder.readInt16();
+ static void encode(MojoEncoder encoder, int val) {
+ encoder.writeInt16(val);
+ }
+}
+
+
+class Uint16 implements MojoType<int> {
+ static const int encodedSize = 2;
+ static int decode(MojoDecoder decoder) => decoder.readUint16();
+ static void encode(MojoEncoder encoder, int val) {
+ encoder.writeUint16(val);
+ }
+}
+
+
+class Int32 implements MojoType<int> {
+ static const int encodedSize = 4;
+ static int decode(MojoDecoder decoder) => decoder.readInt32();
+ static void encode(MojoEncoder encoder, int val) {
+ encoder.writeInt32(val);
+ }
+}
+
+
+class Uint32 implements MojoType<int> {
+ static const int encodedSize = 4;
+ static int decode(MojoDecoder decoder) => decoder.readUint32();
+ static void encode(MojoEncoder encoder, int val) {
+ encoder.writeUint32(val);
+ }
+}
+
+
+class Int64 implements MojoType<int> {
+ static const int encodedSize = 8;
+ static int decode(MojoDecoder decoder) => decoder.readInt64();
+ static void encode(MojoEncoder encoder, int val) {
+ encoder.writeInt64(val);
+ }
+}
+
+
+class Uint64 implements MojoType<int> {
+ static const int encodedSize = 8;
+ static int decode(MojoDecoder decoder) => decoder.readUint64();
+ static void encode(MojoEncoder encoder, int val) {
+ encoder.writeUint64(val);
+ }
+}
+
+
+class MojoString implements MojoType<String> {
+ static const int encodedSize = 8;
+ static String decode(MojoDecoder decoder) => decoder.decodeStringPointer();
+ static void encode(MojoEncoder encoder, String val) {
+ encoder.encodeStringPointer(val);
+ }
+}
+
+
+class NullableMojoString implements MojoType<String> {
+ static const int encodedSize = MojoString.encodedSize;
+ static var decode = MojoString.decode;
+ static var encode = MojoString.encode;
+}
+
+
+class Float implements MojoType<double> {
+ static const int encodedSize = 4;
+ static double decode(MojoDecoder decoder) => decoder.readFloat();
+ static void encode(MojoEncoder encoder, double val) {
+ encoder.writeFloat(val);
+ }
+}
+
+
+class Double implements MojoType<double> {
+ static const int encodedSize = 8;
+ static double decode(MojoDecoder decoder) => decoder.readDouble();
+ static void encode(MojoEncoder encoder, double val) {
+ encoder.writeDouble(val);
+ }
+}
+
+
+class PointerTo {
+ Object t;
+
+ PointerTo(this.t);
+
+ int encodedSize = 8;
+ Object decode(MojoDecoder decoder) {
+ int pointer = decoder.decodePointer();
+ if (pointer == 0) {
+ return null;
+ }
+ return _callDecode(t, decoder.decodeAndCreateDecoder(pointer));
+ }
+ void encode(MojoEncoder encoder, Object val) {
+ if (val == null) {
+ encoder.encodePointer(val);
+ return;
+ }
+ MojoEncoder obj_encoder = encoder.createAndEncodeEncoder(getEncodedSize(t));
+ _callEncode(t, obj_encoder, val);
+ }
+}
+
+
+class NullablePointerTo extends PointerTo {
+ static const int encodedSize = 8;
+}
+
+
+class ArrayOf {
+ Object t;
+ int length;
+
+ ArrayOf(Object t, [int length = 0]) : t = t, length = length;
+
+ int dimensions() => [length].addAll((t is ArrayOf) ? t.dimensions() : []);
+
+ int encodedSize = 8;
+ List decode(MojoDecoder decoder) => decoder.decodeArrayPointer(t);
+ void encode(MojoEncoder encoder, List val) {
+ encoder.encodeArrayPointer(t, val);
+ }
+}
+
+
+class NullableArrayOf extends ArrayOf {
+ static const int encodedSize = ArrayOf.encodedSize;
+}
+
+
+class Handle implements MojoType<int> {
+ static const int encodedSize = 4;
+ static int decode(MojoDecoder decoder) => decoder.decodeHandle();
+ static void encode(MojoEncoder encoder, int val) {
+ encoder.encodeHandle(val);
+ }
+}
+
+
+class NullableHandle implements MojoType<int> {
+ static const int encodedSize = Handle.encodedSize;
+ static const decode = Handle.decode;
+ static const encode = Handle.encode;
+}
« no previous file with comments | « mojo/public/dart/bindings/lib/src/client.dart ('k') | mojo/public/dart/bindings/lib/src/interface.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698